oasp-forge / oasp4j-enterprise-security

2 stars 0 forks source link

Spring Boot + Zuul as Proxy #45

Closed JuHarm89 closed 9 years ago

JuHarm89 commented 9 years ago

Setup an application with Spring Boot and configure it as Reverse Proxy (Project Zuul) with Spring Cloud Netflix (http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html). Additionally exploring OAuth2 capabilities of Spring Cloud Security for Oauth2 SSO with Bearer Tokens

hohwille commented 9 years ago

For zuul you can extend com.netflix.zuul.ZuulFilter to implement the redirection logic easily. Override run() method and start with List<Pair<String, String>> responseHeaders = com.netflix.zuul.context.RequestContext.getCurrentContext().getZuulResponseHeaders();

hohwille commented 9 years ago

Try these dependencies in you pom.xml:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.security.oauth</groupId>
  <artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-jwt</artifactId>
</dependency>
<dependency>
  <groupId>io.oasp.java.modules</groupId>
  <artifactId>oasp4j-logging</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
hohwille commented 9 years ago

For versioning use BOMs:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-parent</artifactId>
      <version>1.0.0.RELEASE</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>io.oasp.java</groupId>
      <artifactId>oasp4j-bom</artifactId>
      <version>1.1.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
hohwille commented 9 years ago

Can be configured via application.properties or application.yml. See also org.springframework.cloud.netflix.zuul.ZuulProxyConfiguration.

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Example:

zuul.routes.oasp.path = /oasp/**
zuul.routes.oasp.url = http://localhost:8081/oasp

In General:

zuul.routes.<app>.path = /<app>/**
zuul.routes.<app>.url = http[s]://<host>:<port>/<app>
hohwille commented 9 years ago

In the example above the portal would proxy a request on path /oasp/index.html to http://localhost:8081/oasp/index.html and feed the result of that to the initial requester.

hohwille commented 9 years ago

https://github.com/Netflix/zuul/wiki

JuHarm89 commented 9 years ago

Hey Jörg, thanks for your Input. We already setup a Proxy with Spring Boot and Zuul and the proxy-part works fine. A bit tricky seems to be be how to get the JWT. Right now I am a bit confused whether it is possible to use the OpenAM JEE Policy Agent or Spring-cloud-security (@EnableOAuth2Sso) for this purpose. Another question would be: Doesn't the JWT need to be stored by the JS Client somehow (e.g. localstorage) and send with each request?

JuHarm89 commented 9 years ago

To make OpenAM issue JWT it needs to be configured as OpenID Provider (as it seems). So right now I can get a valid JWT from OpenAM as OpenID provider, but the Integration with the Policy Agent seems to be a little bit tricky, especially the Installation of the policy Agent on the embedded Tomcat of Spring Boot. Furthermore i am not sure if the JEE Policy Agent is the right choice for our needs, because normally policy agents are used on the app server itself and i didnt find any documentation about how to relay a JWT from a policy Agent to the Server running the application. OpenIG seems to be the solution here (having a own reverse Proxy build in) or we could maybe use Spring Cloud Security together with the ZuulProxy as API Gateway and make some customization on the Spring OAuth SSO Configuration to integrate it with OpenAM. What are your thoughts on that?

hohwille commented 9 years ago

My thoughts about this are to decouple the JWT token generation from the AM generally. Just use what ever is easy as "protocol" or "contract" between portal and AM for auth (e.g. SAML). In the portal after auth simply generate JWT yourself and manually add it to the header of the zuul proxy request. You can cache the JWT in the session if exp claim fits to session timeout what should be suggested.

hohwille commented 9 years ago

For me it worked like this:

@Named
public class OAuth2BearerHeaderFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "pre";
  }

  @Override
  public int filterOrder() {
    return 10;
  }

  @Override
  public boolean shouldFilter() {

    return true;
  }

  @Override
  public Object run() {

    RequestContext ctx = RequestContext.getCurrentContext();
    MyAuthentication authentication = MyAuthentication.get();
    // authentication = (MyAuthentication ) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    ctx.addZuulRequestHeader(HttpHeaders.AUTHORIZATION,
        OAuth2AccessToken.BEARER_TYPE + " " + authentication.getSecurityToken());

    return null;
  }
}
hohwille commented 9 years ago

Within your implementation of AuthenticationProvider you only need to create the instance of MyAuthentication (probably name it AccessAuthentication or OaspAuthentication) containing the RSA-Signed token. Therefore I use Jackson to create the JWT-Content as JSON from a simple Map<String, String>:

String jsonClaim = this.objectMapper.writeValueAsString(map); Jwt token = JwtHelper.encode(jsonClaim, this.signer); String securityToken = token.getEncoded();

That's about it...