使用spring boot实现2路SSL

我正在创建一些宁静的Web服务,并使用Spring-Boot创建一个嵌入式tomcat容器。

其中一个要求是实现双向SSL。 我一直在查看HttpSecurity对象,并且可以使用它来仅通过SSL通道运行web服务: –

@Override protected void configure(HttpSecurity http) throws Exception { System.out.println("CONFIGURED"); http // ... .requiresChannel() .anyRequest().requiresSecure(); } 

我似乎无法找到的方法是只允许提供有效客户端证书的应用程序访问Web服务。

我只有SSL的基本知识,所以即使是正确方向的一般指针也会受到赞赏。

正在部署的服务器将具有混合的应用程序 – 这是唯一需要使用双向SSL锁定的应用程序。 我真正想要的是一种锁定单个应用程序只接受客户端证书的方法。

您可以配置clientAuth=want ,请参阅Apache Tomcat 8配置参考 :

如果希望SSL堆栈在接受连接之前需要来自客户端的有效证书链,则设置为true 。 设置为want SSL堆栈请求客户端证书,但如果没有呈现则不会失败。 除非客户端请求受使用CLIENT-CERT身份validation的安全约束保护的资源,否则false值(默认值)将不需要证书链。

然后使用Spring Security – X.509身份validation读取客户端证书:

您还可以使用SSL与“相互身份validation”; 然后,服务器将从客户端请求有效证书,作为SSL握手的一部分。 服务器将通过检查其证书是否由可接受的权限签名来validation客户端。 如果提供了有效证书,则可以通过应用程序中的servlet API获取该证书。 Spring Security X.509模块使用filter提取证书。 它将证书映射到应用程序用户,并加载该用户的授权权限集,以便与标准Spring Security基础结构一起使用。

如果您仍希望SSL连接成功,即使客户端未提供证书,也可以将clientAuth设置为want 。 除非您使用非X.509身份validation机制(如表单身份validation),否则不提供证书的客户端将无法访问由Spring Security担保的任何对象。

我遇到了类似的问题,并认为我会分享我带来的解决方案。

首先,您需要了解SSL证书身份validation将在您的Web服务器端处理(cfr.dur的解释,使用“clientAuth = want”设置)。 然后,必须配置您的Web应用程序,以便处理提供的(和允许的)证书,将其映射到用户等。

我与你的细微差别在于我将我的spring启动应用程序打包到WAR存档中,然后将其部署在现有的Tomcat应用程序服务器上。

我的Tomcat的server.xml配置文件定义了HTTPS连接器,如下所示:

  

小注释以避免混淆:keystoreFile包含用于SSL(仅)的证书/私钥对,而truststoreFile包含用于客户端SSL身份validation的允许CA证书(请注意,您还可以将客户端证书直接添加到该信任存储中) 。

如果您在Spring Boot应用程序中使用嵌入式tomcat容器,则应该能够使用以下属性键/值在应用程序的属性文件中配置这些设置:

 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 

然后,在我的Web应用程序上,我声明了一个特定的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"); } } 

然后我需要声明UserDetailsS​​ervice bean(例如在我的Application的主类中):

 @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’)”)注释添加到我想要保护的方法中。

总结一下,认证流程如下:

  1. 用户提供SSL证书;
  2. Tomcat对其信任存储进行validation;
  3. 自定义WebSecurityConfigurerAdapter从证书的CN中检索“用户名”;
  4. 应用程序validation与检索到的用户名关联的用户;
  5. 在方法级别,如果使用@PreAuthorize(“hasRole(’SSL_USER’)”)进行批注,则应用程序将检查用户是否具有所需角色。