This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Security 6.5.0! |
X.509 Authentication
The most common use of X.509 certificate authentication is in verifying the identity of a server when using SSL, most commonly when using HTTPS from a browser. The browser automatically checks that the certificate presented by a server has been issued (digitally signed) by one of a list of trusted certificate authorities that it maintains.
You can also use SSL with “mutual authentication”. The server then requests a valid certificate from the client as part of the SSL handshake. The server authenticates the client by checking that its certificate is signed by an acceptable authority. If a valid certificate has been provided, it can be obtained through the servlet API in an application. For example, if you use Tomcat, you should read the Tomcat SSL instructions. You should get this working before trying it out with Spring Security.
The Spring Security X.509 module extracts the certificate by using a filter. It maps the certificate to an application user and loads that user’s set of granted authorities for use with the standard Spring Security infrastructure.
Adding X.509 Authentication to Your Web Application
Similar to Reactive X.509 authentication, the servlet x509 authentication filter allows extracting an authentication token from a certificate provided by a client.
The following example shows a reactive x509 security configuration:
-
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>
In the preceding configuration, when neither principalExtractor
nor authenticationManager
is provided, defaults are used.
The default principal extractor is SubjectX500PrincipalExtractor
, which extracts the CN (common name) field from a certificate provided by a client.
The default authentication manager is ReactivePreAuthenticatedAuthenticationManager
, which performs user account validation, checking that a user account with a name extracted by principalExtractor
exists and that it is not locked, disabled, or expired.
The following example demonstrates how these defaults can be overridden:
-
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"/>
In the previous example, a username is extracted from the emailAddress
field of a client certificate instead of CN, and account lookup uses a custom ReactiveAuthenticationManager
instance.
For an example of configuring Netty and WebClient
or curl
command-line tool to use mutual TLS and enable X.509 authentication, see github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509.
Setting up SSL in Tomcat
There are some pre-generated certificates in the Spring Security Samples repository.
You can use these to enable SSL for testing if you do not want to generate your own.
The server.jks
file contains the server certificate, the private key, and the issuing authority certificate.
There are also some client certificate files for the users from the sample applications.
You can install these in your browser to enable SSL client authentication.
To run tomcat with SSL support, drop the server.jks
file into the tomcat conf
directory and add the following connector to the server.xml
file:
<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"
/>
clientAuth
can also be set to want
if you still want SSL connections to succeed even if the client does not provide a certificate.
Clients that do not present a certificate cannot access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication.