이 클래스의 주요 역할은 Spring Security 필터들이 올바른 순서로 실행되도록 각 필터의 순서를 지정하는 것입니다.
@SuppressWarnings("serial")
final class FilterOrderRegistration {
private static final int INITIAL_ORDER = 100;
private static final int ORDER_STEP = 100;
private final Map<String, Integer> filterToOrder = new HashMap<>();
FilterOrderRegistration() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class, order.next());
put(ForceEagerSessionCreationFilter.class, order.next());
put(ChannelProcessingFilter.class, order.next());
order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextHolderFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class, order.next());
put(CsrfFilter.class, order.next());
put(LogoutFilter.class, order.next());
this.filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
order.next());
this.filterToOrder.put(
"org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter",
order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
this.filterToOrder.put(
"org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
order.next(); // gh-8105
put(DefaultLoginPageGeneratingFilter.class, order.next());
put(DefaultLogoutPageGeneratingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(DigestAuthenticationFilter.class, order.next());
this.filterToOrder.put(
"org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter",
order.next());
put(BasicAuthenticationFilter.class, order.next());
put(RequestCacheAwareFilter.class, order.next());
put(SecurityContextHolderAwareRequestFilter.class, order.next());
put(JaasApiIntegrationFilter.class, order.next());
put(RememberMeAuthenticationFilter.class, order.next());
put(AnonymousAuthenticationFilter.class, order.next());
this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
order.next());
put(SessionManagementFilter.class, order.next());
put(ExceptionTranslationFilter.class, order.next());
put(FilterSecurityInterceptor.class, order.next());
put(AuthorizationFilter.class, order.next());
put(SwitchUserFilter.class, order.next());
}
/**
* Register a {@link Filter} with its specific position. If the {@link Filter} was
* already registered before, the position previously defined is not going to be
* overriden
* @param filter the {@link Filter} to register
* @param position the position to associate with the {@link Filter}
*/
void put(Class<? extends Filter> filter, int position) {
this.filterToOrder.putIfAbsent(filter.getName(), position);
}
/**
* Gets the order of a particular {@link Filter} class taking into consideration
* superclasses.
* @param clazz the {@link Filter} class to determine the sort order
* @return the sort order or null if not defined
*/
Integer getOrder(Class<?> clazz) {
while (clazz != null) {
Integer result = this.filterToOrder.get(clazz.getName());
if (result != null) {
return result;
}
clazz = clazz.getSuperclass();
}
return null;
}
private static class Step {
private int value;
private final int stepSize;
Step(int initialValue, int stepSize) {
this.value = initialValue;
this.stepSize = stepSize;
}
int next() {
int value = this.value;
this.value += this.stepSize;
return value;
}
}
}
1. FilterOrderRegistration 생성자
FilterOrderRegistration() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class, order.next());
// 여러 필터들을 순차적으로 등록
put(SwitchUserFilter.class, order.next());
}
• 이 생성자는 filterToOrder라는 맵에 다양한 Spring Security 필터들을 순서대로 등록합니다.
• 각 필터는 순서대로 고유한 순서 값(position)을 갖게 되며, 이 값은 100에서 시작해 각 필터가 100씩 증가하는 값을 갖습니다.
• Step 객체인 order를 통해 next() 메서드를 호출하여 position 값을 순차적으로 증가시키며 필터를 등록합니다.
• 이를 통해 필터들이 filterToOrder 맵에 등록된 순서대로 실행될 수 있도록 보장합니다.
주요 필터와 그 역할
1. DisableEncodeUrlFilter
• URL을 인코딩하지 않도록 설정하는 필터입니다. 보안 목적과 무관하며 주로 URL 처리 시의 특정 요구사항을 반영합니다.
2. ForceEagerSessionCreationFilter
• 세션을 필요로 하는 경우 세션을 즉시 생성하도록 강제하는 필터입니다.
3. ChannelProcessingFilter
• 요청이 HTTPS와 같은 특정 전송 채널을 통해서만 전달되도록 하는 필터입니다. 보안 채널을 강제하는 데 사용됩니다.
4. WebAsyncManagerIntegrationFilter
• Spring의 비동기 요청 처리와 Spring Security를 통합해주는 필터입니다. 비동기 처리가 필요한 경우에도 보안을 유지할 수 있도록 합니다.
5. SecurityContextHolderFilter
• SecurityContext 객체를 SecurityContextHolder에 설정하고 관리하는 필터입니다. 인증 정보를 전역적으로 접근 가능하게 유지합니다.
6. SecurityContextPersistenceFilter
• SecurityContext를 세션에 저장하고 로드하는 역할을 합니다. 요청 사이에서 사용자 인증 상태를 유지하는 데 필요합니다.
7. HeaderWriterFilter
• 응답 헤더를 추가하거나 수정하는 필터입니다. 보안 헤더를 설정해 클릭재킹, XSS와 같은 공격을 방지하는 데 사용됩니다.
8. CorsFilter
• Cross-Origin Resource Sharing (CORS) 정책을 적용하는 필터입니다. 다른 도메인에서의 요청을 허용할지 설정합니다.
9. CsrfFilter
• CSRF(Cross-Site Request Forgery) 공격을 방지하기 위한 필터입니다. 요청의 유효성을 확인하는 CSRF 토큰을 검증합니다.
10. LogoutFilter
• 사용자가 로그아웃할 때 호출되는 필터입니다. 세션을 무효화하고 SecurityContext를 초기화하여 로그아웃을 처리합니다.
11. OAuth2AuthorizationRequestRedirectFilter
• OAuth2 인증 요청을 위한 필터입니다. 사용자를 OAuth2 권한 서버로 리다이렉트하여 인증 요청을 시작합니다.
12. Saml2WebSsoAuthenticationRequestFilter
• SAML2 프로토콜을 통해 SSO 인증 요청을 처리하는 필터입니다. SAML2 환경에서 SSO를 지원할 때 사용됩니다.
13. X509AuthenticationFilter
• X.509 인증서를 사용하여 사용자 인증을 수행하는 필터입니다. SSL 클라이언트 인증이 필요한 경우 사용됩니다.
14. AbstractPreAuthenticatedProcessingFilter
• 사전 인증된 사용자의 인증 처리를 담당합니다. 예를 들어, SSO 등 외부 시스템에서 인증된 사용자를 처리할 때 사용됩니다.
15. CasAuthenticationFilter
• 중앙 인증 서비스(CAS)를 사용한 인증을 처리하는 필터입니다. 주로 교육기관 등에서 SSO 인증을 위해 사용됩니다.
16. OAuth2LoginAuthenticationFilter
• OAuth2 로그인 요청을 처리하는 필터입니다. OAuth2AuthorizationRequestRedirectFilter를 통해 리다이렉트된 이후의 처리를 담당합니다.
17. Saml2WebSsoAuthenticationFilter
• SAML2 프로토콜을 통해 SSO 로그인 요청을 처리합니다.
18. UsernamePasswordAuthenticationFilter
• 사용자 이름과 비밀번호를 통한 기본적인 인증을 처리하는 필터입니다. Spring Security의 가장 기본적인 인증 방식입니다.
19. DefaultLoginPageGeneratingFilter
• 기본 로그인 페이지를 생성하는 필터입니다. 로그인 페이지가 설정되지 않았을 때 기본 페이지를 제공합니다.
20. DefaultLogoutPageGeneratingFilter
• 기본 로그아웃 페이지를 생성하는 필터입니다. 로그아웃 페이지가 설정되지 않았을 때 기본 페이지를 제공합니다.
21. ConcurrentSessionFilter
• 동일한 계정으로 여러 세션을 제한하는 필터입니다. 특정 사용자가 하나의 세션만 유지하도록 할 때 사용됩니다.
22. DigestAuthenticationFilter
• Digest 인증 방식을 처리하는 필터입니다. HTTP Basic 인증보다 안전한 인증 방법을 제공하는 데 사용됩니다.
23. BearerTokenAuthenticationFilter
• JWT와 같은 Bearer 토큰 기반 인증을 처리하는 필터입니다.
24. BasicAuthenticationFilter
• HTTP Basic 인증을 처리하는 필터입니다. 기본적인 인증 방식으로, 사용자 이름과 비밀번호를 이용합니다.
25. RequestCacheAwareFilter
• 요청 캐시를 관리하는 필터로, 인증이 필요한 요청을 캐시에 저장했다가 인증 후에 요청을 재시도하도록 합니다.
26. SecurityContextHolderAwareRequestFilter
• SecurityContextHolder에 저장된 정보를 기반으로 요청에 보안 컨텍스트를 적용합니다.
27. JaasApiIntegrationFilter
• JAAS(Java Authentication and Authorization Service)를 지원하는 필터입니다. JAAS API와의 통합을 지원합니다.
28. RememberMeAuthenticationFilter
• Remember-Me 기능을 지원하는 필터입니다. 사용자가 로그인할 때 “Remember Me” 옵션을 선택하면, 다음 번 로그인 시 인증 상태를 유지합니다.
29. AnonymousAuthenticationFilter
• 인증되지 않은 사용자를 위한 기본 인증을 제공하는 필터입니다. 인증되지 않은 사용자에게 익명 권한을 부여합니다.
30. OAuth2AuthorizationCodeGrantFilter
• OAuth2 코드 인증 방식을 처리하는 필터입니다. Authorization Code Grant 방식을 통해 인증을 수행합니다.
31. SessionManagementFilter
• 세션 관리와 관련된 설정을 적용하는 필터입니다. 예를 들어, 최대 세션 수 제한이나 세션 고정 공격 방지 설정을 처리합니다.
32. ExceptionTranslationFilter
• 인증 또는 권한 오류 발생 시 예외를 처리하는 필터입니다. 에러 페이지로 리다이렉트하거나 오류 메시지를 반환합니다.
33. FilterSecurityInterceptor
• Spring Security의 접근 제어(ACL)를 적용하는 최종 필터입니다. 사용자 권한에 따라 요청이 허용되거나 거부됩니다.
34. AuthorizationFilter
• 요청에 대한 권한을 검사하는 필터입니다. 인증이 완료된 후, 사용자의 권한이 요청 리소스에 접근할 수 있는지 확인합니다.
35. SwitchUserFilter
• 관리자가 다른 사용자로 “스위치”하여 시스템에 접근할 수 있게 하는 필터입니다. 예를 들어, 관리자 계정이 사용자 계정으로 임시로 전환할 때 사용됩니다.
2. put(Class<? extends Filter> filter, int position)
void put(Class<? extends Filter> filter, int position) {
this.filterToOrder.putIfAbsent(filter.getName(), position);
}
• 이 메서드는 특정 필터와 해당 필터의 실행 순서(position)를 filterToOrder 맵에 저장합니다.
• putIfAbsent 메서드를 사용하여, 이미 필터가 등록되어 있다면 현재 position 값으로 덮어쓰지 않고 무시합니다. 이를 통해 필터의 중복 등록을 방지할 수 있습니다.
매개변수 설명:
• filter: 등록할 필터의 클래스 타입 (Class<? extends Filter>)
• position: 필터가 실행될 순서 (정수)
3. getOrder(Class<?> clazz)
Integer getOrder(Class<?> clazz) {
while (clazz != null) {
Integer result = this.filterToOrder.get(clazz.getName());
if (result != null) {
return result;
}
clazz = clazz.getSuperclass();
}
return null;
}
• getOrder는 특정 필터 클래스(clazz)의 순서를 반환합니다.
• filterToOrder 맵에서 해당 클래스 이름으로 순서를 찾고, 순서가 등록되지 않았다면 상위 클래스를 계속 탐색하여 등록된 순서 값을 찾습니다.
• 이는 필터가 상속 구조로 정의되었을 경우에도 올바르게 순서를 가져올 수 있도록 설계된 부분입니다.
반환 값:
• 필터가 등록된 순서 값(position)을 반환하며, 등록되지 않은 경우 null을 반환합니다.
사용 예시:
• 특정 필터의 실행 순서가 궁금할 때 getOrder(MyFilter.class)를 호출하여 순서를 확인할 수 있습니다.
4. Step 내부 클래스
private static class Step {
private int value;
private final int stepSize;
Step(int initialValue, int stepSize) {
this.value = initialValue;
this.stepSize = stepSize;
}
int next() {
int value = this.value;
this.value += this.stepSize;
return value;
}
}
• Step 클래스는 필터의 순서 값(position)을 자동으로 증가시키는 기능을 제공합니다.
• Step 객체는 초기 값(initialValue)과 증가 값(stepSize)을 받아서, next() 메서드를 호출할 때마다 현재 순서 값을 반환하고 다음 순서 값으로 증가시킵니다.
메서드 설명:
• next(): 현재 순서 값(value)을 반환하고, stepSize만큼 증가시켜 다음 호출 시 반환할 순서 값을 설정합니다.
사용 예시:
• Step order = new Step(100, 100);을 생성 후, order.next()를 호출할 때마다 100, 200, 300...의 순서를 생성합니다.
클래스의 전체 동작 요약
• FilterOrderRegistration 클래스는 Spring Security에서 사용하는 다양한 필터를 순서에 따라 filterToOrder 맵에 저장합니다.
• put() 메서드로 각 필터를 고유한 순서(position)로 등록하며, Step 클래스를 통해 순서를 순차적으로 생성합니다.
• getOrder() 메서드는 특정 필터 클래스의 순서를 확인하고, 필요한 경우 상위 클래스를 통해 순서를 찾아줍니다.
• 이러한 순서 관리를 통해 Spring Security는 요청이 처리될 때 필터들이 올바른 순서대로 실행될 수 있도록 보장합니다.
'Spring Security' 카테고리의 다른 글
CORS(Cross-Origin Resource Sharing)의 Simple Request와 Non-Simple Request (0) | 2024.10.31 |
---|---|
Spring Security 인증 아키텍처 (0) | 2024.10.31 |
requestMatcher (0) | 2024.10.30 |
hasAuthority와 그 외의 다양한 표현식 (0) | 2024.10.30 |
CSRF(Cross-Site Request Forgery) (2) | 2024.10.30 |