Authentication session

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)

OAuth code as JWT?

  • 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?