X.509 認証

X.509 証明書認証の最も一般的な使用箇所は、SSL を使用する場合、最も一般的にはブラウザーから HTTPS を使用する場合に、サーバーの ID を確認することです。ブラウザーは、サーバーによって提示された証明書が、サーバーが保持している信頼できる認証局のリストの 1 つによって発行された(デジタル署名された)ことを自動的にチェックします。

SSL を「相互認証」と組み合わせて使用することもできます。サーバーは SSL ハンドシェイクの一環として、クライアントに有効な証明書をリクエストします。サーバーは、クライアントの証明書が適切な認証局によって署名されているかどうかを確認し、クライアントを認証します。有効な証明書が提供されている場合は、アプリケーションのサーブレット API を通じて取得できます。たとえば、Tomcat を使用している場合は、TomcatSSL 命令 [Apache] (英語) を参照してください。Spring Security で試す前に、この手順を理解できるようにしておきましょう。

Spring Security X.509 モジュールは、フィルターを使用して証明書を抽出します。証明書をアプリケーションユーザーにマッピングし、そのユーザーに付与された権限セットを読み込み、標準の Spring Security インフラストラクチャで使用します。具体的には、HttpSecurity DSL を使用する場合は、少なくとも FACTOR_X509 権限が含まれます。

Web アプリケーションへの X.509 認証の追加

リアクティブ X.509 認証と同様に、サーブレット x509 認証フィルターを使用すると、クライアントによって提供された証明書から認証トークンを抽出できます。

次の例は、リアクティブ x509 セキュリティ構成を示しています。

  • Java

  • Kotlin

  • XML

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	http
		.x509(Customizer.withDefaults())
		.authorizeHttpRequests((exchanges) -> exchanges
			.anyRequest().authenticated()
		);
	return http.build();
}
@Bean
fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? {
    http {
        authorizeHttpRequests {
            authorize(anyRequest, authenticated)
        }
        x509 { }
    }
    return http.build()
}
<http>
    <intercept-url pattern="/**" access="authenticated"/>
    <x509 />
</http>

上記の構成では、principalExtractor も authenticationManager も指定されていない場合、デフォルトが使用されます。デフォルトのプリンシパルエクストラクターは SubjectX500PrincipalExtractor であり、クライアントから提供された証明書から CN(共通名)フィールドを抽出します。デフォルトの認証マネージャーは ReactivePreAuthenticatedAuthenticationManager で、ユーザーアカウントの検証を実行し、principalExtractor によって抽出された名前のユーザーアカウントが存在し、ロック、無効化、有効期限が切れていないことを確認します。

次の例は、これらのデフォルトをオーバーライドする方法を示しています。

  • Java

  • Kotlin

  • XML

@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
	SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor();
	principalExtractor.setExtractPrincipalNameFromEmail(true);


	http
		.x509((x509) -> x509
			.x509PrincipalExtractor(principalExtractor)
		)
		.authorizeHttpRequests((exchanges) -> exchanges
			.anyRequest().authenticated()
		);
	return http.build();
}
@Bean
fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? {
    val principalExtractor = SubjectX500PrincipalExtractor()
    principalExtractor.setExtractPrincipalNameFromEmail(true)

    http {
        authorizeHttpRequests {
            authorize(anyRequest, authenticated)
        }
        x509 {
            x509PrincipalExtractor = principalExtractor
        }
    }
    return http.build()
}
<http>
    <intercept-url pattern="/**" access="authenticated"/>
    <x509 principal-extractor-ref="principalExtractor"/>
</http>
<b:bean id="principalExtractor"
    class="org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor"
    p:extractPrincipalNameFromEmail="true"/>

前の例では、ユーザー名は CN ではなくクライアント証明書の emailAddress フィールドから抽出され、アカウント検索ではカスタム ReactiveAuthenticationManager インスタンスが使用されます。

相互 TLS を使用して X.509 認証を有効にするように Netty および WebClient または curl コマンド行ツールを構成する例については、github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509 (英語) を参照してください。

Tomcat で SSL をセットアップする

Spring Security サンプルリポジトリ [GitHub] (英語) には、事前に生成された証明書がいくつかあります。独自に生成したくない場合は、これらを使用してテスト用の SSL を有効にすることができます。server.jks ファイルには、サーバー証明書、秘密鍵、発行オーソリティの証明書が含まれています。サンプルアプリケーションのユーザー用のクライアント証明書ファイルもいくつかあります。これらをブラウザーにインストールして、SSL クライアント認証を有効にすることができます。

SSL をサポートする Tomcat を実行するには、server.jks ファイルを tomcat conf ディレクトリにドロップし、次のコネクターを server.xml ファイルに追加します。

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
			clientAuth="true" sslProtocol="TLS"
			keystoreFile="${catalina.home}/conf/server.jks"
			keystoreType="JKS" keystorePass="password"
			truststoreFile="${catalina.home}/conf/server.jks"
			truststoreType="JKS" truststorePass="password"
/>

クライアントが証明書を提供しなくても SSL 接続を成功させたい場合は、clientAuth を want に設定することもできます。証明書を提示しないクライアントは、フォーム認証などの非 X.509 認証メカニズムを使用しない限り、Spring Security によって保護されているオブジェクトにアクセスできません。