@@ -34,22 +34,31 @@ func (h *Handler) trySessionLoginWithSession(ctx context.Context, r *http.Reques
3434
3535 // Create a new client state for the target client via SSO. It carries the
3636 // source's authentication time: the user did not authenticate again here.
37+ var newState * storage.ClientAuthState
3738 if err := h .Storage .UpdateAuthSession (ctx , session .ID , func (old storage.AuthSession ) (storage.AuthSession , error ) {
3839 if old .ClientStates == nil {
3940 old .ClientStates = make (map [string ]* storage.ClientAuthState )
4041 }
41- old . ClientStates [ authReq . ClientID ] = & storage.ClientAuthState {
42+ newState = & storage.ClientAuthState {
4243 AuthenticatedAt : sourceState .AuthenticatedAt ,
4344 LastActivity : now ,
4445 ViaSSO : true ,
4546 }
47+ old .ClientStates [authReq .ClientID ] = newState
4648 old .LastActivity = now
4749 old .IdleExpiry = h .Sessions .IdleExpiry (now )
4850 return old , nil
4951 }); err != nil {
5052 h .Logger .ErrorContext (ctx , "session: failed to create SSO client state" , "err" , err )
5153 return false
5254 }
55+ // Keep the caller's session in sync for storage backends that work on a
56+ // deserialized copy (SQL, ent, Kubernetes, etcd) rather than the shared
57+ // in-memory map.
58+ if session .ClientStates == nil {
59+ session .ClientStates = make (map [string ]* storage.ClientAuthState )
60+ }
61+ session .ClientStates [authReq .ClientID ] = newState
5362
5463 h .Logger .DebugContext (ctx , "session: SSO login from sharing client" ,
5564 "user_id" , session .UserID , "connector_id" , session .ConnectorID , "client_id" , authReq .ClientID )
@@ -69,11 +78,11 @@ func (h *Handler) trySessionLoginWithSession(ctx context.Context, r *http.Reques
6978 // re-authentication demand for a stale session on the first. The per-session,
7079 // per-client timestamp already exists (ClientAuthState.AuthenticatedAt,
7180 // carried across for SSO above) and is guaranteed non-nil here.
81+ authenticatedAt := ui .LastLogin
82+ if cs := session .ClientStates [authReq .ClientID ]; cs != nil && ! cs .AuthenticatedAt .IsZero () {
83+ authenticatedAt = cs .AuthenticatedAt
84+ }
7285 if authReq .MaxAge >= 0 {
73- authenticatedAt := ui .LastLogin
74- if cs := session .ClientStates [authReq .ClientID ]; cs != nil && ! cs .AuthenticatedAt .IsZero () {
75- authenticatedAt = cs .AuthenticatedAt
76- }
7786 if now .Sub (authenticatedAt ) > time .Duration (authReq .MaxAge )* time .Second {
7887 return false
7988 }
@@ -84,12 +93,14 @@ func (h *Handler) trySessionLoginWithSession(ctx context.Context, r *http.Reques
8493 "session_id" , session .ID , "user_id" , session .UserID )
8594 }
8695
87- return h .finishSessionLogin (ctx , r , w , authReq , session , & ui , now )
96+ return h .finishSessionLogin (ctx , r , w , authReq , session , & ui , authenticatedAt , now )
8897}
8998
9099// finishSessionLogin completes a session-based login (direct or SSO) by updating the auth request
91100// with the user's identity, refreshing session activity, and returning the appropriate redirect URL.
92- func (h * Handler ) finishSessionLogin (ctx context.Context , r * http.Request , w http.ResponseWriter , authReq * storage.AuthRequest , session * storage.AuthSession , ui * storage.UserIdentity , now time.Time ) bool {
101+ // authenticatedAt is the per-session, per-client authentication time used for both max_age gating
102+ // and the auth_time claim the RP sees.
103+ func (h * Handler ) finishSessionLogin (ctx context.Context , r * http.Request , w http.ResponseWriter , authReq * storage.AuthRequest , session * storage.AuthSession , ui * storage.UserIdentity , authenticatedAt time.Time , now time.Time ) bool {
93104 claims := storage.Claims {
94105 UserID : ui .Claims .UserID ,
95106 Username : ui .Claims .Username ,
@@ -99,12 +110,12 @@ func (h *Handler) finishSessionLogin(ctx context.Context, r *http.Request, w htt
99110 Groups : ui .Claims .Groups ,
100111 }
101112
102- // Update AuthRequest with stored identity and auth_time from last login.
113+ // Update AuthRequest with stored identity and auth_time from the per-session login.
103114 if err := h .Storage .UpdateAuthRequest (ctx , authReq .ID , func (a storage.AuthRequest ) (storage.AuthRequest , error ) {
104115 a .LoggedIn = true
105116 a .Claims = claims
106117 a .ConnectorID = session .ConnectorID
107- a .AuthTime = ui . LastLogin
118+ a .AuthTime = authenticatedAt
108119 return a , nil
109120 }); err != nil {
110121 h .Logger .ErrorContext (ctx , "session: failed to update auth request" , "err" , err )
0 commit comments