OAuth 2.0 Flow

강서진·2024년 4월 22일

스프링 시큐리티에서 OAuth 인증 과정은 2개의 필터를 거친다. 이 필터들이 각자 어떤 역할을 하는지의 흐름을 알아보고자 소스코드를 들여다보았다.

OAuth2AuthorizationRequestRedirectFilter

OAuth2AuthorizationRequestRedirectFilter 필터는 사용자의 브라우저를 Authorization server의 인증 엔드포인트에 리다이렉트하는 것으로 authorization code grant 프로세스를 초기화한다. 엔드포인트로의 redirect uri로 사용되는 OAuth 2.0 Authorization request를 빌드하는데, 이 request는 클라이언트 id, scope, state, response type, 그리고 인증이 성공했(거나 실패했)을 때 사용자를 리다이렉트할 redirection uri를 포함하고 있다.
기본적으로 이 필터는 DefaultOAuth2AuthorizationRequestResolver를 사용해 /oauth2/authorization/{registrationId}로 들어오는 권한부여 요청에 응답한다. {registrationId}는 OAuth 2.0 인증 요청을 시작하는 데 사용되는 클라이언트의 등록 식별자이다. 생성자에 넘겨주는 ClientRegistrationRepository를 달리 하거나, 사용하는 OAuth2AuthorizationRequestResolver를 직접 재정의하여 이 기본 설정을 수정할 수 있다.

이 필터에서는 OAuth2AuthorizationRequestResolver의 resolve 메서드를 호출해, 받은 HttpSerevletRequest에서 OAuth2AuthorizationRequest 객체를 생성하여 반환한다.

OAuth2AuthorizationRequestResolver

이 인터페이스를 구현한 클래스들은 HttpServletRequest에서 OAuth2AuthorizationRequest 객체를 생성할 수 있다. 기본적으로 DefaultOAuth2AuthorizationRequestResolver 구현체가 사용된다.

DefaultOAuth2AuthorizationRequestResolver

OAuth2AuthorizationRequestResolver 인터페이스의 구현체로, 기본 URI패턴 /oauth2/authorization/{registrationId}를 사용하여 HttpServletRequest에서 OAuth2AuthorizationRequest 객체를 생성하여 반환한다.
더 자세한 과정은 다음과 같다.
(1) resolve 메서드로 HttpServletRequest를 받는다. 이 요청의 URI 패턴에서 문자열인 {registrationId}를 추출한다.
(2) getAction() 메서드를 호출하여 요청 파라미터에서 action이 있으면 문자열로 추출한다(없으면 디폴트로 login을 사용한다).
(3) HttpServletRequest, registrationId, action을 받는 resolve 메서드를 호출하여 OAuth2AuthorizationRequest 객체를 생성해 반환한다.

OAuth2AuthorizationRequestRedirectFilter는 파라미터로 받은 OAuth2AuthorizationRequest의 Grant Type이 지정된 타입과 일치하면, 이를 AuthorizationRequestRepository에 저장한 후 OAuth2AuthorizationRequest가 가진 AuthorizationRequestUri로 리다이렉트 요청을 보낸다.

AuthorizationRequestRepository

인증 과정 중에 파라미터로 전달된 redirect_uri, state 등을 저장하는 인터페이스이다.
사용자가 OAuth 2.0 인증이 필요한 요청을 날릴 때 요청이 발생하는데, 이 요청은 OAuth2AuthorizationRequestRedirectFilter가 인터셉트한다. 이 필터가 요청에서 필요한 파라미터를 추출하여 권한 요청을 생성하는데, 이 요청이 AuthorizationRequestRepository에 저장된다.
사용자의 권한 부여 프로세스가 끝나면 다시 해당 필터가 repository에 담겨있던 권한 요청을 state 파라미터를 사용하여 받아온다. 필터는 이 과정에서 원래의 권한 요청의 state 파라미터와 일치하는지를 보고 권한 부여 프로세스의 무결성을 확인할 수 있다.

요약

요약하면, OAuth2AuthorizationRequestRedirectFilter 필터는 다음과 같은 작업을 처리한다.

  • OAuth 2.0 인증 프로세스를 초기화:
    보호된 리소스에 액세스하거나, OAuth 2.0 인증이 필요한 로그인 프로세스 시작 시 인증 요청을 가로챈다.
  • 사용자를 인증 서버로 리다이렉션:
    사용자의 웹 브라우저를 인증 서버의 인증 엔드포인트로 리다이렉트
    (인증 서버는 주로 구글, 카카오, 네이버 등 사용자가 지정한 OAuth 2.0 서버를 의미한다. 리소스 서버와 일치하는 경우가 많다.)
  • 인증 요청 매개변수 전달:
    리디렉션과 함께 필요한 매개변수를 전달한다.
    주로 클라이언트 Id, 리디렉션 URI, 요청 범위(scope) 및 추가적인 매개변수가 포함된다.
  • 인증 콜백 처리:
    사용자가 인증 프로세스를 완료하면 발급되는 인증 코드 또는 액세스 토큰이 인증 콜백 URL로 리다이렉트된다. 이 콜백을 처리하고, URL 매개변수에서 인증 코드나 액세스 토큰을 추출한다.
  • 인증 프로세스 완료 처리:
    인증 코드나 액세스 토큰을 추출한 후 액세스 토큰(또는 리프레시 토큰 등)으로 교환하기 위한 백엔드 호출을 수행한다(다른 구성요소가 담당할 수도 있음).

OAuth2LoginAuthenticationFilter

OAuth2LoginAuthenticationFilter는 authorization code grant 플로우에서 OAuth2Authorization 응답을 처리하고 OAuth2LoginAuthenticationToken을 AuthenticationManager에 위임하여 사용자를 로그인하는 과정을 담당한다.

이 과정은 다음과 같이 진행된다.
(1) Resource Owner가 클라이언트(=애플리케이션)에게 액세스를 허용하였다면, Authorization Server는 redirect_uri의 파라미터에 code와 state 값을 추가하고 Resource Owner(End-user)의 웹 브라우저를 이 필터로 리다이렉트한다.
(2) 이 필터는 전달받은 code로 OAuth2LoginAuthenticationToken을 생성하고, 이를 AuthenticationManager에게 위임한다.
(3) 인증에 성공하면 End-user의 principal을 가지고, OAuth2AutorizedClientRepository를 통해 Authorized Client와 관련된 OAuth2AuthenticationToken이 생성된다.
(4) OAuth2AuthenticationToken이 반환되고, SecurityContextRepository에 저장된다.

AbstractAuthenticationProcessingFilter

OAuth2LoginAuthenticationFilter는 AbstractAuthenticationProcessingFilter를 상속하는데, 이 추상 클래스 필터가 작동하기 위해서는 AuthenticationManager가 필요하다. 인증이 필요한 요청이나 로그인 요청이 들어올 경우 이를 인터셉트하며, attempAuthentication 메서드를 호출하여 인증을 진행한다.
인증이 성공하면 반환된 Authentication 객체는 현재 스레드의 (선행된 필터에서 이미 생성되었을) SecurityContext에 저장된다. 이후에는 AuthenticationSuccessHandler가 호출되어 성공적인 로그인 이후의 처리과정을 담당하며, 따로 생성해주지 않을 경우 기본적으로 생성된 SavedRequestAwareAuthenticationSuccessHandler가 맡는다.
또, 애플리케이션 컨텍스트에서 InteractiveAuthenticationSuccessEvent가 발생한다(인증에 실패한 경우에는 AuthenticationManager가 기록 및 처리를 담당하므로 별도의 이벤트가 발생하지 않는다).
반대로 인증이 실패할 경우, AuthenticationFailureHandler가 인증 실패 정보를 클라이언트에게로 전달한다. 따로 생성해주지 않은 경우에는 기본적으로 생성된 SimpleUrlAuthenticationFaulreHandler가 호출되어 인증 실패를 처리한다(401 에러).
세션을 사용할 경우, attemptAuthentication()이 성공할 경우 바로 호출되는 SessionAuthenticationStrategy가 있다. session-fixation 공격을 예방하거나 특정 유저가 로그인한 세션의 수를 일정하게 유지하기 위한 구현체를 따로 주입할 수 있다.

0개의 댓글