Replies: 4 comments 2 replies
-
@blevine what is the URL after the redirect from the ALB to Keycloak? The one when you are asked for the username again? |
Beta Was this translation helpful? Give feedback.
-
Thanks for responding so quickly. The URL was: https:///auth/realms/idp_test/protocol/openid-connect/auth?client_id=idp_test&redirect_uri=https%253A%252F%252F%252Foauth2%252Fidpresponse&response_type=code&scope=email%20profile%20openid%20acr&state= So I think I figured out at least part of the issue. I had been experimenting with step-up authentication and originally had a flow that incorporated two levels of authentication. When I started running into the problem described above, I wanted to take step-up authentication out the equation to get a simpler reproducible case. So I removed the conditional level of authentication executions from the flow . However, in my clients I had left the Default ACR Values configuration set to 1 and 2 respectively. Looking at the code for CookieAuthenticator, I can see that it checks the requested level of authentication (which was 1 in this case) against the highest level of authentication (which was -1 meaning no level) and if requested level > highest level, authentication does not succeed (calls context.attempted()). So the flow then falls through to the next authenticator which is Home IDP. Since there actually is a session, the form shows the username. To test this theory and so I could run a debugger on Keycloak, I ran an experiment on a local Keycloak test instance by changing the client config of the security-admin-console client to include default acr values: So no load balancer to further confuse things. I didn't even define an external IdP--I just let Home IDP authenticate locally. I successfully logged in the first time and accessed the admin console. When I refreshed the page, I was able to reproduce the behavior I described above. And stepping through the CookieAuthenticator code in the debugger, I could see that the following code was executed:
where previouslyAuthenticatedLevel was -1 and acrStore.getRequestedLevelOfAuthentication() was 2. To summarize, this happened because the client was configured with a default level of authentication, but there was no conditional level of authentication execution in the authentication flow. My original flow that did include the step-up authentication flow is below. This seems correct to me and so I'm not sure why it resulted in this behavior. I'm going to add the step-up auth executions to my local debug environment to see what happens. As you can imagine, it's very difficult to debug this problem against Keycloak running in a Kubernetes cluster in the cloud. I hope you don't mind if I report back my findings to see if you have any additional advice. Original step-up authentication flow |
Beta Was this translation helpful? Give feedback.
-
So, I still get the problem behavior I described above when doing IdP auth, but not when I do local auth. Do you believe that this is because the IdP auth does not finish the flow and so does not set the level of authentication into the user's session? At this point, the fact that I can't continue to OTP authentication (level 2) after IdP authentication is not that much of an issue since only internal employees (who are not required to do OTP authentication) will be authenticated against the external IdP. |
Beta Was this translation helpful? Give feedback.
-
I enabled some trace logging. I think this pretty much proves that this is due to keycloak/keycloak#10250. Here's some log output from the IdP authentication case:
and here's output from the local authentication case:
I started a discussion about this here: keycloak/keycloak#25272 Thanks again for your help. |
Beta Was this translation helpful? Give feedback.
-
I've created a flow according to your docs with the Home IDP authenticator and an alternate username/password form. I'm running Keycloak 18.0.2 and using a custom version of your plugin based on a recent version of your code that I back-ported to Keycloak 18.0.2.
My Keycloak instance is running in a Kubernetes cluster with 2 nodes. The application that is protected by Keycloak is fronted by an AWS Application Load Balancer. Authentication is done at the load balancer. The load balancer has its own session timeout. When that timeout has not expired, the user is directed to the resource without hitting Keycloak. When it has expired, Keycloak is hit to determine whether the user still has a session. Here's a more detailed description if you're not familiar with application load balancers: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html#authentication-flow. The most pertinent section is probably this: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html#timeout. In my case, the load balancer session timeout is 30 seconds, the access token timeout is 5 minutes, the Keycloak session idle timeout is 30 minutes, the session max timeout is 1 hour.
For my tests, I've set the load-balancer session to 30 seconds so that Keycloak is hit more frequently. The problem is that after 30 seconds, I'm presented with the username/email form even though the Keycloak session has not expired.
I noticed that on first login, I see the expected form:
and login proceeds as normal.
If I refresh the page after 30 seconds, I see the same form however, my username appears in the header indicating that there is still an existing session.
In fact, if I try to log in with a different username, I get an error saying that I'm already logged in as blevine.
I don't understand why I'm being presented with that form when there's still an existing session. I would have expected the Cookie authenticator to succeed and so the Home IDP authenticator would not have been reached. Here is my flow:
Any suggestions?
Beta Was this translation helpful? Give feedback.
All reactions