Skip to content

Commit 091cea0

Browse files
kangcheolungclaude
andcommitted
fix: 컬렉션 권한 엔티티 오버로드 방어 로직 추가 및 Swagger 설명 정정
canReadCollection/canWriteCollection/canAdminCollection의 엔티티 오버로드가 호출부의 soft-delete 필터링에만 의존하고 있어, 호출부가 필터링을 빠뜨린 엔티티를 넘기면 삭제된 컬렉션도 권한이 통과될 수 있었다. validateActiveCollection()을 엔티티 오버로드 진입 지점에 추가해 추가 쿼리 없이 자체 방어하도록 한다(CodeRabbit 리뷰 반영). addDocument()의 Swagger description도 canWriteCollection()이 WRITE뿐 아니라 ADMIN 권한자도 통과시킨다는 실제 동작에 맞게 정정한다. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 43b6c2d commit 091cea0

2 files changed

Lines changed: 12 additions & 5 deletions

File tree

src/main/java/com/opensource/docgrid/domain/collection/controller/CollectionController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public ResponseEntity<ApiResponse<CollectionResponse>> getCollection(
9797

9898
@Operation(
9999
summary = "컬렉션에 문서 추가",
100-
description = "컬렉션에 문서를 추가합니다. 컬렉션 쓰기 권한(WRITE, 소유자 포함)이 있는 사용자만 가능합니다. 이미 추가된 문서면 409를 반환합니다."
100+
description = "컬렉션에 문서를 추가합니다. 컬렉션 쓰기 권한(WRITE 또는 ADMIN, 소유자 포함)이 있는 사용자만 가능합니다. 이미 추가된 문서면 409를 반환합니다."
101101
)
102102
@PostMapping("/{collectionId}/documents")
103103
public ResponseEntity<ApiResponse<CollectionDocumentResponse>> addDocument(

src/main/java/com/opensource/docgrid/domain/permission/service/query/PermissionQueryService.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,9 @@ public boolean canReadCollection(Long userId, Long collectionId) {
251251
return canReadCollection(userId, getActiveCollection(collectionId));
252252
}
253253

254-
// 이미 조회된 컬렉션 엔티티로 판단 — 호출부가 이미 non-deleted 엔티티임을 보장해야 함
254+
// 이미 조회된 컬렉션 엔티티로 판단 — soft-delete된 엔티티면 COLLECTION_NOT_FOUND
255255
public boolean canReadCollection(Long userId, DocumentCollection collection) {
256+
validateActiveCollection(collection);
256257
if (collection.getOwner().getId().equals(userId)) return true;
257258
if (collection.getVisibility() == VisibilityType.PUBLIC) return true;
258259
Long collectionId = collection.getId();
@@ -267,6 +268,7 @@ public boolean canWriteCollection(Long userId, Long collectionId) {
267268
}
268269

269270
public boolean canWriteCollection(Long userId, DocumentCollection collection) {
271+
validateActiveCollection(collection);
270272
if (collection.getOwner().getId().equals(userId)) return true;
271273
Long collectionId = collection.getId();
272274
if (collectionPermissionRepository.existsUserWritePermission(userId, collectionId)) return true;
@@ -280,6 +282,7 @@ public boolean canAdminCollection(Long userId, Long collectionId) {
280282
}
281283

282284
public boolean canAdminCollection(Long userId, DocumentCollection collection) {
285+
validateActiveCollection(collection);
283286
if (collection.getOwner().getId().equals(userId)) return true;
284287
Long collectionId = collection.getId();
285288
if (collectionPermissionRepository.existsUserAdminPermission(userId, collectionId)) return true;
@@ -288,15 +291,19 @@ public boolean canAdminCollection(Long userId, DocumentCollection collection) {
288291
}
289292

290293
// collectionId로 조회하되, status가 DELETED인 컬렉션은 필터링해서 제외한다 (없는 것으로 취급).
291-
// → DELETED가 아닌 컬렉션만 찾아서 반환하고, 없거나 DELETED면 COLLECTION_NOT_FOUND를 던진다.
292-
// collectionId로 조회하는 다른 지점에서도 이 필터링을 동일하게 적용해야
293-
// "삭제된 컬렉션을 살아있는 것처럼" 취급하는 구멍이 생기지 않는다.
294294
private DocumentCollection getActiveCollection(Long collectionId) {
295295
return collectionRepository.findById(collectionId)
296296
.filter(c -> c.getStatus() != CollectionStatus.DELETED)
297297
.orElseThrow(() -> new DocGridException(ErrorCode.COLLECTION_NOT_FOUND));
298298
}
299299

300+
// 엔티티 오버로드 방어 로직 — 호출부가 soft-delete 필터를 빠뜨리고 넘긴 엔티티도 여기서 최종 차단한다(추가 조회 없음).
301+
private void validateActiveCollection(DocumentCollection collection) {
302+
if (collection.getStatus() == CollectionStatus.DELETED) {
303+
throw new DocGridException(ErrorCode.COLLECTION_NOT_FOUND);
304+
}
305+
}
306+
300307
private double ms(long fromNano) {
301308
return (System.nanoTime() - fromNano) / 1_000_000.0;
302309
}

0 commit comments

Comments
 (0)