Update Principal in Session when using Spring-Session
Asked Answered
S

2

7

We have extended the principal with our own User object. This way the object is available with every request. When a user updates his information, the principal needs to updated with this new data. When not using spring-session, this method works. However, with spring-session, it does not.

I checked in the spring-session code, and the RedisOperationsSessionRepository:save(RedisSession session) only calls session.saveDelta(), which only saves changed attributes. So, how do we update a principal in session?

Note - the place where the principal is updated is in the service layer, so we do not have access to a SessionAuthenticationStrategy.

Stewpan answered 15/12, 2015 at 22:55 Comment(0)
S
10

Found a way to do this, so answering my own question. Spring-security stores the context as an attribute in HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY. So updating the key manually (instead of through Spring-Session) results in the Principal being updated.

httpSession.setAttribute(
  HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
  SecurityContextHolder.getContext()
);
Stewpan answered 16/12, 2015 at 7:56 Comment(0)
C
1

It is enough to set a new Authentication object. You can recreate it reusing some parts from old:

final Authentication oldAuth = SecurityContextHolder.getContext().getAuthentication();
final Authentication newAuth = new PreAuthenticatedAuthenticationToken(
        newDetails, oldAuth.getCredentials(), oldAuth.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuth);

If the reference for Authentication has changed this triggers updates to session storage (be it Redis or whatever)...

Setting special magical session attribute HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY (the constant "SPRING_SECURITY_CONTEXT" is spread across Spring Security classes) also might trigger propagation of a new value through session storage (like Redis or DB), for example in RedisSessionRepository attributeName is placed to delta for saving:

@Override
public void setAttribute(String attributeName, Object attributeValue) {
    this.cached.setAttribute(attributeName, attributeValue);
    this.delta.put(getAttributeKey(attributeName), attributeValue);
    flushIfRequired();
}
Chinaman answered 27/7, 2022 at 18:35 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.