Authentication session
- Replaces ClientSessionModel
- authenticationSession is created when OIDC/SAML application redirects to Keycloak login screen
- It lives during whole authentication, requiredActions, consents flow
- authenticationSession is removed once all Keycloak flows finished (right before redirect back to OIDC/SAML application).
- At the same point, userSession with same ID is created and SSO cookies are created
- new infinispan cache "authenticationSessions"
- Distributed cache with 1 owner by default
- Cache "sessions" now contains just userSession entities
- Authentication session is tracked with the cookie AUTH_SESSION_ID
- That cookie also provides session stickiness
- Format of the cookie is like <auth-session-id>.<node-id>
Sticky sessions
- Sticky session ensures that loadbalancer forwards all requests from same user (browser) to the same backend node
StickySessionEncoderProvider
- SPI for add the sticky session information to the request
- By default it adds route to the AUTH_SESSION_ID cookie as mentioned above
- It doesn't necessarily sticky to the itself. Instead it asks infinispan who is the owner
Example
- Initial request processed on node1
- authentication session with random ID "123" is created
- Infinispan distributed cache decides that ID "123" will be saved (owned) by the distributed cache on node2
- Keycloak then adds the route to the "node2", not to current "node1"
- Great performance - session always available locally
- When ownership changes (rebalance of distributed cache) route in the cookie is automatically updated
- Similar to what Wildfly doing for servlet Http sessions
Improving?
- Integrate with KeyAffinityService
- Infinispan builtin utility to return some ID owned by current node
- Useful in cases when admins don't want Keycloak to add sticky session information to the cookie
- Feedback from the community on keycloak-dev
Java
- AuthenticationSessionProvider - default impl based on infinispan
- StickySessionProvider - adds sticky sessions to the cookies
- AuthenticationSessionManager - delegates to the providers above and deals with the AUTH_SESSION_ID cookie etc
UserSessionEntity
- same ID like authentication session
- Allows easily detect that authenticationSession is already authenticated
- Infinispan default hashing strategy will assign userSessionEntity same owner like particular authenticationSessionEntity
- Need to doublecheck infinispan behaviour (failover, different count of owners for "sessions" and "authenticationSessions" caches)
- Upgrade master to Wildfly 11?
Example flow
- User opens login screen
- Authentication session "123" created
- User authenticates
- Authentication session "123" removed and user session "123" created
- Cookie AUTH_SESSION_ID not removed. Will still have value like "123.node1"
- User opens login screen for another client - SSO login
- Authentication session "123" will be created again.
- All requests sticky to same node
AuthenticatedClientSessionModel
- contains information about client inside userSession
- not separate entity, but attachement of userSession entity
- On userSessionEntity there is: Map<String, AuthenticatedClientSessionEntity> authenticatedClientSessions
- Key is client UUID
- just one authenticatedClientSession on userSession per client
- Still work to do - ideally replace with just list of clients
Browser buttons
- No additional redirects (improved since last presentation)
- Small amount of javascript based on "history.replaceState"
- Old browsers will just ignore that - same behaviour like before
Next steps
- Try setup of cross-dc. Initial performance tests
- Refactoring userSessionProvider - work in progress
- Events (tasks) based approach
- Avoid lost updates (write skew) when more requests updating same userSession in cluster
- Consistency in cluster
- Eventual-consistency in cross-dc (updates might change order due the fact the ASYNC channel between datacenters)
sticky sessions for backchannel requests
- Use sticky session if possible even for backchannel requests
- Not always possible
- Possible in our own adapters
- Possible in some loadbalancers (undertow with reverse-proxy LB or mod_cluster LB)
- In cross-dc, code-to-token request may not be able to participate in sticky session
- By default ASYNC channel for communication between datacenters regarding userSession CRUD
- code-to-token request is sent quickly after userSession created
- code-to-token request processed on node2 may not see userSession previously created in DC1
- codeToToken request won't lookup userSession at all
- Code will be JWT signed by realm HMAC key containing all informations, which will be transferred to the tokens
- Is it ok regarding security?
- will need refactoring of protocolMappers SPI
- other option: wait until userSession retrieved from second DC
- Asynchronous requests? Otherwise DoS?
- Bad performance, longer response times
- Require sticky session for code-to-token request?
- May not be so bad if route is added directly to "code" parameter
- http://apphost/app?code=123.node1&state=456
- Many loadbalancers seem to support sticky session based on URL part, probably not all
- Code is one time use per OIDC/OAuth specifications
- Approach with having single-use cache with the list of expired codes
- In case that sticky session can't be used, will need to call blocking "cache.putIfAbsent" and wait until synced to second DC
- With sticky session don't need to call second DC, but check route (claim inside "code" )
- Option to relax on one-time use code?