Spring Security - 2

Spring Security에 대해 공부하고 정리한 내용입니다.

Authentication

Authentication은 Spring Security에서 두가지 목적을 갖고있다.

  • AuthenticationManager의 입력으로 한 유저가 인증하기위해 제공한 credentials을 제공하기위함. 이 경우 isAuthenticated()의 결과는 false다.
  • 현재 인증된 사용자를 나타낸다. 현재 Authentication이 SecurityContext로 부터 얻을 수 있다면 인증된 사용자라고 나타낼 수 있다.

Authentication은 다음을 포함하고 있다.

  • principal - 유저를 식별한다. 유저 이름과 패스워드와 함께 인증이 시도 될 때, principal은 보통 UserDetails의 인스턴스이다.
  • credentials - 보통 패스워드를 나타낸다. 유저가 인증된 이후에는 노출이 되지 않도록 제거된다.
  • authorities - GrantedAuthority는 유저가 권한이 있다는 높은 레벨의 허가를 나타낸다. 예를 들어 roles or scopes를 얘기한다.

GrantedAuthority

위에 Authentication에서 보았듯이 GrantedAuthority는 유저가 권한이 있다는 높은 레벨의 허가를 나타낸다.

GrantedAuthorityAuthetication.getAuthorities 메소드를 통해 얻을 수 있다. 이 메소드는 GrantedAuthority의 컬렉션을 제공한다.

AuthenticationManager

AuthenticationManager는 Spring Security 필터가 인증을 수행하는 방법을 정의한 API다. 반환 된 AuthenticationAuthenticationManager를 실행한 컨트롤러(Spring Security 필터들)에 의해 SecurityContextHolder에 설정이된다.

AuthenticationManager를 사용하지 않고 Spring Security 필터에서 말고 직접 AuthenticationSecurityContextHolder에 설정할 수 있다.

가장 일반적인 AuthenticationManager의 구현체는 ProviderManager 이다.

ProviderManager

ProviderManager 가장 일반적인 AuthenticationManager의 구현체이다.

ProviderManager 동작

ProviderManagerAuthenticationProvider 리스트로 위임을 한다. 각각의 AuthenticationProvider는 인증이 성공, 실패를 나타낼 수 있고 결정할 수 없으면 다음 AuthenticationProvider에게 결정하도록 내려보낸다. 만약 어떠한 AuthenticationProvider가 인증을 할 수 없으면 AuthenticationExceptionProviderNotFoundException와 함께 인증 실패를 알릴 것이다.

여기서 결정할 수 없다는 것은 각 AuthenticationProvider는 특정 유형의 인증을 수행하는 방법을 갖고 있고 이에 맞지 않다는 것을 얘기한다. 예를 들어 한 AuthenticationProvider는 유저 이름과 패스워드로 검증을 할 수 있는 반면, 다른 AuthenticationProvider는 다른 방식으로 검증을 한다. 즉, 다양한 인증 방식을 지원하면서 그 중 하나의 방식으로 인증을 할 수 있다.

AuthenticationProvider

위에서 보았듯이 다수의 AuthenticationProvider들은 ProviderManger에 속해 있고 각각의 AuthenticationProvider는 특정 유형의 인증을 수행한다.

예를 들어 DaoAuthenticationProvider는 유저 이름과 패스워드로 인증을 지원하고 반면에 JwtAuthenticationProvider는 JWT 토큰으로 인증을 지원한다.

Request Credential with AuthenticationEntryPoint

AuthenticationEntryPoint는 유저에게 credential을 요청하는 HTTP 응답을 보내는 것에 사용된다.

인증할 수 있는 정보를 클라이언트가 같이 보낸다면 HTTP 응답으로 crendential 요청을 할 필요가 없지만 클라이언트가 인증되지 않은 상태로 자원을 요청한다면 접근을 인가할 수 없다. 이 경우에 AuthenticationEntryPoint를 구현함으로 클라이언트에게 credential을 요청하는 것이다. AuthenticationEntryPoint에 page를 redirect하거나 WWW-Authenticate를 응답 헤더에 포함하는 방법 등으로 클라이언트에게 요청을 한다.

AbstractAuthenticationProcessingFilter

유저의 credential을 인증하기 위한 기반 필터이다.

ProviderManager 동작

  1. 유저가 credential을 보냈을 때 AbstractAuthenticationProcessingFilter가 인증 될 HttpServletRequestAuthentication을 만든다. Authentication의 타입은 AbstractAuthenticationProcessingFilter의 subclass의 의존해서 만들어진다.

    예를 들어, UsernamePasswordAuthenticationFilterHttpServletRequest에 제출된 유저이름과 패스워드로 UsernamePaswordAuthenticationToken을 만든다.

  2. AuthenticationManager에게 인증을 위해 Authentication이 전달된다.

  3. 만약 인증이 실패라면 인증 실패 처리가 된다.

    • SecurityContextHolder는 비워진다.
    • RememberMeService.loginFail이 실행된다. Remember me가 설정되지 않았다면 아무것도 하지 않는다.
    • AuthneticationFailureHandler가 실행된다.
  4. 만약 인증이 성공이라면 인증 성공 처리가 된다.

    • SessionAuthenticationStrategy 에 새 로그인이 알려진다.
    • AuthenticationSecurityContextHolder에 설정되고 이후에 SecurityContextPersistencFilterSecurityContextHttpSession에 저장한다.
    • RememberMeService.loginSuccess가 실행된다. Remember me가 설정되지 않았다면 아무것도 하지 않는다.
    • ApplicationEventPublisherInteractiveAuthenticationSuccessEvent를 발행한다.
    • AuthenticationSuccessHandler가 실행된다.

Reference

https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-authentication-authentication

⤧  Next post 가비지 컬렉션(GC) ⤧  Previous post 테스트 커버리지(Test Coverage)