使用 spring 启动实现 2 路 SSL
Implementing 2 way SSL using spring boot
我正在创建一些 restful 网络服务并使用 Spring-Boot 创建嵌入式 tomcat 容器。
要求之一是实现 2 路 SSL。我一直在查看 HttpSecurity 对象,并且只能通过 SSL 通道将其 运行 Web 服务获取:-
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("CONFIGURED");
http
// ...
.requiresChannel()
.anyRequest().requiresSecure();
}
我似乎找不到一种方法,使网络服务只能由提供有效客户端证书的应用程序访问。
我只有 SSL 的基本知识,所以即使是正确方向的一般指导也会受到赞赏。
要部署到的服务器将有多种应用程序 - 这是唯一需要使用 2-way SSL 锁定的应用程序。我真正想要的是一种锁定单个应用程序以仅接受客户端证书的方法。
您可以配置 clientAuth=want
,请参阅 Apache Tomcat 8 Configuration Reference:
Set to true
if you want the SSL stack to require a valid certificate chain from the client before accepting a connection. Set to want
if you want the SSL stack to request a client Certificate, but not fail if one isn't presented. A false
value (which is the default) will not require a certificate chain unless the client requests a resource protected by a security constraint that uses CLIENT-CERT
authentication.
然后用Spring Security - X.509 Authentication读取客户端证书:
You can also use SSL with "mutual authentication"; the server will then request a valid certificate from the client as part of the SSL handshake. The server will authenticate 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. Spring Security X.509 module extracts the certificate 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.
和
clientAuth
can also be set to want
if you still want SSL connections to succeed even if the client doesn’t provide a certificate. Clients which don’t present a certificate won’t be able to access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication.
我遇到了类似的问题,想分享我的解决方案。
首先,您需要了解 SSL 证书身份验证将在您的 Web 服务器端处理(参见 dur 的解释,使用“clientAuth=want”设置)。
然后,必须配置您的 Web 应用程序以处理提供的(和允许的)证书,将其映射到用户等。
我与您的细微差别是,我将我的 spring 启动应用程序打包到 WAR 存档中,然后将其部署到现有的 Tomcat 应用程序服务器上。
我的 Tomcat 的 server.xml 配置文件定义了一个 HTTPS 连接器,如下所示:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks"
keystorePass=“some-complex-password“
clientAuth="want" sslProtocol="TLS"
truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks"
truststorePass=“some-other-complex-password” />
避免混淆的小注释:keystoreFile 包含用于 SSL(仅)的 certificate/private 密钥对,而 truststoreFile 包含允许的用于客户端 SSL 身份验证的 CA 证书(请注意,您还可以添加客户端证书直接进入那个信任商店)。
如果您在 spring 引导应用程序中使用嵌入式 tomcat 容器,您应该能够使用以下 属性 在应用程序的属性文件中配置这些设置key/values:
server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks
server.ssl.key-store-password=some-complex-password
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks
server.ssl.trust-store-password=some-other-complex-password
server.ssl.client-auth=want
然后,在我的网络应用程序中,我声明了一个特定的 SSL 配置如下:
@Configuration
@EnableWebSecurity
//In order to use @PreAuthorise() annotations later on...
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter {
@Value("${allowed.user}")
private String ALLOWED_USER;
@Value("${server.ssl.client.regex}")
private String CN_REGEX;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure (final HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication...
.and()
.x509() //... and that x509 authentication is enabled
.subjectPrincipalRegex(CN_REGEX)
.userDetailsService(userDetailsService);
}
@Autowired
//Simplified case, where the application has only one user...
public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
//... whose username is defined in the application's properties.
auth
.inMemoryAuthentication()
.withUser(ALLOWED_USER).password("").roles("SSL_USER");
}
}
然后我需要声明 UserDetailsService bean(例如在我的应用程序的主 class 中):
@Value("${allowed.user}")
private String ALLOWED_USER;
@Bean
public UserDetailsService userDetailsService () {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
if (username.equals(ALLOWED_USER)) {
final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER"));
return user;
}
return null;
}
};
}
就是这样!然后,我可以将 @PreAuthorize(“hasRole(‘ROLE_SSL_USER’)”) 注释添加到我想要保护的方法中。
总结一下,认证流程如下:
- 用户提供 SSL 证书;
- Tomcat 根据其信任库进行验证;
- 自定义 WebSecurityConfigurerAdapter 从证书的 CN 中检索“用户名”;
- 应用程序验证与检索到的用户名关联的用户;
- 在方法级别,如果使用@PreAuthorize("hasRole('SSL_USER')") 注释,应用程序将检查用户是否具有所需的角色。
我正在创建一些 restful 网络服务并使用 Spring-Boot 创建嵌入式 tomcat 容器。
要求之一是实现 2 路 SSL。我一直在查看 HttpSecurity 对象,并且只能通过 SSL 通道将其 运行 Web 服务获取:-
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("CONFIGURED");
http
// ...
.requiresChannel()
.anyRequest().requiresSecure();
}
我似乎找不到一种方法,使网络服务只能由提供有效客户端证书的应用程序访问。
我只有 SSL 的基本知识,所以即使是正确方向的一般指导也会受到赞赏。
要部署到的服务器将有多种应用程序 - 这是唯一需要使用 2-way SSL 锁定的应用程序。我真正想要的是一种锁定单个应用程序以仅接受客户端证书的方法。
您可以配置 clientAuth=want
,请参阅 Apache Tomcat 8 Configuration Reference:
Set to
true
if you want the SSL stack to require a valid certificate chain from the client before accepting a connection. Set towant
if you want the SSL stack to request a client Certificate, but not fail if one isn't presented. Afalse
value (which is the default) will not require a certificate chain unless the client requests a resource protected by a security constraint that usesCLIENT-CERT
authentication.
然后用Spring Security - X.509 Authentication读取客户端证书:
You can also use SSL with "mutual authentication"; the server will then request a valid certificate from the client as part of the SSL handshake. The server will authenticate 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. Spring Security X.509 module extracts the certificate 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.
和
clientAuth
can also be set towant
if you still want SSL connections to succeed even if the client doesn’t provide a certificate. Clients which don’t present a certificate won’t be able to access any objects secured by Spring Security unless you use a non-X.509 authentication mechanism, such as form authentication.
我遇到了类似的问题,想分享我的解决方案。
首先,您需要了解 SSL 证书身份验证将在您的 Web 服务器端处理(参见 dur 的解释,使用“clientAuth=want”设置)。 然后,必须配置您的 Web 应用程序以处理提供的(和允许的)证书,将其映射到用户等。
我与您的细微差别是,我将我的 spring 启动应用程序打包到 WAR 存档中,然后将其部署到现有的 Tomcat 应用程序服务器上。
我的 Tomcat 的 server.xml 配置文件定义了一个 HTTPS 连接器,如下所示:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks"
keystorePass=“some-complex-password“
clientAuth="want" sslProtocol="TLS"
truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks"
truststorePass=“some-other-complex-password” />
避免混淆的小注释:keystoreFile 包含用于 SSL(仅)的 certificate/private 密钥对,而 truststoreFile 包含允许的用于客户端 SSL 身份验证的 CA 证书(请注意,您还可以添加客户端证书直接进入那个信任商店)。
如果您在 spring 引导应用程序中使用嵌入式 tomcat 容器,您应该能够使用以下 属性 在应用程序的属性文件中配置这些设置key/values:
server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks
server.ssl.key-store-password=some-complex-password
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks
server.ssl.trust-store-password=some-other-complex-password
server.ssl.client-auth=want
然后,在我的网络应用程序中,我声明了一个特定的 SSL 配置如下:
@Configuration
@EnableWebSecurity
//In order to use @PreAuthorise() annotations later on...
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter {
@Value("${allowed.user}")
private String ALLOWED_USER;
@Value("${server.ssl.client.regex}")
private String CN_REGEX;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure (final HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication...
.and()
.x509() //... and that x509 authentication is enabled
.subjectPrincipalRegex(CN_REGEX)
.userDetailsService(userDetailsService);
}
@Autowired
//Simplified case, where the application has only one user...
public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
//... whose username is defined in the application's properties.
auth
.inMemoryAuthentication()
.withUser(ALLOWED_USER).password("").roles("SSL_USER");
}
}
然后我需要声明 UserDetailsService bean(例如在我的应用程序的主 class 中):
@Value("${allowed.user}")
private String ALLOWED_USER;
@Bean
public UserDetailsService userDetailsService () {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
if (username.equals(ALLOWED_USER)) {
final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER"));
return user;
}
return null;
}
};
}
就是这样!然后,我可以将 @PreAuthorize(“hasRole(‘ROLE_SSL_USER’)”) 注释添加到我想要保护的方法中。
总结一下,认证流程如下:
- 用户提供 SSL 证书;
- Tomcat 根据其信任库进行验证;
- 自定义 WebSecurityConfigurerAdapter 从证书的 CN 中检索“用户名”;
- 应用程序验证与检索到的用户名关联的用户;
- 在方法级别,如果使用@PreAuthorize("hasRole('SSL_USER')") 注释,应用程序将检查用户是否具有所需的角色。