title: Spring Oauth 2 SSO, Zuul and OpenAM integration
body: <p><strong>Introduction, Requirements:</strong></p>
  
  <p>right now i am writing a Single Page Application with AngularJS which talks to a Spring REST API. For security purposes I would like to setup a reverse proxy with zuul which proxies every request to the API and verifies that the user is authenticated. Also, if the user is not authenticated he should be redirected to an OpenAM instance (functioning as OAuth 2 Authorization Server). If the user is authenticated the request should be forwarded to the API with a Json Web Token (JWT) in the Header, containing at least the LDAP groups of the User.</p>
  
  <p>In short I would like to have something like a API Gateway similar to the solution in this tutorial: <a href="https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v" rel="nofollow">https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v</a></p>
  
  <p><strong>Status quo</strong></p>
  
  <p>I setup the Spring Cloud Security and Zuul with the following config:</p>
  
  <pre><code>server:
    port: 9000
  spring:
    oauth2:
      sso:
        home:
          secure: false
          path: /,/**/*.html
      client:
        accessTokenUri: http://openam.example.org:8080/OpenAMTest/oauth2/access_token
        userAuthorizationUri: http://openam.example.org:8080/OpenAMTest/oauth2/authorize
        clientId: bearer-client
        clientSecret: clientsecret
        scope: openid profile
      resource:
        userInfoUri: http://openam.example.org:8080/OpenAMTest/oauth2/userinfo
  zuul:
    routes:
      exampleApp:
        path: /example-application/**
        url: http://openam.example.org:8081/example-application
  </code></pre>
  
  <p>The Application class looks like the following:</p>
  
  <pre><code>@SpringBootApplication
  @EnableZuulProxy
  @EnableOAuth2Sso
  public class TestZuulProxy extends SpringBootServletInitializer {
  
  public static void main(String[] args){
  
      SpringApplication.run(TestZuulProxy.class, args);
  }
  
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(applicationClass);
  }
  
  private static Class&lt;TestZuulProxy&gt; applicationClass = TestZuulProxy.class;
  
  @Configuration
  @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
  protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
  
      @Override
      public void match(RequestMatchers matchers) {
          matchers.anyRequest();
      }
  
      @Override
      public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests().antMatchers("/index.html", "/home.html", "/")
                  .permitAll().anyRequest().authenticated().and().csrf()
                  .csrfTokenRepository(csrfTokenRepository()).and()
                  .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
  
      }
  
      private CsrfTokenRepository csrfTokenRepository() {
          HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
          repository.setHeaderName("X-XSRF-TOKEN");
          return repository;
      }
  
      public class CsrfHeaderFilter extends OncePerRequestFilter {
          @Override
          protected void doFilterInternal(HttpServletRequest request,
                                          HttpServletResponse response, FilterChain filterChain)
                  throws ServletException, IOException {
              CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                      .getName());
              if (csrf != null) {
                  Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                  String token = csrf.getToken();
                  if (cookie==null || token!=null &amp;&amp; !token.equals(cookie.getValue())) {
                      cookie = new Cookie("XSRF-TOKEN", token);
                      cookie.setPath("/");
                      response.addCookie(cookie);
                  }
              }
              filterChain.doFilter(request, response);
          }
      }
  }
  }
  </code></pre>
  
  <p>Now when i go to the "example-application" i get forwarded to the OpenAM authorization login screen. When I type in the credentials I can access the "example-application". Console log on the Gateway Service:</p>
  
  <pre><code>2015-06-22 17:14:10.911  INFO 6964 --- [nio-9000-exec-3] o.s.c.s.o.r.UserInfoTokenServices        : Getting user info from: http://openam.example.org:8080/OpenAMTest/oauth2/userinfo
  2015-06-22 17:14:10.953  INFO 6964 --- [nio-9000-exec-3] o.s.b.a.audit.listener.AuditListener     : AuditEvent [timestamp=Mon Jun 22 17:14:10 CEST 2015, principal=Aaccf Amar, type=AUTHENTICATION_SUCCESS, data={details=remoteAddress=0:0:0:0:0:0:0:1, sessionId=&lt;SESSION&gt;, tokenType=BearertokenValue=&lt;TOKEN&gt;}]
  </code></pre>
  
  <p>Http-Header read by Zuul Filter:</p>
  
  <pre><code>authorization --- Bearer c2b75b5a-c026-4e07-b8b9-81e9162c9277
  x-forwarded-host --- localhost:9000
  x-forwarded-prefix --- /example-application
  </code></pre>
  
  <p>So something works! I have an access-token that gets forwarded to the REST-API.</p>
  
  <p><strong>Problem</strong></p>
  
  <p>1) This solution does not really meet my requirements, because I don't want the REST API to call the token-endpoint of OpenAM. I want that a JWT with the nessessary claims gets passed to the API in the Header. Should I create a JWT in the Gateway (e.g. Zuul Filter) manually or is there another solution?</p>
  
  <p>2) In the solution above, when the access-token expires Zuul keeps forwarding me to the API. Why is this? Doesn't Spring Oauth2 checks if the access-token expires? how can I implement that?</p>
  
  <p>3) I also tried to configure the tokenInfoUri in application.yml, but then I am getting a "405 Method Not Allowed" exception, because I think OpenAM expects a GET request on the tokeninfo-Endpoint. Can I customize this somehow? Which Classes do I need to override/customize to change the request.</p>
  
  <p>If you have an advices, ideas or possible solutions, let me know!</p>
  
  <p>Thank you!</p>