Announcement Announcement Module
Collapse
No announcement yet.
Spring Security-- How to add/ remove authorities of the user after he logs in. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Security-- How to add/ remove authorities of the user after he logs in.

    Hi All,
    I am working on Spring security now. What it does is while the user logs in, at that time only it loads all the authorities which belong to that user. So my question is
    How can we change(add/remove) the authorities of the user while in session. Dumb solution is add authority to the user and make him log out.
    But I want a better solution without making a redirect to login page.


    Thanks,
    Vivek.

  • #2
    Assuming you are using the standard HttpSession storage of Spring Sec authentication information, you can just pull the UserDetails out of the session and manipulate it. The problem you will have is that the standard Authentication implementations ensure that the Collection returned by getAuthorities is non-modifiable, so you may have to do some custom coding.

    Another option would simply be to reload the user's authorities when something changes. This might require a custom servlet filter which will be responsible for manipulation of the SecurityContext and active Authentication object. If you aren't familiar with this, I'd suggest looking at some of the source code for the standard filters first.

    Comment


    • #3
      Hi Pmularien,
      First of all, thanks for your reply. I like Spring Framework very much. And I have just started working on Spring Security.

      So here is the summary of what all I did,

      In my securityFilter chain bean, I am using these filters

      Code:
      <security:filter-chain pattern="/**" filters="securityContextFilter, logoutFilter, authenticationFilter, requestCacheFilter, servletApiFilter, anonFilter, sessionMgmtFilter, concurrencySessionFilter, exceptionTranslator, filterSecurityInterceptor" />
      </security:filter-chain-map>
      HttpSessionSecurityContextRepository is injected into securityContextPersistenceFilter, so I am presumming that, I am storing all the authenication information in Http Session,

      My code is as follows,

      Code:
      User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // Where User is an my own defined entity which implements UserDetails interface
              UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
      				user, 
      				"<cleartextpassowrd of the user who logged in>,
      				authorities); //Where authorities is a List<GrantedAuthority> = (List<GrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
      
              request.getSession();
      
              token.setDetails(new WebAuthenticationDetails(request));
                         
              Authentication authenticatedUser = authenticationManager.authenticate(token);//--------A
      
              SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
              
              request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
      This works but I have serious problems here,
      1. I am not able to fetch the password from User. I mean I am getting the encrypted password. While registration itself I am using the encryption and that too with salt.
      For decryption I read its very difficult and its not advisable.

      2. For some reason I observe SecurityContextHolder.getContext().getAuthenticati on().getCredentials() is returning null.
      Can you please tell me in what circumstances it is null?


      In the above code, I am injecting authentication manager into that controller class.
      Code:
      <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
      		   <property name="clearExtraInformation" value="false" />
      		   <property name="providers">
      				<list>
      					<beans:ref local="databaseAuthenticationProvider" />
      				</list>
      			</property>
      	  </bean>
        
      	  <bean id="databaseAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
      			<property name="userDetailsService" ref="userDetailsService" />
      			<property name="hideUserNotFoundExceptions" value="false" />      
      			<property name="saltSource" ref="saltSource" />
      			<property name="passwordEncoder" ref="passwordEncoder" />
      			
      	 </bean>
      Before calling A I am writing code for enabling/adding authorities for that user in database. I feel this is mandatory because for the next time the user logs in he has to get the new authorities by default.


      I don't know whether I am doing things correctly here or not.

      Now comming to what you have suggested.

      1.
      Assuming you are using the standard HttpSession storage of Spring Sec authentication information, you can just pull the UserDetails out of the session and manipulate it. The problem you will have is that the standard Authentication implementations ensure that the Collection returned by getAuthorities is non-modifiable, so you may have to do some custom coding.
      Can you please tell me How can I set a modified userdetails object back into the current session. Here am I missing any information related to Spring Security session attributes.

      2.
      Another option would simply be to reload the user's authorities when something changes. This might require a custom servlet filter which will be responsible for manipulation of the SecurityContext and active Authentication object. If you aren't familiar with this, I'd suggest looking at some of the source code for the standard filters first.
      What do you exactly mean by when something changes? Can you please tell me how to add authorities to active authentication object( By active I presume that you meant user is already authenticated and no need to supply username & password once again) ?


      I have searched a lot about my problem over the web. But nothing worked out for me. If you can help me on this issue, I would be greatly obliged and I am sure this post will help so many Spring Security users like me.


      Thanks,
      Vivek.

      Comment


      • #4
        If you need to load roles when user login its possible
        CustomAuthunticationManage is customized to load the roles from database .

        Code:
          --> 
        - <http entry-point-ref="myAuthenticationEntryPoint" session-fixation-protection="newSession">
        - <!-- add any of your cusotom url patterns to protect
          --> 
          <intercept-url pattern="/login.htm*" filters="none" /> 
          <intercept-url pattern="/css/**" filters="none" /> 
          <intercept-url pattern="/images/**" filters="none" /> 
          <intercept-url pattern="/**" access="ROLE_USER" /> 
          <logout logout-success-url="/login.htm" /> 
          <anonymous username="guest" granted-authority="ROLE_ANONYMOUS" /> 
          </http>
          <authentication-manager alias="authenticationManager" /> 
        - <!-- Cutom login filter which replaces the default AUTHENTICATION_PROCESSING_FILTER 
          --> 
        - <beans:bean id="myAuthenticationManager" class="spring.login.CustomAuthunticationManager">
          <beans:property name="lo" ref="authservice" /> 
          </beans:bean>
        - <beans:bean id="customizedFormLoginFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
          <custom-filter position="AUTHENTICATION_PROCESSING_FILTER" /> 
        - <!-- replace the default one
          --> 
          <beans:property name="defaultTargetUrl" value="/" /> 
        - <!-- After a successful login, the user will be taken to this page
          --> 
          <beans:property name="authenticationFailureUrl" value="/login.htm?login_error=1" /> 
        - <!-- Authentication failed? take him to error page
          --> 
          <beans:property name="authenticationManager" ref="myAuthenticationManager" /> 
        - <!-- Here it is the custom authenticationManager, login magic goes here 
          --> 
          <beans:property name="allowSessionCreation" value="true" /> 
        - <!-- Allow the application to create sessions
          --> 
          </beans:bean>
        - <!-- My custom auth manager
          --> 
        - <!--  Automatically receives AuthenticationEvent messages 
          --> 
          <beans:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener" /> 
        - <!-- My authuntication entry point, can be replaced easily if we are doing custom commence of invalid auths.
          --> 
        - <beans:bean id="myAuthenticationEntryPoint" class="spring.login.CustomAuthenticationEntryPoint">
          <beans:property name="loginFormUrl" value="/login.htm" /> 
          </beans:bean>
        - <!--     Usernames/Passwords are
                rod/koala
                dianne/emu
                scott/wombat
                peter/opal
            
          --> 
          </beans:beans>

        Comment


        • #5
          Hi Sony_notes,
          Thanks for your inputs in solving this issue. So I am assuming that instead of default authentication manager being injected into controller class you want me to inject custom authentication manager (like this . So there will be two authentication managers. I doubt whether this will work. But I will try this let you know.

          Comment


          • #6
            not two authentication manage , its just customize authentication manager so you can authenticate with ldap and take roles from rdbms.

            Comment


            • #7
              Hi Sony_notes,

              I am really confused when you mentioned the word LDAP. Can you mention briefly what you wanted me to do. If you write an algorithm then that will be really helpful.

              And, Can you please tell me on what circumstances will the method getCredentials() return null.

              Thanks,
              Vivek.

              Comment


              • #8
                <property name="eraseCredentialsAfterAuthentication" value="false" /> in applicationcontext-security.xml allowed me to retrieve the password. But My question is, is this the correct way to do?

                Comment


                • #9
                  Originally posted by vivek4348 View Post
                  I am working on Spring security now. What it does is while the user logs in, at that time only it loads all the authorities which belong to that user. So my question is How can we change(add/remove) the authorities of the user while in session.
                  The easiest option is to obtain the current Authentication and create a new instance of it and set it on the SecurityContextHolder as described in Setting the SecurityContextHolder Contents Directly. Be sure you understand the implications of acting upon the Authentication in multiple threads (read on in the reference to understand). An example of adding a GrantedAuthority to the current Authentication is given below:

                  Code:
                  // update database with new role
                  //... you fill in this part
                  
                  // update the current Authentication
                  Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                  List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities());
                  authorities.add(new GrantedAuthorityImpl('ROLE_NEWROLE'));
                  Authentication newAuth = new UsernamePasswordToken(auth.getPrincipal(),auth.getCredentials(),authorities)
                  SecurityContextHolder.getContext().setAuthentication(newAuth);
                  Originally posted by vivek4348 View Post
                  <property name="eraseCredentialsAfterAuthentication" value="false" /> in applicationcontext-security.xml allowed me to retrieve the password. But My question is, is this the correct way to do?
                  I'm not sure what getting the password has to do with your original question. However, if the passwords are hashed (in your case it sounds as though they are) there is no way to obtain the original password. Note that hashing (is one way and can't be undone) is different than encrypting (which can be decrypted). If you are unfamiliar with this, I would suggest Googling for "hash vs encryption" or something similar.

                  Cheers,

                  Comment


                  • #10
                    Thanks Rwinch for your response,
                    Code:
                    Authentication newAuth = new UsernamePasswordToken(auth.getPrincipal(),auth.getCredentials(),authorities)
                    The above line requires credentials of the user. And for the above line to work correctly,
                    Code:
                    <property name="eraseCredentialsAfterAuthentication" value="false" />
                    has to defined in applicationContext-Security.xml.

                    Otherwise getCredentials() method will return null.( Because in source code of the provider class, the constructor is setting this property as true.)

                    Anyways thanks all of you for taking time to solve this problem.

                    I really like the way Spring security works.

                    Thanks.
                    Vivek.

                    Comment


                    • #11
                      Originally posted by vivek4348 View Post
                      Otherwise getCredentials() method will return null
                      It should not matter that the credentials are null (unless you are doing something special). Spring Security does not care what the credentials are so long as the Authentication object is marked as authenticated and has the proper GrantedAuthority's.

                      Comment


                      • #12
                        Sorry, about that. May be I didn't test it properly initially. You are right!! As you said, we don't require to set eraseCredentialsAfterAuthentication property.

                        Thanks
                        Vivek.

                        Comment


                        • #13
                          Hi As mentioned on erlier mail if you can create custom authentication then whatever you need is able to do in the custom authenticaiton. If you customise user then you can update all information to the user.
                          following are example in custom authentication manage i hope it may work.
                          Code:
                          package spring.login;
                          
                          import org.apache.commons.lang.StringUtils;
                          import org.springframework.security.*;
                          import org.springframework.security.userdetails.User;
                          import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
                          
                          
                          
                          public class CustomAuthunticationManager implements AuthenticationManager {
                          
                           private  LDAPAuthentiatonService lo;
                          
                              public LoginAuthService getLo() {
                                  return lo;
                              }
                          
                              public void setLo(LoginAuthService lo) {
                                  this.lo = lo;
                              }
                          
                          
                              customuser usermanager;
                              GrantedAuthorityImpl authority = new GrantedAuthorityImpl("ROLE_USER");
                          	// able to get  authority from database too.
                              User cs = null;
                          
                              public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                          
                                  if (StringUtils.isBlank((String) authentication.getPrincipal()) || StringUtils.isBlank((String) authentication.getCredentials())) {
                          
                                      System.out.println("invalid cresen");
                                      throw new BadCredentialsException("Valid user name name and password needed");
                                  } else {
                          
                                      //System.out.println("credential :" + authentication.getCredentials());
                                      //System.out.println("princapial : " + authentication.getPrincipal());
                          
                                      String user = (String) authentication.getPrincipal();
                                      String password = (String) authentication.getCredentials();
                                     
                                     if (!lo.Connect(user,password))
                                      {
                                          System.out.print("thrw");
                                       throw new BadCredentialsException("Invalid username/password");
                          
                                      }
                                      else
                                      {
                                         cs = new User(lo.getUsername(), password, true, true, true, true, new GrantedAuthority[]{authority});
                                         // usermanager = new customuser(lo.getUsername(), password, true, true, true,  new GrantedAuthority[]{authority},lo.getUserinfo());
                                         // usermanager = new customuser(lo.getUserinfo().getFirstname() + " " + lo.getUserinfo().getLastname() + "( " + lo.getUserinfo().getEmpid() + " )", password, true, new GrantedAuthority[]{authority}, lo.getUserinfo());
                          
                                          
                                      }
                                      
                                      
                          
                          
                                  }
                          
                          
                                  // return authentication;
                          System.out.println("started session");
                          return new UsernamePasswordAuthenticationToken(cs, authentication.getCredentials(), new GrantedAuthority[]{authority});
                                 // return new UsernamePasswordAuthenticationToken(usermanager, authentication.getCredentials(), new GrantedAuthority[]{authority});
                          
                              }
                          }

                          Comment


                          • #14
                            Hi Sony_notes,
                            Yes this also works. Anyways thanks for your time to solve this problem.

                            Comment

                            Working...
                            X