将Spring Security OAuth2与SAML SSO连接

Luk*_*Luk 6 spring spring-security spring-security-ldap spring-boot spring-security-oauth2

我们有一个基于Spring Boot的微服务架构,在该架构中,我们有多个相互对话的微服务以及一个连接到不同微服务的Javascript UI。

由于这是一个内部应用程序,并且我们需要将它们连接到SAML2端点以提供SSO,因此将所有这些连接在一起让我有些头疼。理想情况下,微服务在其自身(JWT)和UI之间使用oAuth2,但是用户身份验证是通过SAML2完成的

我要实现以下目标:

  • UI客户端使用JWT与微服务对话
  • 微服务也使用JWT进行通信。当用户向微服务发起请求并且该微服务需要来自另一个微服务的更多数据时,它将使用用户的JWT令牌(这应该很容易做到)。
  • 具有一个中央身份验证微服务,该服务负责生成新令牌并针对SAML端点对用户进行身份验证。
  • 在身份验证微服务中存储一些SAML详细信息(例如,角色)

所以我尝试了很多不同的东西。我能说的是:

我想我最麻烦的是oauth2资源服务器和SAML服务的连接点。

关于SAML,我有以下可以正常工作的方法:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Value("${security.saml2.metadata-url}")
    String metadataUrl;
    @Value("${server.ssl.key-alias}")
    String keyAlias;
    @Value("${server.ssl.key-store-password}")
    String password;
    @Value("${server.port}")
    String port;
    @Value("${server.ssl.key-store}")
    String keyStoreFilePath;

    @Autowired
    SAMLUserDetailsService samlUserDetailsService;


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/oauth/**").authenticated()
                .and().exceptionHandling()

                .and()
                .authorizeRequests()
                .antMatchers("/saml*").permitAll()
                .anyRequest().authenticated()
                .and()
                .apply(saml()).userDetailsService(samlUserDetailsService)
                .serviceProvider()
                .keyStore()
                .storeFilePath("saml/keystore.jks")
                .password(this.password)
                .keyname(this.keyAlias)
                .keyPassword(this.password)
                .and()
                .protocol("https")
                .hostname(String.format("%s:%s", "localhost", this.port))
                .basePath("/")
                .and()
                .identityProvider()
                .metadataFilePath(this.metadataUrl);

    }
}
Run Code Online (Sandbox Code Playgroud)

而且效果很好。因此,当我命中一个受保护的端点时,我将被重定向并可以通过saml登录。然后在samlUserDetailsS​​ervice中获取用户详细信息。

关于oauth我有这样的事情:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                .tokenEnhancer(accessTokenConverter())
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }


    @Bean
    JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("ABC"); //needs to be changed using certificates
        return converter;
    }


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()
                .withClient("acme")
                .secret("acmesecret")
                .authorizedGrantTypes("refresh_token", "authorization_code")
                .autoApprove(true)
                .scopes("webapp")
                .accessTokenValiditySeconds(60)
                .refreshTokenValiditySeconds(3600);
    }
}
Run Code Online (Sandbox Code Playgroud)

这部分也可以与其他具有@EnableResourceServer的micorservices一起使用

据我了解的OAuth部分,ClientDetailsS​​erviceConfigurer只是配置客户端应用程序(在我的情况下为其他微服务),对此我应该使用client_credentials类的授予(但不确定)。但是我不清楚如何连接SAML部分...

作为替代方案,我正在考虑将其拆分。创建一个微服务,它是一个OAuth授权服务,另一个是执行SAML位的服务。在这种情况下,如果用户通过了身份验证,则SAML微服务将连接到SAML并提供类似/ me的终结点。然后,OAuth授权服务将使用SAML微服务来检查用户是否在那里进行了身份验证,并且在这种情况下提供令牌。对于刷新令牌,我也将这样做。据我了解,我将在公共void configure(ClientDetailsS​​erviceConfigurer客户端)throws Exception {}方法中实现这种逻辑。

如果有更好的方法,请告诉我!