4

I'm trying to get a Zuul reverse proxy setup with Spring Boot, Eureka, Zuul and Spring OAuth. Specifically, I'm trying to obtain an OAuth bearer token from our OAuth server that is behind Zuul. To do this, i need to make a POST request to the proxy endpoint that redirects to our OAuth server. This request is using the client_credentials grant type and thus am using BasicAuth to obtain the bearer token. I've verified that I can obtain the token by bypassing Zuul.

I been having trouble getting my expected results which are a reverse proxy that is OAuth aware but has no required security itself. I've tried a few different variations on configuration and cannot find the golden ticket.

Here is my Maven:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.mycompany.cloud</groupId>
    <artifactId>mycompany-cloud</artifactId>
    <version>0.0.2-SNAPSHOT</version>
  </parent>
  <artifactId>mycompany-cloud-zuul-proxy</artifactId>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.security.oauth</groupId>
      <artifactId>spring-security-oauth2</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Brixton.SR2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.3.5.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

I initially created a configuration that was just

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableOAuth2Sso
public class ZuulProxyApplication {
  public static void main(final String[] args) {
    SpringApplication.run(ZuulProxyApplication.class, args);
  }
}

but this by default enabled basic auth security. I knew this because i would get CSRF erros on any POST request made. Setting security.enable-csrf=false did not disable this (i found this odd). Setting security.basic.enabled=false also did not disable any security also odd. I finally noticed the JavaDoc on @EnableOAuth2Sso said that if no WebSecurityConfigurerAdapter was provided then it would use a default. I tried adding the @EnableWebSecurity to my configuration which should have added a WebSecurityConfigurerAdapter but I was still getting CSRF errors on my POST requests. Maybe the default its using isnlt aware of SecurityProperties. So I ended up with this configuration:

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulProxyApplication {

  public static void main(final String[] args) {
    SpringApplication.run(ZuulProxyApplication.class, args);
  }

  @Configuration
  @EnableOAuth2Sso
  @EnableWebSecurity
  @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
  protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
      // add no users
      auth.inMemoryAuthentication();
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
      http.csrf().disable();
    }

  }
}

and the following properties:

spring:
  application:
    name: mycompany-cloud-zuul-proxy
    index: 0
security:
  oauth2:
    client:
      access-token-uri: http://mycompany-cloud-authorization-server/oauth/token
      user-authorization-uri: http://mycompany-cloud-authorization-server/oauth/authorize
  basic:
    enabled: false
  enable-csrf: false
  sessions: stateless
server:
  port: 9200
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9100/eureka/

And this was successful, it disabled the CSRF configuration and I was able to make POST requests to my services without receiving the CSRF error. However, now my OAuth server is rejecting the requests because the BasicAuth header is no longer on the request. It appears that Zuul is stripping the header. Am I misunderstanding that adding the @EnableOAuth2Sso annotation makes the application OAuth aware and that it would allow means of accessing the configured OAuth server or does it simply apply to Bearer tokens? Is it normal to place your OAuth server behind the proxy or is that not an expected thing to do? I'm guessing that I'm missing some important knowledge and/or configuration that I have yet to comprehend from the documentation.

Any help here would be appreciated.

loesak
  • 1,413
  • 2
  • 19
  • 33

1 Answers1

3

However, now my OAuth server is rejecting the requests because the BasicAuth header is no longer on the request

By default Spring cloud Zuul implementation strips some headers for security purpose (see Cookies and sensitive headers documentation)

Thus since Spring cloud netflix 1.1 following headers Cookie, Set-Cookie, Authorization are considered as sensible headers

Is it normal to place your OAuth server behind the proxy or is that not an expected thing to do?

Spring cloud is basically not designed by default to have Authorization server (or OAuth server) behind proxy (Zuul). In most example and documention Authorization server is outside proxy.

I personally created a POC for Authorization behind Proxy https://github.com/kakawait/uaa-behind-zuul-sample that may (or not) help you.

Kakawait
  • 3,929
  • 6
  • 33
  • 60
  • this all seems to be tailored towards user based oauth. We primarily need to also support grant type client_credentials and eventually all the other grant types. I have working, based off some of your provided code, the services passing the received bearer token onto the other services it calls, but now i'm trying to get the zuul proxy to do the same. I'm starting to feel that everything built for @EnableOAuthSso has been tailored to OAuth schemes where an actual user is involved (e.g. not client_credentials). Is this the case? – loesak Jul 20 '16 at 18:32
  • From what I understand with `@EnableOauthSso` you can't use `client_credentials` because SSO is design for human and browser. If some routes needs to be used with client_credentials simply remove SSO on this route. But if your route should support both I think is not currently possible you may open issue or ask on gitter directly with Spring guys – Kakawait Jul 21 '16 at 12:14
  • ok. good to validate my assumptions. i couldn't find anywhere that said it was for user based oauth only. I would think SSO should also be able to work for machine base as well as user based authentication. The way i would have expected it to work would be to either blindly pass on bearer tokens (or pre-validate them) to the backend service being called and leave the routing of the user to the login/authorization pages to the oauth server based on the type of grant being used. Wouldn't think it would be much more than that. – loesak Jul 21 '16 at 13:39
  • I did end up getting the authorization server to work (mostly) behind the Zuul. I however ended up removing from behind Zuul because some issues that came up. One issue was, the authorization server sends back redirects to the login page for user based authentication. This redirect takes into account the normal X-Forwarded-* headers when building that redirection URL but it however does not take into account the X-Forwarded-Path header that Zuul adds because most endpoints are proxied behind a specific path (http://zuul/uaa/v1/* -> http://auth/*) and Zuul isnt a ReverseProxy out of the box – loesak Oct 05 '16 at 16:58
  • Did you use `ForwardedHeaderFilter` on auth server? I personally have no problem with path and forward header with such architecture. – Kakawait Oct 05 '16 at 17:42
  • i did, it properly used all the x-forwarded-* headers except the path one – loesak Oct 17 '16 at 16:00
  • my apologies. i misread your comment. thought you were referring to the "use-forwarded-headers" spring boot configuration which is enabled. i do not think i'm using that specific filter if its not auto configured which it doesnt look like it is. I would have suspected the "use-forwarded-headers" would have done this automatically (new feature?) but that looks like its just used to configure the underlying server (tomcat valve in my case) which i dont believe is aware of x-forwarded-prefix. I will look into using the filter and see if that resolves my issue. – loesak Oct 17 '16 at 16:28
  • There is an issue on spring boot about adding the filter by default but maintainers for some reason mention on issue refuse to do it. I don't have ref of the issue but you can easily find it. – Kakawait Oct 17 '16 at 16:30
  • is there any solution to getting zuul to rewrite/add cookie paths? Say for when using oauth server behind zuul the path for the session cookie is modified to add the path mapped by zuul? – loesak Oct 26 '16 at 20:00