25

I'm using spring-security framework.When I update the permissions,It does not take effect immediately.I have to quit the current user(means logout), and then re-visit(means login) will be to update the user's permission.

Is a way that immediately enable the authority after update user authority in spring security?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Gordian Yuan
  • 4,750
  • 6
  • 29
  • 35
  • One possible solution is described in [Adjusting secured session in real time](http://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time) post on Spring Source blog. – Karimchik May 22 '09 at 13:06
  • It took a while, but I think this was finally figured out: http://stackoverflow.com/q/23072235/42962 – hooknc Jan 22 '16 at 21:54

7 Answers7

9

You can set alwaysReauthenticate in your AbstractSecurityInterceptor like this

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="alwaysReauthenticate" value="true"/>
 ...
</bean>

Of course you should pay attention because 99,9% you don't need reauthentication. As authentication might use a database or something else your performance might degrade. But usually you have a cache, like 2nd Level with hibernate, so loading the userdetails everytime should be an memory only operation in all cases where authorities havn't changed.

Janning Vygen
  • 8,877
  • 9
  • 71
  • 102
  • 1
    If I want to secure methods on beans, do I need to make the same change to another filter, or is this enough? – Simon Gibbs Oct 21 '11 at 10:10
  • 1
    this filter is only for web request as far as i see. if you are using MEthodSecurityInterceptor you can call reauthenticate on your own. But if every method call is preceded by checking this web filter as every method call is somewhat inside a http request you should be fine – Janning Vygen Oct 24 '11 at 08:52
  • 1
    This is the correct answer. I'd like only to add that one needs to incorporate this interceptor into security config by either `` inside of section or by interceptor property: ` ` – Roman Sinyakov Aug 02 '16 at 15:50
4

Gandalf solution is valid but not complete. In order for the new permissions to be considered by spring security (eg. allow access to pages previously not available), you need to create a new authentication object (eg. new UsernamePasswordAuthenticationToken) containing the new list of authorities.

Hyperion
  • 41
  • 1
3

The following thread explains how to reload your user/principal every request:

Reload UserDetails Object from Database Every Request in Spring Security


Full disclosure I am the author of the question and answer of the question in the above link.

hooknc
  • 4,854
  • 5
  • 31
  • 60
2

Is not enough to reset the Thread Local context, you need to update the session too:

UserContext userContext = (UserContext) context.getAuthentication().getPrincipal();
if (userContext != null && userContext.getUsername() != null) {
    //This is my function to refresh the user details
    UserDetailsBean userDetails = getUserDetailsBean(userContext.getUsername());
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication instanceof UsernamePasswordAuthenticationToken) {
        UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
        auth.setDetails(userDetails);
    }
    return userDetails;
} else {
    throw new ServiceException("User not authenticated");
}
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());

At least in google appengine the session is not a reference and by modifying the thread local doesn't get updated automatically, you have to manually session.set your object.

Jordi P.S.
  • 3,838
  • 7
  • 36
  • 59
1

Since you didn't quite provide the exact details in your question, I assume that you have a situation where:

  1. You are supplying a UserDetailsService to load up a UserDetails when a user attempts to login
  2. As a part of that service, you are querying a database/DAO to load up details about a user's permissions, and are setting the granted authorities based on this
  3. That when you say "When I update the permissions" you are referring to updating the user's permissions in the database (or whatever you are storing data in).

If so then what you are seeing is by design - Spring Security only loads the UserDetails for the user the first time, when they attempt to login, and then stores it in Session from then on. Generally this makes sense, as it avoids the application from having to perform the same queries about user details on each request. Also, a user's permissions are generally not changing throughout 99.9% of their visits.

To change this behavior, you might want to look into adding a "refresh" command/page somewhere that will trigger some code (which you will have to write) which will re-query the UserDetailsService and replace the UserDetails in SecurityContext. I don't believe there is any built-in way to do this.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • Your assumption is correct.I would like to know is there any good ways to do this without having to re-login.Perhaps I can modification user permissions which store in the current session.I'm trying to .. – Gordian Yuan May 21 '09 at 12:57
0

You could create your own implementation of the UserDetails interface that is returned from your authentication mechanism, that allows access to the GrantedAuthorities[]. Then add your new authority directly to that UserDetails object. You may run into issues if a user can have multiple sessions open at once (or if multiple users share the same generic login), that the new permissions will only be seen on the session you have altered.

Gandalf
  • 9,648
  • 8
  • 53
  • 88
-3

You can try this

SecurityContextHolder.getContext().setAuthentication(SecurityContextHolder.getContext().getAuthentication());
yostane
  • 383
  • 1
  • 4
  • 19