I'm configuring a Spring Cloud (Angel.SR6) application using the Zuul reverse proxy utility, in order to hide the internal service ports. My zuul (edge) service is published in the 8765 port and my organizations service is in the 8083 one. Everything goes smoothly when I access the application with no security, http://localhost:8765/organization/organizations
returns the JSON with all the organizations.
However, now I want to integrate a Keycloak SSO (OAuth2) server for authorization purposes. I have added the Spring Security adapter in my organization service and configured it to authenticate in http://localhost:8080/auth
. Everything goes well, except that zuul performs a redirection instead of proxying. So when authentication is successful, I get redirected to http://localhost:8083/organizations
instead of http://localhost:8765/organization/organizations
. Here there are my browser requests:
That's because the keycloak adapter creates a token verification endpoint in the http://localhost:8083/sso/login
, from which it performs a redirection to the authorization server in order to validate the token. When authorization server acknowledges it, a redirection is sent to the organization service, with the /organization
path, so the end url being loaded is http://localhost:8083/organizations
. But I would like the first requested url to be loaded instead.
Which choice do I have?
Recently I've had the same problem. I've solved it by:
Add to application.properties in Zuul
zuul.sensitive-headers=Cookie,Set-Cookie
Introduce KeycloakFilterRoute in Zuul
class KeycloakFilterRoute extends ZuulFilter {
private static final String AUTHORIZATION_HEADER = "authorization";
@Override
public String filterType() {
return "route";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.getRequest().getHeader(AUTHORIZATION_HEADER) == null) {
addKeycloakTokenToHeader(ctx);
}
return null;
}
private void addKeycloakTokenToHeader(RequestContext ctx) {
RefreshableKeycloakSecurityContext securityContext = getRefreshableKeycloakSecurityContext(ctx);
if (securityContext != null) {
ctx.addZuulRequestHeader(AUTHORIZATION_HEADER, buildBearerToken(securityContext));
}
}
private RefreshableKeycloakSecurityContext getRefreshableKeycloakSecurityContext(RequestContext ctx) {
if (ctx.getRequest().getUserPrincipal() instanceof KeycloakAuthenticationToken) {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) ctx.getRequest().getUserPrincipal();
return (RefreshableKeycloakSecurityContext) token.getCredentials();
}
return null;
}
private String buildBearerToken(RefreshableKeycloakSecurityContext securityContext) {
return "Bearer " + securityContext.getTokenString();
}
}