[keycloak-dev] Issue with concurrent SSO login to same client in more browser tabs
Marek Posolda
mposolda at redhat.com
Mon Nov 19 05:45:36 EST 2018
Hi,
I've sent PR https://github.com/keycloak/keycloak/pull/5736 to fix the
issue in subject (corresponding JIRAs are KEYCLOAK-7774 KEYCLOAK-8438).
The cause is that once the user is authenticated in the browser and has
userSession, there is just 1 clientSession per the userSession+client.
So in case of concurrent SSO login in more browser tabs, there can be an
issue that each tab is writing it's state to the same clientSession,
which causes conflicts (especially attributes like nonce, scope or
redirectUri can be possibly different for each tab and shouldn't be
shared).
The possibility can be to revert back when we had more clientSessions
per userSession+client. I think this is step back and has lots of other
issues (memory consumption, more cluster and cross-dc writes, worse
performance in general...). For the future, it will be rather ideal to
remove clientSession entirely or reduce their size even more, as they
will be needed for logout, but hopefully for nothing more.
So the other possibility is to move most of the state to the "code"
parameter and to the refreshToken. Each browser tab has it's own "code"
and it's own refreshToken. Problem with the "code" is, that it's used as
query parameter in the URL and hence has limits for it's size. It seems
ideal is still to stick with 2000 characters per URL. And when
redirectUri itself will be part of the code, it can be problematic as we
don't know how the redirectUri provided by users will be big....
Fortunately refreshToken doesn't have this issue as it needs to be
always sent in the POST request.
So to solve the issue for "code", I've added an entry to the infinispan
cache "actionTokens", which encapsulates needed state and it's supposed
to be valid just for the very short time (between the
AuthenticationResponse to the application and the time when application
sends the code-to-token request) and it's lifespan corresponds to realm
code lifespan (1 minute by default). In the code-to-token request, there
is a call to "cache.remove" to remove the code. Infinispan caches
(local, distributed and hotrod caches) fortunately guarantee that
"remove(123)" is always successful just in 1 thread (Successful means
that it returns previous state). So we still have guarantee for the
single-use code.
Marek
More information about the keycloak-dev
mailing list