1. 인증 저장소 - SecurityContextHolder, SecurityContext
SecurityContextHolder
- 인증된 유저의 정보를 보관하는 저장소입니다.
- 다양한 방식의 인증 정보를 저장할 수 있습니다.
- 저장되는 인증 정보의 타입만 맞으면 됩니다.
- JWT, LDAP, OAuth, SSO 등
- 인증 정보를 저장하는 것이 사용자가 인증되었음을 나타내는 가장 간단한 방법입니다.
- SecurityContextHolder안에 담긴 SecurityContext(인증 정보)를 어떻게 보관할지 전략을 설정할 수 있습니다.
SecurityContextHolderStrategy
- SecurityContextHolder 내의 MODE_ 로 시작하는 static 변수로 선언되어 있습니다.
MODE_GLOBAL
- 전체 애플리케이션에 SecurityContext가 오직 한개 입니다.
MODE_INHERITABLETHREADLOCAL
- 현재 스레드의 SecurityContext를 자식스레드에 공유합니다.
(기본 옵션) MODE_THREADLOCAL
- 스레드당 SecurityContext가 할당됩니다.
- ThreadLocal에 SecurityContext가 저장됩니다.
- 스레드와 생명주기가 같으므로 인증 처리를 한 후 인증 정보가 남지 않도록 비워주어야 합니다.
- 비워주지 않으면, 스레드 재사용시에 이전 인증정보가 재사용될 수 있습니다.
SecurityContext
- Authentication 객체가 저장되는 보관소로 필요 시 언제든지 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 인터페이스
- 인증이 완료되면 HttpSession 에 저장되어 어플리케이션 전반에 걸쳐 접근이 가능합니다.
2. 인증저장소 필터 - SecurityContextHolderFilter
Persisting Authentication
- 처음 유저가 보안 리소스에 접근을 요청할 때, 인증이 되어있지 않으므로 로그인 창으로 리다이렉트 합니다.
- 유저가 리다이렉트된 로그인창을 통해 인증에 성공하면, 서버는 새로운 세션 아이디를 발급해줍니다.
- 발급받은 세션 아이디 값을 통해 클라이언트는 서버와 인증이 지속될 수 있습니다.
SecurityContextRepository
- 요청간의 SecurityContext를 지속하기 위해 사용되는 전략
- DelegatingSecurityContextRepository 를 기본 구현체로 사용합니다.
- DelegatingSecurityContextRepository는 여러 SecurityContextRepository 구현체들에게 위임하여 처리합니다.
- SecurityContextRepository 구현체
- HttpSessionSecurityContextRepository
- SecurityContext를 HttpSession에 저장합니다
- 여러 요청에 걸쳐 SecurityContext를 유지할 수 있습니다.
- RequestAttributeSecurityContextRepository
- SecurityContext를 ServletRequest의 attribute에 저장합니다
- dispatch type이 발생할 때 SecurityContext를 복원할 수 있습니다.
- 한 번의 요청에서만 SecurityContext를 유지할 수 있습니다.
- HttpSessionSecurityContextRepository
SecurityContextHolderFilter
- SecurityContextHolderFilter는 SecurityContextRepository로 SecurityContext를 로딩하는 역할을 맡은 필터입니다.
- SecurityContextHolderFilter는 SecurityContextRepository로 SecurityContext를 로딩하고
SecurityContextHolder에 SecurityContext를 셋팅합니다 - SecurityContextHolderFilter는 로딩하는 역할만 하기 때문에 SecurityContext는 저장되어있는 상태여야 합니다.
3. 인증 객체 - Authentication
- 인증된 유저의 정보를 표현하는 인터페이스 입니다.
- Principal
- user를 표현하는데 사용되는 필드입니다. (UserDetails 인터페이스)
- Credentials
- 식별정보에 대한 필드입니다.
- 보통 password를 담으며, 유저가 인증되면 유출방지를 위해 지워집니다.
- Authorities
- 유저의 권한에 대한 필드입니다.
- 역할과 범위로 표현됩니다 (GrantedAuthorities 인터페이스)
- Authenticated
- 인증성공 여부에 대한 필드입니다.
- false일 경우, 만나는 모든 security interceptor는 인증절차를 요구합니다
- 사용자가 보안 리소스 접근시도를 할 경우, authenticated 속성이 true인지 확인합니다
- false일 경우, AuthorizationFIlter는 예외를 발생시킵니다
- ExceptionTranslationFilter에 의해 사용자는 인증 절차로 리다이렉트 됩니다.
4. 인증 관리자 - AuthenticationManager
- Spring Security의 필터가 어떻게 인증을 수행할 것인지 결정하는 API 객체입니다.
- 인증 요청이 올 경우, 전달된 Authentication 객체를 대상으로 인증을 시도합니다.
- 인증에 성공할 경우, 사용자의 권한정보가 들어있는 Authentication를 리턴해줍니다.
- 리턴된 Authentication 객체는 SecurityContextHolder에 저장됩니다.
- 인증에 실패할 경우, 예외가 발생합니다.
- DisabledException : 계정이 enable 하지 않을 경우 (UserDetails 인터페이스의 isEnable() 리턴값 여부로 결정)
- LockedException : 계정이 locked 되었을 경우 (UserDetails 인터페이스의 isAccountNonLocked() 리턴값 여부로 결정)
- BadCredentialsException : Filter의 Provider가 인증 수행 도중 패스워드가 불일치 할 경우 (인증 수행 중, 예외를 발생시킴)
- 인증 과정은 위의 예외 순으로 수행됩니다.
- 불필요하게 패스워드 인증을 수행하지 않음으로써 논리적이고 효율적으로 동작합니다.
ProviderManager
- ProviderManager는 AuthenticationManager의 대표적인 구현체입니다.
- ProviderManager는 AuthenticationProvider가 담긴 List를 가집니다.
- ProviderManager는 이 List에게 인증을 위임합니다.
- List의 AuthenticationProvider들은 인증을 처리하면서
- 성공할 경우, ProviderManager에게 사용자의 권한정보가 들어있는 Authentication를 리턴해줍니다
- 실패할 경우, ProviderManager에게 AuthenticationException을 던집니다.
- 자신이 지원하지 않는 Authentication 객체일 경우, 다음 순서의 AuthenticationProvider이 결정하도록 패스합니다.
- List의 모든 AuthenticationProvider가 Authentication을 인증하는것을 지원하지 않는다면
- ProviderNotFoundException를 던집니다.
- List에게 위임하는 이러한 방식은
- 특정 Authentication 객체별 인증을 처리하는 방식을 따로 처리하여 전문화할 수 있고
- 동시에 다양한 Authentication의 인증처리를 지원할 수 있습니다.
- ProviderManager는 부모 AuthenticationManager를 가질 수 있습니다. (옵션)
- ProviderManager의 List에서 해당 Authentication을 처리하지 못하는 경우, 의뢰하기 위해 사용됩니다.
- ProviderManager들의 부모는 서로 같을 수 있습니다.
- 보통 ProviderManager들의 인증처리가 같은 부분이 있는 경우, 부모에게 공통적으로 처리되는 인증을 맡깁니다.
- 각 필터의 인증 방식만 다를경우, 다양한 인증 메커니즘을 구성하기 위해 필터의 ProviderManager를 다르게 구성합니다.
- 기본적으로 ProviderManager는 인증 성공 후, 인증객체에 있는 민감정보를 지웁니다.
- 보안을 강화하기 위함입니다.
- HttpSession에 민감정보가 필요이상으로 남아있는 것을 방지합니다.
- 그러나 이 정보가 지워지면 캐싱해서 사용하지 못합니다.
- 인증객체 정보를 캐싱하는 방법이 있습니다.
- AuthenticationProvider에 캐싱기능을 구현한 구현체를 사용합니다.
- ProviderManager의 eraseCredentialsAfterAuthentication 속성을 false로 설정합니다.
5. 인증 처리자 - AuthenticationProvider
- 인증 처리를 위해 ProviderManager에서 쓸 AuthenticationProvider를 셋팅할 수 있습니다.
- 각 AuthenticationProvider는 특정 타입의 Authentication을 처리할 수 있습니다.
6. 인증 요청 담당 - AuthenticationEntryPoint
- AuthenticationEntryPoint는 클라이언트에게 인증 요청에 대한 응답을 보내는데 쓰여집니다.
- 보안 리소스에 요청할 경우 인증이 필요합니다.
- 클라이언트가 이미 인증되어 있다면, 바로 접근이 가능합니다.
- 클라이언트가 이미 인증되어 있지 않다면, 서버는 클라이언트에게 보안 리소스를 제공할 수 없습니다.
- 클라이언트는 서버로부터 인증되어야 제공받을 수 있습니다.
- 서버는 클라이언트에게 인증을 요청해야 합니다.
- 이때 AuthenticationEntryPoint가 동작하여 클라이언트에게 인증요청 응답을 내려줍니다
- AuthenticationEntryPoint는 다양한 응답을 가집니다.
- 보통 로그인 페이지 리다이렉션
- WWW-Authenticate 헤더 응답
- 커스터마이징된 동작
7. 인증 필터 - AbstractAuthenticationProcessingFilter
- AbstractAuthenticationProcessingFilter는 비밀번호 기반 인증을 처리하는 필터로 사용됩니다.
- AbstractAuthenticationProcessingFilter는 사용할 AuthenticationManager를 필드에 셋팅하는 것이 필수입니다.
- AbstractAuthenticationProcessingFilter의 AuthenticationManager는 주로 인증 요청 토큰을 처리하는데 씁니다.
- 인증 요청 토큰은 특정 구현 클래스들에 의해 생성됩니다.
- AbstractAuthenticationProcessingFilter는 요청을 가로챕니다.
- 요청을 가로채어 자신이 처리할 수 있는 인증 객체인지 판단한 후 인증을 진행합니다.
- AbstractAuthenticationProcessingFilter는 추상클래스이므로 구현 매커니즘 별 구현된 서브클래스가 인증을 수행합니다.
- 클라이언트가 민감정보를 제출하여 인증 시도를 요청할 때
- AbstractAuthenticationProcessingFilter는 HttpServletRequest로부터 Authentication을 생성합니다.
- 생성된 Authentication는 AbstractAuthenticationProcessingFilter의 서브클래스에 따라 달라집니다.
- ex) UsernamePasswordAuthenticationFilter -> UsernamePasswordAuthenticationToken
- AuthenticationManager는 전달된 Authentication를 가지고 인증을 시도합니다.
- 인증이 실패하였다면
- SecurityContextHolder는 비워집니다.
- RememberMeService의 loginFail()이 호출됩니다. (rememberme가 설정되어 있는 경우에만 호출됨)
- AuthenticationFailureHandler가 호출됩니다.
- 인증이 성공하였다면
- SessionAuthenticationStrategy가 새로운 로그인을 알게됩니다. (세션 공격 정책에 의한 동작이 수행될 수 있음)
- SecurityContextHolder에 Authentication이 담겨집니다.
- RememberMeService의 loginSuccess()이 호출됩니다. (rememberme가 설정되어 있는 경우에만 호출됨)
- ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent 를 발행합니다.
- AuthenticationSuccessHandler가 호출됩니다.
참고
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] 3-3. 인증: 패스워드 저장소 (0) | 2023.10.02 |
---|---|
[Spring Security] 3-2. 인증: 아이디 / 패스워드 (2) | 2023.10.02 |
[Spring Security] 5. 예외 처리 (0) | 2023.09.30 |
[Spring Security] 2. 스프링 시큐리티 주요 아키텍처 (0) | 2021.07.28 |
[Spring Security] 2-1. 인증 필터 (0) | 2021.07.25 |