We've been using a Apache 2.2 reverse proxy to have multiple apps running on the same VM. Everything worked fine till the moment we added Keycloak adapter 3.4.0.Final + spring security 1.5.9.RELEASE.
So this is how it works:
VM1 app1 app2
VM2 Keycloak
laptop on the same network Browser app1 - for dev purposes
Scenarios: 1) Everything worked fine between laptop - VM2 with the app. 2) Everything worked fine between browser laptop - VM1 - VM2 When no reverse proxy was in place (so directly accessing the app port). 3) Problems when reverse proxy in place. browser laptop - VM1 (Apache with mod_prox) - VM2
I followed all the advice in the documentation:
http://www.keycloak.org/docs/1.9/server_installation_guide/topics/clustering/load-balancer.html
Those were my rules before:
LoadModule proxy_module modules/mod_proxy.so
ProxyRequests On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPassMatch ^/MyAPP/(.+) http://localhost:8585/MyAPP/$1
ProxyPassReverse ^/MyAPP/(.+) http://localhost:8585/MyAPP/$1
ProxyPreserveHost On
Observed: GET VM1/MyAPP/index.html -> redirected to VM2 keycloak with the right redirect url GET VM1/MyAPP/index.html?State=xxxx -> redirected to / GET / -> there's nothing on root so it would end here
First change: I've seen that the cause of this was a keycloak success handler that was redirecting me to root. So I changed it to redirect it to the same page with this:
public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean( KeycloakAuthenticationProcessingFilter filter){
FilterRegistrationBean registrationBean = new
FilterRegistrationBean(filter);
successHandler = new AuthenticationSuccessHandler();
successHandler.setDefaultTargetUrl("/MyAPP/index.html");
filter.setAuthenticationSuccessHandler(successHandler);
}
Observed:
GET VM1/MyAPP/index.html -> redirected to VM2 keycloak with the right redirect url
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
GET VM1/MyAPP/index.html?State=xxxx -> redirected to /MyAPP/index.html
....
Infinite loop.I've also noticed that the application was doing the authentication everytime. Suspicious.
So I started suspecting it was apache that was causing problems and decided to give a shot to a different proxy: haproxy. It failed with the same problem. But I was being redirected to /sso/login intead
So next step was to debug the different requests: Proxied vs non Proxied
VM1/MyAPP vs VM1:8585/MyAPP
So I discovered that it would authenticate the request every time the request had the authorization header.This was only happening with the proxy version.
So with apache 2.2 you cannot remove headers. That was just added on 2.4 So again haproxy, and tried it in the same way forcing the removal of authorization header. And it almost worked. I was getting some problem with the request method being 1 instead of GET. Odd...
So long story short It was obvious now that basic auth was the problem.
How to solve this problem?
Update:
My question now is: How can I change KeycloakAuthenticationEntryPoint loginUri to contain the subcontext of my reverse proxy in the configuration? - Having a reverse proxy "sso/login" on root doesn't let me have more than 1 keycloak app in the same server.
How did I solve the problem:
1) So the first step was to disable basic auth on the apache that was interfering with keycloak authorization process or at least with spring security.
What I started notice after this was that I was always being redirected to /sso/login on root.
2) To solve this problem I added a new proxy pass rule to redirect sso/login request to my server.
ProxyPassMatch ^/sso/login(.*) http://localhost:8585/sso/login$1
ProxyPassReverse ^/sso/login(.*) http://localhost:8585/sso/login$1
After this I was still being redirected to /sso/login or just to the root. After trying with incognito mode I found it actually worked. Tried different browser and it worked as well.
3) Some old session status was still on my browser so cleared all the cookies closed all the browser tabs and restarted chrome and it started working.
4) Bullet point 2 has a big flaw. It won't allow you to have multiple keycloak adapter app in the same server. To change the behavior on spring side I solve it with two processes. - The first one is to re-set the login uri on keycloakAuthenticationEntryPoint
@Autowired
AdapterDeploymentContext adapterDeploymentContext;
private static final String OAUTH_LOGIN_URL = "/sso/login";
@Override
protected void configure(HttpSecurity http) throws Exception{
KeycloakAuthenticationEntryPoint keycloakAuthenticationEntryPoint =
new KeycloakAuthenticationEntryPoint(adapterDeploymentContext);
keycloakAuthenticationEntryPoint.setLoginUri(realSubContext + OAUTH_LOGIN_URL);
...
}
The second one was to add a redirect rewrite rule for sso login keycloak: redirect-rewrite-rules : "^/sso/login(.*)$": "/MYSUBCONTEXT/sso/login$1"