title: Connecting Spring Security OAuth2 with SAML SSO
body: <p>We’re having a microservices architecture based on spring boot where we have multiple microservices talking to each other and also a Javascript UI that connects to the different microservices.</p>
  
  <p>Since this is an internal application and we have the requirement to connect them to our SAML2 endpoint to provide SSO, I’m getting a bit of a headache to connect all of this together. Ideally the microservices use oAuth2 between themselves (JWT) and the UI, but User Authentication is done through SAML2</p>
  
  <p>The following I want to achieve with this:</p>
  
  <ul>
  <li>UI Clients talk to the microservices by using JWT</li>
  <li>Microservices use JWT as well to talk to each other. When a user initiates a request to a microservice and that microservice needs more data from another one, it uses the users JWT token (this should be fairly easy to do).</li>
  <li>Having one central authentication microservice which is responsible for generating new tokens and authenticate the user against the SAML endpoint.</li>
  <li>Storing some SAML details (e.g. Roles) in the authentication microservice</li>
  </ul>
  
  <p>So I have tried many different things. What I can say is the following:</p>
  
  <ul>
  <li>Using OAuth between microservices and JWT works fine and is not really an issue (e.g. this link is a nice tutorial to set this up <a href="http://www.swisspush.org/security/2016/10/17/oauth2-in-depth-introduction-for-enterprises" rel="noreferrer">http://www.swisspush.org/security/2016/10/17/oauth2-in-depth-introduction-for-enterprises</a> )</li>
  <li>Using SAML with spring-security-saml-dsl is also straight forward and works pretty well</li>
  <li>I have implemented JWT in combination of spring-security-saml-dsl and that works also well (similar to this: <a href="https://www.sylvainlemoine.com/2016/06/06/spring-saml2.0-websso-and-jwt-for-mobile-api/" rel="noreferrer">https://www.sylvainlemoine.com/2016/06/06/spring-saml2.0-websso-and-jwt-for-mobile-api/</a> except that I use spring-security-saml-dsl) which I don’t like because it uses to much custom code with all the filters, etc. but would be a way to go.</li>
  </ul>
  
  <p>I guess where I struggle with is the connection points of oauth2 Resource Server and the SAML services.</p>
  
  <p>Regarding SAML I have the following that works fine:</p>
  
  <pre><code>@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);
  
      }
  }
  </code></pre>
  
  <p>and that works fine. so when I hit a protected endpoint I will get redirected and can login through saml. I get the userdetails then in the samlUserDetailsService.</p>
  
  <p>Regarding oauth I have something like this:</p>
  
  <pre><code>@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);
      }
  }
  </code></pre>
  
  <p>This part also works fine with other micorservices where I have @EnableResourceServer</p>
  
  <p>As far as I understand the OAuth part, the ClientDetailsServiceConfigurer just configures the client applications (in my case the other microservices) and I should use client_credentials kind of grant for this (but aren't sure). But how I would wire in the SAML part is not clear to me... </p>
  
  <p>As an alternative I'm thinking about splitting this up. Creating a microservice that is an OAuth Authorization Service and another one that does the SAML bit. In this scenario, the SAML Microservice would connect to SAML and provide an endpoint like /me if the user is authenticated. The OAuth Authorization Service would then use the SAML Microservice to check if a user is Authenticated there and provide a token if that is the case. I would also do the same regarding refresh tokens.
  As far as I understand this, I would implement this kind of logic in the 
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {} method.</p>
  
  <p>If there's a better approach, let me know!</p>