Skip to content

[DM-48] API Key 검증 로직 구현#17

Merged
godqhrenf merged 5 commits intodevfrom
feat/DM-48-api-key-validation
Mar 11, 2026
Merged

[DM-48] API Key 검증 로직 구현#17
godqhrenf merged 5 commits intodevfrom
feat/DM-48-api-key-validation

Conversation

@godqhrenf
Copy link
Collaborator

@godqhrenf godqhrenf commented Mar 10, 2026

관련 이슈

작업 내용

  • 로그 수집 시 API Key 검증하는 로직 구현

체크 리스트

  • PR 제목 규칙을 준수했습니다
  • 관련 이슈를 연결했습니다
  • 본문 내용을 명확하게 작성했습니다
  • 정상 작동을 로컬 환경에서 검증했습니다

변경 사항 요약

  • AI 리뷰를 반영하여 변경한 사항을 요약하여 작성
  • AI 제안을 거절한 경우 이유 작성

리뷰어에게

  • 특히 우려되는 기능이나 코드에 대한 점검 요청

@godqhrenf godqhrenf self-assigned this Mar 10, 2026
@qodo-code-review
Copy link

Review Summary by Qodo

Implement production API Key validation with HMAC hashing

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Replace dummy API Key validation with production-ready HMAC-based verification
• Add database lookup by key prefix and status validation
• Implement constant-time comparison for secure hash verification
• Add comprehensive unit tests covering all validation scenarios
Diagram
flowchart LR
  A["Raw API Key"] --> B["Extract Prefix"]
  B --> C["Query DB by Prefix"]
  C --> D{Key Found?}
  D -->|No| E["Return null"]
  D -->|Yes| F{Status Active?}
  F -->|No| E
  F -->|Yes| G["Compute HMAC Hash"]
  G --> H["Constant-time Compare"]
  H --> I{Match?}
  I -->|Yes| J["Return ProjectId"]
  I -->|No| E
Loading

Grey Divider

File Changes

1. src/main/java/kr/java/documind/domain/auth/model/repository/ProjectApiKeyRepository.java ✨ Enhancement +2/-0

Add prefix-based API Key repository query

• Add new query method findByKeyPrefix() to retrieve API keys by their prefix
• Enable efficient database lookup during API Key validation process

src/main/java/kr/java/documind/domain/auth/model/repository/ProjectApiKeyRepository.java


2. src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java ✨ Enhancement +45/-14

Implement production HMAC-based API Key validation

• Replace hardcoded test API Key validation with real HMAC-based verification
• Implement database lookup using ProjectApiKeyRepository with prefix extraction
• Add API Key status validation to reject suspended/revoked keys
• Implement constant-time hash comparison for timing attack prevention
• Add comprehensive null checks and security-focused logging with key masking

src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java


3. src/test/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationServiceTest.java 🧪 Tests +150/-0

Add comprehensive API Key validation unit tests

• Add 6 comprehensive unit tests covering valid key validation and all failure scenarios
• Test null API Key, non-existent prefix, hash mismatch, and inactive key statuses
• Use Mockito for repository mocking and ReflectionTestUtils for HMAC secret injection
• Verify end-to-end flow from key generation through validation

src/test/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationServiceTest.java


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 10, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. HMAC secret 키 불일치🐞 Bug ✓ Correctness
Description
ProjectApiKeyValidationService가 hmacSecret을 ${api-key.hmac-secret}에서 주입받도록 되어 있으나, 실제 설정은
app.api-key.hmac-secret로 정의되어 있어 런타임에 secret 주입이 실패하여 API Key 검증이 동작하지 않습니다.
Code

src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[R22-23]

+    @Value("${api-key.hmac-secret}")
+    private String hmacSecret;
Evidence
검증 서비스는 ${api-key.hmac-secret}를 요구하지만, repo 내 설정 파일과 기존 키 발급 로직(ProjectService)은
app.api-key.hmac-secret를 사용합니다. 또한 HmacApiKeyUtil.computeHmac는 hmacSecret을 바로 역참조하므로(secret이 미주입/누락
시) 검증 로직이 정상 동작할 수 없습니다.

src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[20-23]
src/main/java/kr/java/documind/domain/member/service/ProjectService.java[57-58]
src/main/resources/application-prod.yml[95-145]
src/main/java/kr/java/documind/global/util/HmacApiKeyUtil.java[36-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProjectApiKeyValidationService`가 HMAC secret을 `${api-key.hmac-secret}`에서 주입받도록 되어 있어, 현재 레포 설정(`app.api-key.hmac-secret`)과 불일치합니다. 이 상태로는 배포/실행 시 secret 주입 실패로 API Key 검증이 동작하지 않습니다.
### Issue Context
- 설정 파일들은 `app.api-key.hmac-secret`를 사용합니다.
- 키 발급 로직(`ProjectService`)도 동일한 키를 사용합니다.
### Fix Focus Areas
- src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[20-23]
- src/main/java/kr/java/documind/domain/member/service/ProjectService.java[57-58]
- src/main/resources/application-prod.yml[95-145]
- src/main/resources/application-dev-sample.yml[165-168]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unindexed prefix 조회🐞 Bug ➹ Performance
Description
/api/logs 요청마다 key_prefix로 ProjectApiKey를 조회하도록 변경됐지만, 현재 DB 스키마에는 key_prefix 인덱스가 없어 트래픽 증가 시 검증
쿼리가 테이블 풀스캔으로 느려질 수 있습니다.
Code

src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[R38-40]

+        String prefix = HmacApiKeyUtil.extractPrefix(rawApiKey);
+        Optional<ProjectApiKey> apiKeyOptional = projectApiKeyRepository.findByKeyPrefix(prefix);
+
Evidence
RateLimitFilter는 /api/logs 경로에 대해 항상 API Key 검증을 호출하고, 검증은 key_prefix로 DB 조회를 수행합니다. 하지만
project_api_key 테이블은 key_prefix 컬럼만 존재할 뿐, 인덱스는 project_id/api_key_hash/api_key_status에만 있어 prefix
조회는 인덱스 미사용(풀스캔) 경로가 됩니다.

src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[38-40]
src/main/java/kr/java/documind/global/security/filter/RateLimitFilter.java[49-68]
src/main/resources/db/migration/V4__Create_project_tables.sql[51-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
API Key 검증이 `key_prefix`로 DB 조회(`findByKeyPrefix`)를 수행하지만, 스키마에 `key_prefix` 인덱스가 없어 /api/logs 트래픽에서 매 요청마다 비효율적인 조회가 발생할 수 있습니다.
### Issue Context
- 필터가 `/api/logs` 요청마다 검증 서비스를 호출합니다.
- 현 마이그레이션(V4)에는 `key_prefix` 인덱스가 없습니다.
### Fix Focus Areas
- src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[38-40]
- src/main/java/kr/java/documind/global/security/filter/RateLimitFilter.java[49-68]
- src/main/resources/db/migration/V4__Create_project_tables.sql[51-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Prefix 중복 시 런타임 오류🐞 Bug ⛯ Reliability
Description
ProjectApiKeyRepository.findByKeyPrefix가 단건(Optional) 반환을 전제로 하지만, 스키마에 key_prefix 유니크 제약이 없어 중복
데이터가 생기면 조회 시 런타임 오류로 요청이 500으로 실패할 수 있습니다.
Code

src/main/java/kr/java/documind/domain/auth/model/repository/ProjectApiKeyRepository.java[17]

+    Optional<ProjectApiKey> findByKeyPrefix(String prefix);
Evidence
Repository 시그니처는 key_prefix가 단건임을 가정(Optional)하지만, 마이그레이션에는 key_prefix에 대한 UNIQUE 제약(또는 UNIQUE
INDEX)이 없습니다. 따라서 운영 데이터가 중복될 경우(실수/데이터 이관/충돌 등) 단건 조회가 깨지며, 검증 경로에서 예외가 발생해 요청 처리 자체가 실패할 수 있습니다.

src/main/java/kr/java/documind/domain/auth/model/repository/ProjectApiKeyRepository.java[10-18]
src/main/resources/db/migration/V4__Create_project_tables.sql[51-62]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`findByKeyPrefix`는 단건을 전제로 하지만 DB는 `key_prefix` 중복을 허용합니다. 이 불일치로 중복 데이터가 존재하는 순간 검증 경로가 런타임 예외로 실패할 수 있습니다.
### Issue Context
- 현재 스키마는 key_prefix에 UNIQUE 제약이 없습니다.
- 서비스는 단건 조회 결과를 그대로 사용합니다.
### Fix Focus Areas
- src/main/java/kr/java/documind/domain/auth/model/repository/ProjectApiKeyRepository.java[10-18]
- src/main/java/kr/java/documind/domain/member/service/ProjectApiKeyValidationService.java[38-46]
- src/main/resources/db/migration/V4__Create_project_tables.sql[51-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@greptile-apps
Copy link

greptile-apps bot commented Mar 10, 2026

Last reviewed commit: 4377fa5

@godqhrenf
Copy link
Collaborator Author

@greptileai review

@greptile-apps
Copy link

greptile-apps bot commented Mar 11, 2026

Last reviewed commit: 1889a07

@godqhrenf godqhrenf requested a review from ParkGoeun00 March 11, 2026 05:01
Copy link
Collaborator

@ParkGoeun00 ParkGoeun00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API 키 검증 필터 체인 등 로그 수집하실 때 API 키 검증 적용하시는 건 다음에 다른 이슈에서 하시는 거죠? 우선 유효한 ProjectId 반환 기능까지 잘 구현된 것 같습니다!

@godqhrenf
Copy link
Collaborator Author

API 키 검증 필터 체인 등 로그 수집하실 때 API 키 검증 적용하시는 건 다음에 다른 이슈에서 하시는 거죠? 우선 유효한 ProjectId 반환 기능까지 잘 구현된 것 같습니다!

@ParkGoeun00 현재 dev 브랜치에 API Key를 검증하는 필터가 이미 적용된 상태입니다. 해당 pr에서는 구체적인 로직만 작성했습니다

@godqhrenf godqhrenf merged commit 040e755 into dev Mar 11, 2026
2 checks passed
@godqhrenf godqhrenf deleted the feat/DM-48-api-key-validation branch March 11, 2026 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants