WEB/Security

Spring Authorization Server + 주요 도메인 클래스

Tony Lim 2022. 12. 25. 17:18
728x90

OAuth2.0 Authorization Server 소개

OpenID Connect 1.0 공급자 및 OAuth2 권한 부여 서버 제품을 구축하기 위한 안전하고 가볍고 사용자 지정 가능한 기반을 제공하기 위해 존재함 -> 기존에 keycloak으로 대신했던 auth server를 직접만들 수 있는 프레임워크를 제공하는 것임


초기화 과정 이해 - OAuth2AuthorizationServerConfiguration

OAuth2AuthorizationServerConfiguer를 추가되면 나머지 5개의 Configurer 들이 추가되고 build시 각각의 init, configure 메소드를 호출하며 필터를 만들어 낸다.

OAuth2 인가 서버에 대한 최소 기본 구성을 제공하는 설정 클래스이다.
OAuth2AuthorizationServerConfiguer를 사용하여 기본 구성을 적용하고 OAuth2 인가 서버를 지원하는 모든 인프라 구성 요소로 구성된 SecurityFilterChain 빈을 등록한다.

open id사용시 userinfo endpoint 요청시 access token과 함께 요청하는데 이를 검증할 JwtDecoder가 필요한 것이다.

endpoints matcher에 해당하는 url 만 검증을 시도한다. 해당 url을 하면 401이 뜨면서 접근이 아예 불가능해지고 다른 url을 사용하면 404로 서버로 접근이 가능하지만 해당 페이지가 없다말해준다.(있으면 걸루감)

 

총 3가지 방법으로 auth sever설정을 로드 할 수 있는데 위 2가지 방법은 기본설정을 로드하는 것이고 마지막은 자신이 직접 custom하게 설정들을 하나하나 추가하는 방법이다.


초기화 과정 이해 - OAuth2AuthorizationServeConfiguer

introspection endpoint , jwks(public key) endpoint , auth server metadata endpoint 등이 존재한다. 이걸 기반으로 설정들을 초기화하게 된다.

OAuth2ClientAuthenticationConfigurer , OAuth2AuthorizationEndpointConfigurer , OAuth2TokenEndpointConfigurer , OAuth2TokenIntrospectionEndpointConfigurer , OAuth2TokenRevocationEndpointConfigurer

총 5개의 Configurer로 endpoint 와 실제 요청이 들어왔을시 해결할 수있는 provider, filter를 build과정에서 초기화한다.

Token endpoint에서 Implicit , password GrantType이 안보이는것을 확인할 수 있다. OAuth 2.1 사양에서는 Implicit 와 Password 방식이 Deprecated 되어서 그럴 수 있어보인다.

open id connect 프로토콜을 통해 인증 처리를 할 수 있게 설정을 초기화한다.
OpenId Connection 엔드포인트는 메타데이터를 조회할 수 있다.


초기화 과정 이해 - ProviderContext  ( 0.4x이후 AuthorizationSeverContext )

@Bean
public ProviderSettings providerSettings(){
    return ProviderSettings.builder().issuer("http://localhost:9000").build();
}

ProviderContextFilter가 주입받아야할 ProviderSettings 는 우리가 빈으로 만들어줘야한다. 기본적으로 제공되지 않음


RegisteredClientRepository / RegisteredClient 이해 및 활용

RegisteredClient 

인가서버에 등록된 클라이언트를 의미며 클라이언트가 authorization_code , client_credentials 와 같은 권한 부여흐름을 시작하려면 먼저 클라이언트 권한 부여 서버에 등록을 해야한다.

 ClientRegistration 은 client에서 사용하는 것이고 RegisteredClient는 인가서버에서 사용하는 클래스이다.

auth server에 등록된 메타정보와 client app의 application.yml 에 등록한 정보가 일치하지 않으면 오류가 나게 된다.
둘이 서로 대응되는 관계이기 때문이다.

 

RegisteredClientRepoistory

새로운 클라이언트를 등록하고 기존 클라이언트를 조회할 수 있는 저장소
InMemoryRegisteredClientRepository , JdbcRegisteredClientRepository가 구현체로 존재한다.

@Bean
public RegisteredClientRepository registeredClientRepository(){

    RegisteredClient registeredClient1= getRegisteredClient("oauth2-client-app1", "{noop}secret1", "read", "write");
    RegisteredClient registeredClient2= getRegisteredClient("oauth2-client-app2", "{noop}secret2", "read", "delete");
    RegisteredClient registeredClient3= getRegisteredClient("oauth2-client-app3", "{noop}secret3", "read", "update");

    return new InMemoryRegisteredClientRepository(Arrays.asList(registeredClient1,registeredClient2,registeredClient3));

}
private RegisteredClient getRegisteredClient(String clientId, String clientSecret, String scope1, String scope2) {
    return RegisteredClient.withId(UUID.randomUUID().toString())
            .clientId(clientId)
            .clientSecret(clientSecret)
            .clientName(clientId)
            .clientIdIssuedAt(Instant.now())
            .clientSecretExpiresAt(Instant.MAX)
            .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
            .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
            .redirectUri("http://127.0.0.1:8081")
            .scope(OidcScopes.OPENID)
            .scope(OidcScopes.PROFILE)
            .scope(OidcScopes.EMAIL)
            .scope(scope1)
            .scope(scope2)
            .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
            .build();
}

다른 곳에서 주입받아서 현재 등록된 client를 확인할 수 있다.


OAuth2AuthorizationService / OAuth2Authorization 이해 및 활용

OAuth2Authorization

리소스 소유자의 역할이 있는 권한 부여 방식(auth_code , resource owner password, client credential[client가 곧 resouceowner이기 떄문])인 경우 클라이언트에 권한 부여 즉 인가 상태를 유지하는 클래스

Spring Security의 OAuth2 Client의 해당 인증 모델은 OAuth2AuthorizedClient와 서로 대응되는 개념이다.

즉 client에서는 OAuth2AuthorizedClient가 인증된 client 즉 자기자신을 의미하는것이고 auth server에서 OAuth2Authorization 그 역할을 대신한다.

권한부여 흐름이 성공적으로 완료되면 OAuth2Authorization이 생성이되고 AccessToken이 저장되며 선택적으로 RefreshToken, IDToken등이 저장된다.

생성된 OAuth2Authorization은 OAuth2AuthorizationService에 의해 메모리나 db에 저장된다.
OAuth2Authorization 에 저장되는 OAuth2Token 타입들은 권한 부여 유형및 Scope에 따라 다르다.

 

OAuth2AuthorizationService

OAuth2AuthorizationService는 새로운 OAuth2Authorization을 저장하고 기존에 있던것을 검색하는 구성요소이다.
InMemoryOAuth2AuthorizationService , JdbcOAuth2AuthorizationService 구현체를 제공한다.

GrantType 종류별로 OAuth2Authorization에 들어가는 token 종류들이 달라진다. 제일 오른쪽사진이 현재 0.31 버전에서는 필드와 일치한다. 이것은 질문에 답변이 오면 확인하자

OAuth2Client(OAuth2AuthorizedClient) 가 요청을 보내면  (예를 들면 auth code와 함께 access token 을 요청) 
auth server에서 매핑되는 OAuth2Authorization 객체의 token 중에 OAuth2AuthorizationCode를 같은지 확인하게 된다.
마치 세션쿠키와의 관계처럼 동작하는 것이다.

auth code가 한번 사용이 되었으면 해당 token에 metadata에 한번 썼으면 invalidated 가 true로 변경되어 해당 auth code로는 access token을 또 못받아오게 한다.

 

 

728x90