構成モデル
デフォルトの構成
OAuth2AuthorizationServerConfiguration
は、OAuth2 認可サーバーの最小限のデフォルト構成を提供する @Configuration
です。
OAuth2AuthorizationServerConfiguration
は OAuth2AuthorizationServerConfigurer
を使用してデフォルト設定を適用し、OAuth2 認証サーバーをサポートするすべてのインフラストラクチャコンポーネントで構成される SecurityFilterChain
@Bean
を登録します。
OAuth2 認証サーバー SecurityFilterChain
@Bean
は、次の既定のプロトコルエンドポイントで構成されます。
JWK Set エンドポイントは、JWKSource<SecurityContext> @Bean が登録されている場合にのみ構成されます。 |
次の例は、OAuth2AuthorizationServerConfiguration
を使用して最小限のデフォルト設定を適用する方法を示しています。
@Configuration
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {
@Bean
public RegisteredClientRepository registeredClientRepository() {
List<RegisteredClient> registrations = ...
return new InMemoryRegisteredClientRepository(registrations);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = ...
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
}
authorization_code グラント [IETF] (英語) では、リソース所有者が認証される必要があります。デフォルトの OAuth2 セキュリティ構成に加えて、ユーザー認証メカニズムを構成する必要があります。 |
OpenID Connect 1.0 (英語) は、デフォルト設定では無効になっています。次の例は、OidcConfigurer
を初期化して OpenID Connect 1.0 を有効にする方法を示しています。
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.oidc(Customizer.withDefaults()) // Initialize `OidcConfigurer`
);
return http.build();
}
デフォルトのプロトコルエンドポイントに加えて、OAuth2 認証サーバー SecurityFilterChain
@Bean
は、次の OpenID Connect 1.0 プロトコルエンドポイントで構成されます。
多くの デプロイは動的クライアント登録を必要としないため、OpenID Connect 1.0 クライアント登録エンドポイントはデフォルトで無効になっています。 |
OAuth2AuthorizationServerConfiguration.jwtDecoder(JWKSource<SecurityContext>) は、OpenID Connect 1.0 UserInfo エンドポイントおよび OpenID Connect 1.0 クライアント登録エンドポイントの REQUIRED である JwtDecoder @Bean を登録するために使用できる便利な (static ) ユーティリティメソッドです。 |
次の例は、JwtDecoder
@Bean
を登録する方法を示しています。
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
OAuth2AuthorizationServerConfiguration
の主な目的は、OAuth2 認可サーバーに最小限の既定の構成を適用するための便利なメソッドを提供することです。ただし、ほとんどの場合、構成のカスタマイズが必要になります。
構成のカスタマイズ
OAuth2AuthorizationServerConfigurer
は、OAuth2 認証サーバーのセキュリティ構成を完全にカスタマイズする機能を提供します。これにより、使用するコアコンポーネント (たとえば、RegisteredClientRepository
、OAuth2AuthorizationService
、OAuth2TokenGenerator
など) を指定できます。さらに、プロトコルエンドポイント ( 認可エンドポイント、デバイス認可エンドポイント、デバイス検証エンドポイント、トークンエンドポイント、トークンイントロスペクションエンドポイントなど) のリクエスト処理ロジックをカスタマイズできます。
OAuth2AuthorizationServerConfigurer
は、次の構成オプションを提供します。
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.registeredClientRepository(registeredClientRepository) (1)
.authorizationService(authorizationService) (2)
.authorizationConsentService(authorizationConsentService) (3)
.authorizationServerSettings(authorizationServerSettings) (4)
.tokenGenerator(tokenGenerator) (5)
.clientAuthentication(clientAuthentication -> { }) (6)
.authorizationEndpoint(authorizationEndpoint -> { }) (7)
.deviceAuthorizationEndpoint(deviceAuthorizationEndpoint -> { }) (8)
.deviceVerificationEndpoint(deviceVerificationEndpoint -> { }) (9)
.tokenEndpoint(tokenEndpoint -> { }) (10)
.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint -> { }) (11)
.tokenRevocationEndpoint(tokenRevocationEndpoint -> { }) (12)
.authorizationServerMetadataEndpoint(authorizationServerMetadataEndpoint -> { }) (13)
.oidc(oidc -> oidc
.providerConfigurationEndpoint(providerConfigurationEndpoint -> { }) (14)
.logoutEndpoint(logoutEndpoint -> { }) (15)
.userInfoEndpoint(userInfoEndpoint -> { }) (16)
.clientRegistrationEndpoint(clientRegistrationEndpoint -> { }) (17)
)
);
return http.build();
}
1 | registeredClientRepository() : 新規および既存のクライアントを管理するための RegisteredClientRepository ( REQUIRED )。 |
2 | authorizationService() : 新規および既存の認可を管理するための OAuth2AuthorizationService 。 |
3 | authorizationConsentService() : 新規および既存の認可同意を管理するための OAuth2AuthorizationConsentService 。 |
4 | authorizationServerSettings() : OAuth2 認証サーバーの構成設定をカスタマイズするための AuthorizationServerSettings ( REQUIRED )。 |
5 | tokenGenerator() : OAuth2 認証サーバーでサポートされているトークンを生成するための OAuth2TokenGenerator 。 |
6 | clientAuthentication() : OAuth2 クライアント認証の設定ツール。 |
7 | authorizationEndpoint() : OAuth2 認証エンドポイントの設定ツール。 |
8 | deviceAuthorizationEndpoint() : OAuth2 デバイス認証エンドポイントの設定ツール。 |
9 | deviceVerificationEndpoint() : OAuth2 デバイス検証エンドポイントの設定ツール。 |
10 | tokenEndpoint() : OAuth2 トークンエンドポイントの設定ツール。 |
11 | tokenIntrospectionEndpoint() : OAuth2 トークンイントロスペクションエンドポイントの設定ツール。 |
12 | tokenRevocationEndpoint() : OAuth2 トークン失効エンドポイントの設定ツール。 |
13 | authorizationServerMetadataEndpoint() : OAuth2 認証サーバーメタデータエンドポイントの設定ツール。 |
14 | providerConfigurationEndpoint() : OpenID Connect 1.0 プロバイダー構成エンドポイントの設定ツール。 |
15 | logoutEndpoint() : OpenID Connect 1.0 ログアウトエンドポイントの設定ツール。 |
16 | userInfoEndpoint() : OpenID Connect 1.0 UserInfo エンドポイントの設定ツール。 |
17 | clientRegistrationEndpoint() : OpenID Connect 1.0 クライアント登録エンドポイントの設定ツール。 |
認可サーバー設定の構成
AuthorizationServerSettings
には、OAuth2 認証サーバーの構成設定が含まれています。これは、プロトコルエンドポイントの URI
と発行者識別子 [IETF] (英語) を指定します。プロトコルエンドポイントのデフォルトの URI
は次のとおりです。
public final class AuthorizationServerSettings extends AbstractSettings {
...
public static Builder builder() {
return new Builder()
.authorizationEndpoint("/oauth2/authorize")
.deviceAuthorizationEndpoint("/oauth2/device_authorization")
.deviceVerificationEndpoint("/oauth2/device_verification")
.tokenEndpoint("/oauth2/token")
.tokenIntrospectionEndpoint("/oauth2/introspect")
.tokenRevocationEndpoint("/oauth2/revoke")
.jwkSetEndpoint("/oauth2/jwks")
.oidcLogoutEndpoint("/connect/logout")
.oidcUserInfoEndpoint("/userinfo")
.oidcClientRegistrationEndpoint("/connect/register");
}
...
}
AuthorizationServerSettings は REQUIRED コンポーネントです。 |
@Import(OAuth2AuthorizationServerConfiguration.class) は、まだ提供されていない場合、AuthorizationServerSettings @Bean を自動的に登録します。 |
次の例は、構成設定をカスタマイズして AuthorizationServerSettings
@Bean
を登録する方法を示しています。
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("https://example.com")
.authorizationEndpoint("/oauth2/v1/authorize")
.deviceAuthorizationEndpoint("/oauth2/v1/device_authorization")
.deviceVerificationEndpoint("/oauth2/v1/device_verification")
.tokenEndpoint("/oauth2/v1/token")
.tokenIntrospectionEndpoint("/oauth2/v1/introspect")
.tokenRevocationEndpoint("/oauth2/v1/revoke")
.jwkSetEndpoint("/oauth2/v1/jwks")
.oidcLogoutEndpoint("/connect/v1/logout")
.oidcUserInfoEndpoint("/connect/v1/userinfo")
.oidcClientRegistrationEndpoint("/connect/v1/register")
.build();
}
AuthorizationServerContext
は、Authorization Server ランタイム環境の情報を保持するコンテキストオブジェクトです。AuthorizationServerSettings
と「現在の」発行者 ID へのアクセスを提供します。
発行者識別子が AuthorizationServerSettings.builder().issuer(String) で構成されていない場合、現在のリクエストから解決されます。 |
AuthorizationServerContext は AuthorizationServerContextHolder を介してアクセスでき、ThreadLocal を使用して現在のリクエストスレッドに関連付けられます。 |
クライアント認証の構成
OAuth2ClientAuthenticationConfigurer
は、OAuth2 クライアント認証 [IETF] (英語) をカスタマイズする機能を提供します。クライアント認証リクエストの前処理、メイン処理、後処理ロジックをカスタマイズできる拡張ポイントを定義します。
OAuth2ClientAuthenticationConfigurer
は、次の構成オプションを提供します。
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationConverter(authenticationConverter) (1)
.authenticationConverters(authenticationConvertersConsumer) (2)
.authenticationProvider(authenticationProvider) (3)
.authenticationProviders(authenticationProvidersConsumer) (4)
.authenticationSuccessHandler(authenticationSuccessHandler) (5)
.errorResponseHandler(errorResponseHandler) (6)
)
);
return http.build();
}
1 | authenticationConverter() : クライアント資格証明を HttpServletRequest から OAuth2ClientAuthenticationToken のインスタンスに抽出しようとするときに使用される AuthenticationConverter ( プリプロセッサー ) を追加します。 |
2 | authenticationConverters() : デフォルトの List および (オプションで) 追加された AuthenticationConverter へのアクセスを提供する Consumer を設定して、特定の AuthenticationConverter を追加、削除、カスタマイズする機能を許可します。 |
3 | authenticationProvider() : OAuth2ClientAuthenticationToken の認証に使用される AuthenticationProvider ( メインプロセッサー ) を追加します。 |
4 | authenticationProviders() : デフォルトの List および (オプションで) 追加された AuthenticationProvider へのアクセスを提供する Consumer を設定して、特定の AuthenticationProvider を追加、削除、カスタマイズする機能を許可します。 |
5 | authenticationSuccessHandler() : クライアント認証の成功を処理し、OAuth2ClientAuthenticationToken を SecurityContext に関連付けるために使用される AuthenticationSuccessHandler ( ポストプロセッサー )。 |
6 | errorResponseHandler() : 失敗したクライアント認証を処理し、OAuth2Error レスポンス [IETF] (英語) を返すために使用される AuthenticationFailureHandler ( ポストプロセッサー )。 |
OAuth2ClientAuthenticationConfigurer
は OAuth2ClientAuthenticationFilter
を構成し、それを OAuth2 認証サーバー SecurityFilterChain
@Bean
に登録します。OAuth2ClientAuthenticationFilter
は、クライアント認証リクエストを処理する Filter
です。
デフォルトでは、クライアント認証は OAuth2 トークンエンドポイント、OAuth2 トークンイントロスペクションエンドポイント、OAuth2 トークン失効エンドポイントに必要です。サポートされているクライアント認証方式は client_secret_basic
、client_secret_post
、private_key_jwt
、client_secret_jwt
、tls_client_auth
、self_signed_tls_client_auth
、none
(パブリッククライアント) です。
OAuth2ClientAuthenticationFilter
は、次のデフォルトで構成されています。
AuthenticationConverter
—JwtClientAssertionAuthenticationConverter
、X509ClientCertificateAuthenticationConverter
、ClientSecretBasicAuthenticationConverter
、ClientSecretPostAuthenticationConverter
、PublicClientAuthenticationConverter
で構成されるDelegatingAuthenticationConverter
。AuthenticationManager
—JwtClientAssertionAuthenticationProvider
、X509ClientCertificateAuthenticationProvider
、ClientSecretAuthenticationProvider
、PublicClientAuthenticationProvider
で構成されるAuthenticationManager
。AuthenticationSuccessHandler
— 「認証済み」OAuth2ClientAuthenticationToken
(現在のAuthentication
) をSecurityContext
に関連付ける内部実装。AuthenticationFailureHandler
—OAuth2AuthenticationException
に関連付けられたOAuth2Error
を使用して OAuth2 エラーレスポンスを返す内部実装。
Jwt クライアントアサーション検証のカスタマイズ
JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY
は、指定された RegisteredClient
に OAuth2TokenValidator<Jwt>
を提供するデフォルトファクトリであり、Jwt
クライアントアサーションの iss
、sub
、aud
、exp
、nbf
クレームを検証するために使用されます。
JwtClientAssertionDecoderFactory
は、型 Function<RegisteredClient, OAuth2TokenValidator<Jwt>>
のカスタムファクトリを setJwtValidatorFactory()
に提供することにより、デフォルトの Jwt
クライアントアサーション検証をオーバーライドする機能を提供します。
JwtClientAssertionDecoderFactory は、指定された RegisteredClient に JwtDecoder を提供する JwtClientAssertionAuthenticationProvider によって使用されるデフォルトの JwtDecoderFactory であり、OAuth2 クライアント認証中に Jwt ベアラートークンを認証するために使用されます。 |
JwtClientAssertionDecoderFactory
をカスタマイズする一般的な使用例は、Jwt
クライアントアサーションで追加のクレームを検証することです。
次の例は、Jwt
クライアントアサーションの追加クレームを検証するカスタマイズされた JwtClientAssertionDecoderFactory
を使用して JwtClientAssertionAuthenticationProvider
を構成する方法を示しています。
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationProviders(configureJwtClientAssertionValidator())
)
);
return http.build();
}
private Consumer<List<AuthenticationProvider>> configureJwtClientAssertionValidator() {
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof JwtClientAssertionAuthenticationProvider) {
// Customize JwtClientAssertionDecoderFactory
JwtClientAssertionDecoderFactory jwtDecoderFactory = new JwtClientAssertionDecoderFactory();
Function<RegisteredClient, OAuth2TokenValidator<Jwt>> jwtValidatorFactory = (registeredClient) ->
new DelegatingOAuth2TokenValidator<>(
// Use default validators
JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY.apply(registeredClient),
// Add custom validator
new JwtClaimValidator<>("claim", "value"::equals));
jwtDecoderFactory.setJwtValidatorFactory(jwtValidatorFactory);
((JwtClientAssertionAuthenticationProvider) authenticationProvider)
.setJwtDecoderFactory(jwtDecoderFactory);
}
});
}
相互 TLS クライアント認証のカスタマイズ
X509ClientCertificateAuthenticationProvider
は、OAuth2 クライアント認証中に ClientAuthenticationMethod.TLS_CLIENT_AUTH
または ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH
メソッドが使用されるときに受信されるクライアント X509Certificate
チェーンを認証するために使用されます。また、TLS ハンドシェイクが正常に完了した後にクライアント X509Certificate
の内容を検証するために使用される「証明書検証子」で構成されます。
PKI 相互 TLS 方式
PKI Mutual-TLS (ClientAuthenticationMethod.TLS_CLIENT_AUTH
) 方式の場合、証明書検証のデフォルトの実装は、クライアントのサブジェクト識別名 X509Certificate
を設定 RegisteredClient.getClientSettings.getX509CertificateSubjectDN()
と照合して検証します。
クライアント X509Certificate
の別の属性、たとえば サブジェクト代替名 (SAN) エントリを検証する必要がある場合、次の例は、証明書検証のカスタム実装を使用して X509ClientCertificateAuthenticationProvider
を構成する方法を示しています。
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationProviders(configureX509ClientCertificateVerifier())
)
);
return http.build();
}
private Consumer<List<AuthenticationProvider>> configureX509ClientCertificateVerifier() {
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof X509ClientCertificateAuthenticationProvider) {
Consumer<OAuth2ClientAuthenticationContext> certificateVerifier = (clientAuthenticationContext) -> {
OAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationContext.getAuthentication();
RegisteredClient registeredClient = clientAuthenticationContext.getRegisteredClient();
X509Certificate[] clientCertificateChain = (X509Certificate[]) clientAuthentication.getCredentials();
X509Certificate clientCertificate = clientCertificateChain[0];
// TODO Verify Subject Alternative Name (SAN) entry
};
((X509ClientCertificateAuthenticationProvider) authenticationProvider)
.setCertificateVerifier(certificateVerifier);
}
});
}
自己署名証明書相互 TLS 方式
自己署名証明書相互 TLS (ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH
) 方式の場合、証明書検証のデフォルトの実装は、設定 RegisteredClient.getClientSettings.getJwkSetUrl()
を使用してクライアントの JSON Web キーセットを取得し、TLS ハンドシェイク中に受信したクライアント X509Certificate
と一致するものを見つけようとします。
RegisteredClient.getClientSettings.getJwkSetUrl() 設定は、JSON Web キー (JWK) セットを介してクライアントの証明書を取得するために使用されます。証明書は、セット内の個々の JWK の x5c パラメーターで表されます。 |
クライアント証明書にバインドされたアクセストークン
トークンエンドポイントで Mutual-TLS クライアント認証を使用すると、認可サーバーは発行されたアクセストークンをクライアントの X509Certificate
にバインドできます。バインドは、クライアントの X509Certificate
の SHA-256 サムプリントを計算し、そのサムプリントをアクセストークンに関連付けることによって実現されます。例: JWT アクセストークンには、最上位の cnf
(確認方法) クレーム内に、X509Certificate
サムプリントを含む x5t#S256
クレームが含まれます。
アクセストークンをクライアントの X509Certificate
にバインドすると、保護されたリソースへのアクセス中に所有証明メカニズムを実装できるようになります。例: 保護されたリソースは、相互 TLS 認証中に使用されるクライアントの X509Certificate
を取得し、証明書の拇印がアクセストークンに関連付けられた x5t#S256
クレームと一致することを確認します。
次の例は、クライアントの証明書にバインドされたアクセストークンを有効にする方法を示しています。
RegisteredClient mtlsClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("mtls-client")
.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("scope-a")
.clientSettings(
ClientSettings.builder()
.x509CertificateSubjectDN("CN=mtls-client,OU=Spring Samples,O=Spring,C=US")
.build()
)
.tokenSettings(
TokenSettings.builder()
.x509CertificateBoundAccessTokens(true)
.build()
)
.build();