Conversation
[Docs] 초기 프로젝트 설계 문서 및 리드미 등록 (#1)
[Fix] SecurityConfig 설정 오류로 인해 @PreAuthorize 어노테이션이 제대로 작동하지 않는 문제 해결 (#22)
[Chore] develop CI/CD를 main 브랜치에 반영
[Chore] CodeRabbit 자동 리뷰 대상 브랜치에 develop 추가
📝 Walkthrough개요Spring Security 인증 규칙이 수정되어, 모든 요청( 변경 사항
코드 리뷰 예상 소요 시간🎯 2 (단순) | ⏱️ ~8분 시
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java`:
- Around line 55-57: The current SecurityConfig uses anyRequest().permitAll(),
which is a fail-open default that risks accidental exposure; change the policy
to a fail-closed default by replacing anyRequest().permitAll() with
anyRequest().authenticated() (or denyAll() if stricter) and explicitly add
permitAll() matchers for public endpoints such as the existing /health route and
any other intended public APIs; update the configuration in SecurityConfig
(where anyRequest().permitAll() is declared) and ensure JwtFilter and
`@PreAuthorize-protected` endpoints remain functional under the new default.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ef4dd422-9639-4da4-9636-76b723741ca5
⛔ Files ignored due to path filters (3)
README.mdis excluded by!**/*.mddocs/convention.mdis excluded by!**/*.mddocs/erd.mdis excluded by!**/*.md
📒 Files selected for processing (1)
src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java
| // 나머지는 다 인증 불필요 | ||
| // 인증이 필요한 메소드 위 @PreAuthorize을 붙일 것 | ||
| .anyRequest().permitAll() |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 목적: 컨트롤러 엔드포인트 중 보호 어노테이션 누락 항목 식별 (read-only)
# 해석:
# - 출력된 엔드포인트는 "의도된 공개 API"인지 명시 확인 필요
# - 비공개 의도면 `@PreAuthorize/`@Secured/@RolesAllowed 등 보안 어노테이션 추가 필요
python - <<'PY'
import re
from pathlib import Path
root = Path("src/main/java")
mapping_re = re.compile(r'^\s*@(?:Get|Post|Put|Delete|Patch|Request)Mapping\b')
method_re = re.compile(r'^\s*(public|protected|private)\s+[\w<>\[\], ?]+\s+(\w+)\s*\(')
guard_re = re.compile(r'@PreAuthorize\b|@Secured\b|@RolesAllowed\b|@PermitAll\b')
class_re = re.compile(r'^\s*public\s+class\s+\w+')
for p in root.rglob("*Controller.java"):
lines = p.read_text(encoding="utf-8").splitlines()
class_has_guard = False
for i, line in enumerate(lines):
if class_re.search(line):
class_window = "\n".join(lines[max(0, i-20):i+1])
class_has_guard = bool(guard_re.search(class_window))
if mapping_re.search(line):
j = i + 1
while j < len(lines) and lines[j].strip().startswith("@"):
j += 1
if j >= len(lines):
continue
m = method_re.search(lines[j])
if not m:
continue
method_window = "\n".join(lines[max(0, i-12):j+1])
method_has_guard = bool(guard_re.search(method_window))
if not (class_has_guard or method_has_guard):
print(f"{p}:{j+1} -> {m.group(2)} (NO_GUARD)")
PYRepository: wagle-project/wagle-server
Length of output: 181
🏁 Script executed:
# First, let's examine the full SecurityConfig.java to understand the context
cat -n src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.javaRepository: wagle-project/wagle-server
Length of output: 4015
🏁 Script executed:
# Check the HealthController to see if it's intentionally public
cat -n src/main/java/com/waglewagle/server/domain/health/controller/HealthController.javaRepository: wagle-project/wagle-server
Length of output: 542
🏁 Script executed:
# Search for the JWT filter implementation and configuration
find src/main/java -name "*JwtFilter*" -o -name "*Jwt*.java" | grep -i filter | head -5Repository: wagle-project/wagle-server
Length of output: 140
🏁 Script executed:
# Check if there are `@PreAuthorize` annotations being used elsewhere
rg "@PreAuthorize" src/main/java --type java | head -20Repository: wagle-project/wagle-server
Length of output: 1374
🏁 Script executed:
# Find all controller endpoints and their protection status
python3 <<'EOF'
import re
from pathlib import Path
root = Path("src/main/java")
mapping_re = re.compile(r'@(?:Get|Post|Put|Delete|Patch|Request)Mapping\(.*?(?:value|path)\s*=\s*"([^"]+)"')
method_re = re.compile(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(')
guard_re = re.compile(r'@PreAuthorize|@Secured|@RolesAllowed|@PermitAll')
results = []
for controller_file in sorted(root.rglob("*Controller.java")):
content = controller_file.read_text(encoding="utf-8")
lines = content.splitlines()
for i, line in enumerate(lines):
# Find mapping annotations
if '@' in line and ('Mapping' in line or 'RequestMapping' in line):
# Look for the method definition after the annotations
j = i + 1
while j < len(lines) and lines[j].strip().startswith("@"):
j += 1
if j >= len(lines):
continue
method_match = method_re.search(lines[j])
if not method_match:
continue
method_name = method_match.group(1)
# Check if method has security annotations
annotation_block = "\n".join(lines[max(0, i-5):j+1])
has_guard = bool(guard_re.search(annotation_block))
# Extract path
path_match = mapping_re.search(line)
path = path_match.group(1) if path_match else "?"
status = "✓ GUARDED" if has_guard else "✗ UNGUARDED"
results.append(f"{controller_file.name}: {path} -> {method_name} [{status}]")
for r in results:
print(r)
EOFRepository: wagle-project/wagle-server
Length of output: 123
🏁 Script executed:
# Now let's examine the JwtFilter to ensure it's properly validating tokens
head -80 src/main/java/com/waglewagle/server/global/security/jwt/JwtFilter.javaRepository: wagle-project/wagle-server
Length of output: 2263
🏁 Script executed:
# Check if there are any `@PostMapping`, `@PutMapping`, `@DeleteMapping` endpoints without protection
rg "/@(?:Post|Put|Delete|Patch)Mapping" src/main/java --type java -A 10 | grep -B 3 -A 7 "public.*\(" | head -100Repository: wagle-project/wagle-server
Length of output: 93
🏁 Script executed:
# Let me check if there are any other REST endpoints in controllers that we haven't identified
find src/main/java -name "*Controller.java" -type f | wc -lRepository: wagle-project/wagle-server
Length of output: 71
🏁 Script executed:
# Check all endpoints more carefully - find all methods in controllers
rg "@(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping|RequestMapping)" src/main/java --type java -B 1 | grep -E "(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping|RequestMapping|public)" | head -40Repository: wagle-project/wagle-server
Length of output: 4221
🏁 Script executed:
# Let me check if FestivalController endpoints have `@PreAuthorize` or should they
cat -n src/main/java/com/waglewagle/server/domain/festival/controller/FestivalController.javaRepository: wagle-project/wagle-server
Length of output: 1786
🏁 Script executed:
# Check all endpoints one more time with security status
python3 <<'EOF'
import re
from pathlib import Path
root = Path("src/main/java")
for controller in sorted(root.rglob("*Controller.java")):
if "Docs" in controller.name: # Skip docs interfaces
continue
content = controller.read_text(encoding="utf-8")
# Find all `@XxxMapping` annotations with methods
pattern = r'@(Get|Post|Put|Delete|Patch)Mapping.*?\n.*?@PreAuthorize.*?\npublic|@(Get|Post|Put|Delete|Patch)Mapping.*?\npublic'
lines = content.splitlines()
for i, line in enumerate(lines):
if '@' in line and 'Mapping' in line:
# Check next 10 lines for method and `@PreAuthorize`
next_lines = "\n".join(lines[i:min(i+10, len(lines))])
has_preauth = '@PreAuthorize' in next_lines
method_match = re.search(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(', next_lines)
if method_match:
method = method_match.group(1)
mapping = line.strip()
status = "✓" if has_preauth else "✗"
print(f"{status} {controller.name}: {mapping} -> {method}")
EOFRepository: wagle-project/wagle-server
Length of output: 132
🏁 Script executed:
# Let me verify all unprotected endpoints in detail
python3 <<'EOF'
import re
from pathlib import Path
root = Path("src/main/java/com/waglewagle/server/domain")
print("=== UNPROTECTED ENDPOINTS ===")
for controller in sorted(root.rglob("*Controller.java")):
if "Docs" in controller.name:
continue
content = controller.read_text(encoding="utf-8")
lines = content.splitlines()
class_mapping = ""
for i, line in enumerate(lines):
if "@RequestMapping" in line:
m = re.search(r'@RequestMapping\("([^"]+)"\)', line)
if m:
class_mapping = m.group(1)
if re.search(r'@(Get|Post|Put|Delete|Patch)Mapping', line):
# Get full block
block = "\n".join(lines[i:min(i+15, len(lines))])
# Extract mapping path
path_match = re.search(r'@\w+Mapping\("([^"]+)"\)|@\w+Mapping\(\)', line)
mapping_path = path_match.group(1) if path_match and path_match.group(1) else ""
full_path = class_mapping + mapping_path
# Check for `@PreAuthorize`
has_auth = "@PreAuthorize" in block
# Get method name
method_match = re.search(r'public\s+[\w<>\[\], ?]+\s+(\w+)\s*\(', block)
if method_match:
method = method_match.group(1)
if not has_auth:
print(f" {controller.name}: {full_path} -> {method}")
EOFRepository: wagle-project/wagle-server
Length of output: 147
🏁 Script executed:
# Check if Festival endpoints are actually meant to be public by checking if they need authentication
grep -r "Festival" src/main/java/com/waglewagle/server/domain/festival/controller/ --include="*.java" | grep -i "public\|private\|auth" | head -20Repository: wagle-project/wagle-server
Length of output: 868
🏁 Script executed:
# Double-check: are FestivalController endpoints supposed to be public?
# Look at the interface/docs to see if there's any auth requirement mentioned
cat -n src/main/java/com/waglewagle/server/domain/festival/controller/FestivalControllerDocs.javaRepository: wagle-project/wagle-server
Length of output: 4825
기본 인가 정책이 permitAll이므로 새 엔드포인트 추가 시 보호 누락 위험이 있습니다.
Line 57의 anyRequest().permitAll()은 명시적으로 허용되지 않은 엔드포인트도 모두 공개되는 fail-open 구조입니다. 현재는 /health가 명시적으로 line 53에서 permitAll()로 지정되어 있고, JwtFilter가 정상 작동하며 protected 엔드포인트들이 @PreAuthorize로 보호되어 있어 문제없이 작동합니다. 다만 새로운 엔드포인트 추가 시 @PreAuthorize 어노테이션을 누락하면 의도하지 않게 공개될 수 있으므로, 기본값을 authenticated() 또는 denyAll()로 두고 공개 API만 명시적으로 permitAll()로 지정하는 구성을 권장합니다.
🔧 제안 수정안
- // 나머지는 다 인증 불필요
- // 인증이 필요한 메소드 위 `@PreAuthorize을` 붙일 것
- .anyRequest().permitAll()
+ // 기본은 인증 필요(새 엔드포인트 추가 시 실수로 인한 공개 방지)
+ .anyRequest().authenticated()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/main/java/com/waglewagle/server/global/security/config/SecurityConfig.java`
around lines 55 - 57, The current SecurityConfig uses anyRequest().permitAll(),
which is a fail-open default that risks accidental exposure; change the policy
to a fail-closed default by replacing anyRequest().permitAll() with
anyRequest().authenticated() (or denyAll() if stricter) and explicitly add
permitAll() matchers for public endpoints such as the existing /health route and
any other intended public APIs; update the configuration in SecurityConfig
(where anyRequest().permitAll() is declared) and ensure JwtFilter and
`@PreAuthorize-protected` endpoints remain functional under the new default.
Summary
main브랜치에만 머지된 PR [Fix] SecurityConfig 설정 오류로 인해 @PreAuthorize 어노테이션이 제대로 작동하지 않는 문제 해결 (#22) #30 (SecurityConfig 수정) 변경사항을develop에 반영변경 파일
SecurityConfig.java:.anyRequest().authenticated()→.anyRequest().permitAll()(인증 필요 API는@PreAuthorize로 개별 관리)README.md: 업데이트docs/convention.md: 신규 추가docs/erd.md: 신규 추가Test plan
@PreAuthorize적용된 API는 토큰 없이 401 반환 확인🤖 Generated with Claude Code
Summary by CodeRabbit
릴리스 노트