-
Notifications
You must be signed in to change notification settings - Fork 0
chore(gateway): sanitize member headers #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/product-catalog-bundle
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||||||||||||
| package com.comatching.gateway.filter; | ||||||||||||||
|
|
||||||||||||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||||||||||||
|
|
||||||||||||||
| import java.util.concurrent.atomic.AtomicReference; | ||||||||||||||
|
|
||||||||||||||
| import org.junit.jupiter.api.Test; | ||||||||||||||
| import org.springframework.cloud.gateway.filter.GatewayFilter; | ||||||||||||||
| import org.springframework.http.HttpCookie; | ||||||||||||||
| import org.springframework.http.server.reactive.ServerHttpRequest; | ||||||||||||||
| import org.springframework.mock.http.server.reactive.MockServerHttpRequest; | ||||||||||||||
| import org.springframework.mock.web.server.MockServerWebExchange; | ||||||||||||||
|
|
||||||||||||||
| import com.comatching.common.util.JwtUtil; | ||||||||||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||||||||||||
|
|
||||||||||||||
| import reactor.core.publisher.Mono; | ||||||||||||||
|
|
||||||||||||||
| class AuthorizationHeaderFilterTest { | ||||||||||||||
|
|
||||||||||||||
| private static final String SECRET_KEY = | ||||||||||||||
| "c2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK"; | ||||||||||||||
|
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 코드에 하드코딩된 시크릿 키가 포함되어 있습니다. 비록 테스트 환경이라 할지라도, 이는 보안상 좋지 않은 관행이며 실제 키가 실수로 커밋될 위험을 내포합니다. (스타일 가이드 8. Security & Stability, 99번 항목) 테스트용 키는 테스트 프로퍼티 파일( 예를 들어, 테스트 클래스 상단에 References
|
||||||||||||||
|
|
||||||||||||||
| private final JwtUtil jwtUtil = new JwtUtil(SECRET_KEY, 3600000L, 3600000L); | ||||||||||||||
| private final AuthorizationHeaderFilter filter = new AuthorizationHeaderFilter(jwtUtil, new ObjectMapper()); | ||||||||||||||
|
|
||||||||||||||
| @Test | ||||||||||||||
| void shouldReplaceClientMemberHeadersWithTokenClaims() { | ||||||||||||||
| String accessToken = jwtUtil.createAccessToken( | ||||||||||||||
| 1L, | ||||||||||||||
| "admin@comatching.com", | ||||||||||||||
| "ROLE_ADMIN", | ||||||||||||||
| "ACTIVE", | ||||||||||||||
| "관리자" | ||||||||||||||
| ); | ||||||||||||||
| MockServerHttpRequest request = MockServerHttpRequest.get("/api/v1/admin/users") | ||||||||||||||
| .cookie(new HttpCookie("accessToken", accessToken)) | ||||||||||||||
| .header("X-Member-Id", "999") | ||||||||||||||
| .header("X-Member-Email", "user@comatching.com") | ||||||||||||||
| .header("X-Member-Role", "ROLE_USER") | ||||||||||||||
| .header("X-Member-Nickname", "stale") | ||||||||||||||
| .build(); | ||||||||||||||
| MockServerWebExchange exchange = MockServerWebExchange.from(request); | ||||||||||||||
| AtomicReference<ServerHttpRequest> downstreamRequest = new AtomicReference<>(); | ||||||||||||||
| GatewayFilter gatewayFilter = filter.apply(new AuthorizationHeaderFilter.Config()); | ||||||||||||||
|
|
||||||||||||||
| gatewayFilter.filter(exchange, filteredExchange -> { | ||||||||||||||
| downstreamRequest.set(filteredExchange.getRequest()); | ||||||||||||||
| return Mono.empty(); | ||||||||||||||
| }).block(); | ||||||||||||||
|
|
||||||||||||||
| ServerHttpRequest mutatedRequest = downstreamRequest.get(); | ||||||||||||||
| assertThat(mutatedRequest.getHeaders().get("X-Member-Id")).containsExactly("1"); | ||||||||||||||
| assertThat(mutatedRequest.getHeaders().get("X-Member-Email")).containsExactly("admin@comatching.com"); | ||||||||||||||
| assertThat(mutatedRequest.getHeaders().get("X-Member-Role")).containsExactly("ROLE_ADMIN"); | ||||||||||||||
| assertThat(mutatedRequest.getHeaders().get("X-Member-Nickname")).containsExactly( | ||||||||||||||
| "%EA%B4%80%EB%A6%AC%EC%9E%90" | ||||||||||||||
| ); | ||||||||||||||
|
Comment on lines
+56
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 검증 로직에 URL 인코딩된 문자열 리터럴( 기대하는 원본 값("관리자")을 테스트 내에서 직접 인코딩하여 비교하면, 테스트의 의도가 훨씬 명확해지고 유지보수가 용이해집니다.
Suggested change
References
|
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestBuilder를 여러 번 호출하여 헤더를 수정하는 대신, 하나의headers블록으로 통합하는 것이 더 효율적이고 가독성이 좋습니다. 이렇게 하면 불필요한 중간ServerHttpRequest.Builder인스턴스 생성을 피할 수 있습니다.또한, 반복적으로 사용되는 헤더 이름("X-Member-Id" 등)은 클래스 레벨의 상수로 선언하여 관리하는 것을 권장합니다. 이는 오타 가능성을 줄이고 코드의 유지보수성을 향상시킵니다. (스타일 가이드 7. Code Style & Clean Code, 90번 항목)
References