Announcement Announcement Module
Collapse
No announcement yet.
Remember-Me Success Handler? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Remember-Me Success Handler?

    Hi,

    I'm using the <remember-me> namespace element to handle Remember Me login on my website and I've come to a problem.

    Once authentication succeeds I would like to add a Role based on the IP address of the Request, it doesn't seem possible to add a success handler like you do with the <form-login> namespace element.

    I can see a couple of things I could do to achieve this but wondered what would be the "best" approach.

    Option 1:
    Extend the RememberMeAuthenticationProvider and override the authenticate method. I can read the IP address from the Authentication object which is of type RememberMeAuthenticationToken; it contains WebAuthenticationDetails.

    Option 2:
    Extend the RememberMeAuthenticationFilter class and override the onSuccessfulAuthentication method. The IP address can be read from the HttpServletRequest. (The Authenication result is also avialable at this point).

    The Filter has an empty implementation of onSuccessfulAuthentication - is that a hint that Option 2 is the right one?

    Also, will I have to define all the beans required for Remember Me if I implement a custom filter? Or can I still use the <remember-me> namespace such that it will use my custom filter and wire everything else it needs itself?

  • #2
    Ah, it looks like by the time either of those options above has the Authentication object the authorites is an unmodifiable list.

    So Option 3: create a custom RememberMeService

    Comment


    • #3
      Originally posted by C0re View Post
      Also, will I have to define all the beans required for Remember Me if I implement a custom filter? Or can I still use the <remember-me> namespace such that it will use my custom filter and wire everything else it needs itself?
      Seems I'll have to define all the required beans myself, cannot combine the two approaches.

      Comment


      • #4
        Is there anyway you can post your xml for a custom RememberMeService? I am trying to write my own custom RememberMeService as well but I am having trouble. Everything boots up correctly for my web app (no errors from Spring), but no cookie is being created when the user logs in. I would love to follow an example and can't seem to find one. I am using Spring Sec 3.0.x. Here what I have so far...

        Code:
        	<http auto-config="false" use-expressions="true">
        	
        		<intercept-url pattern="/app/**" access="isAuthenticated()"/>	
        		<intercept-url pattern="/**" access="permitAll" />
        		
        		<form-login always-use-default-target="true" 
        			default-target-url="/app/Dashboard_show.action" 
        			login-page="/login.jsp"
        			authentication-failure-url="/login.jsp?error=1"/>
        			
        		<logout logout-success-url="/login.jsp"/>
        		     
        		<session-management invalid-session-url="/expiredSession.jsp?error=2">
        			<concurrency-control max-sessions="1"
        				error-if-maximum-exceeded="false"
        				expired-url="/expiredSession.jsp?error=3"/>		
        		</session-management>
        	
        		<!-- Set Custom Remember Me Filter -->
        		<custom-filter position="REMEMBER_ME_FILTER " ref="myRememberMeAuthenticationFilter" />
        
        	</http>
        
        	<!-- Declare custom remember-me filter which extends Spring Sec class-->
        	<beans:bean id="myRememberMeAuthenticationFilter" class="com.afs.web.filter.MyRememberMeAuthenticationFilter">
        		<beans:property name="authenticationManager" ref="authenticationManager"/>
        		<beans:property name="rememberMeServices" ref="tokenBasedRememberMeServices"/>
        		<beans:property name="defaultTargetUrl" value="/expiredSession.jsp?error=1"/>
        	</beans:bean>
                <!-- Use cookie based remember-me -->
        	<beans:bean id="tokenBasedRememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
        		<beans:property name="key" value="xyz"/>
        		<beans:property name="tokenValiditySeconds" value="2592000"/>  <!-- expiration time = 30 days -->
        		<beans:property name="userDetailsService" ref="userService"/>
        	</beans:bean>
        
        	<!-- Set password encoder to spring  -->
        	<beans:bean id="passwordEncoderBean" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
        		<beans:constructor-arg value="256" />
        	</beans:bean>
            
            <!-- Set Authentication Manager -->
            <authentication-manager alias="authenticationManager">
        	    <authentication-provider>
        		  	<jdbc-user-service id="userService" data-source-ref="dataSource" 
        		       	users-by-username-query="select UserName as username, PasswordHash as password, IsActive from AppUser where UserName=?"
        		       	authorities-by-username-query="select appUser.UserName, teamRole.TeamRole from AppUser appUser, 
        		        	TeamRole teamRole where appUser.UserName=? and appUser.AppUserId=teamRole.AppUserId" />
        			<password-encoder ref="passwordEncoderBean">
        				<salt-source user-property="username"/>
        			</password-encoder>
        	    </authentication-provider>
            </authentication-manager>
        Any help would be greatly appreciated!

        Comment


        • #5
          Originally posted by burtonrhodes View Post
          Is there anyway you can post your xml for a custom RememberMeService? I am trying to write my own custom RememberMeService as well but I am having trouble. Everything boots up correctly for my web app (no errors from Spring), but no cookie is being created when the user logs in. I would love to follow an example and can't seem to find one. I am using Spring Sec 3.0.x. Here what I have so far...

          Code:
          	snip
          Any help would be greatly appreciated!
          Does your filter even get called? Is it in the filter chain in the correct position? From what I've read the remember me filter should be directly after the usernamepassword authentication filter, thus in my <http> element I have:

          Code:
          <custom-filter ref="myRememberMeFilter" after="FORM_LOGIN_FILTER"/>

          Comment


          • #6
            Just figured out a cleaner way of adding your own custom Remember Me Service, without having to define the beans for the filter etc.

            Code:
            <http>
                <remember-me services-ref="myRememberMeServices" key="aKey" />
            </http>
            
            <beans:bean id="myRememberMeServices" class="com.f1000.web.security.spring.TokenBasedRememberMeCustomServices">
                <beans:property name="userDetailsService" ref="userSecurityDetailsService"/>
                <beans:property name="key" value="aKey"/>
            </beans:bean>
            This still doesn't help with my original problem.

            The UsernamePasswordAuthenticationFilter will call AuthenticationSuccessHandler.onAuthenticationSucce ss when authentication has been succesful.

            I want to use the same success handler for when TokenBasedRememberMeServices.autoLogin creates a valid Authentication object.

            Ideas?

            Comment


            • #7
              This may help.... For me I wanted to add an "isRememberMe" flag to the session when the user the successfully authenticated via RememberMeServices so I could show a redirect page when this happened. I used your method of just replacing the "services-ref" field in the <remember-me/> tag. I then added additional code to the createSuccessfulAuthentication() method. The tricky part for me was to make sure you set the "key" value to BOTH the <remember-me/> tag and in the "myTokenBasedRememberMeServices" class.

              Hope this helps. This should allow you to "do stuff" when a user logs in successfully using RememberMeServices....

              Code:
              	<http use-expressions="true">
              	
              		<intercept-url pattern="/app/**" access="isAuthenticated()"/>	
              		<intercept-url pattern="/**" access="permitAll" />
              		
              		<form-login always-use-default-target="true" 
              			default-target-url="/app/Dashboard_show.action" 
              			login-page="/login.jsp"
              			authentication-failure-url="/login.jsp?error=1"/>
              			
              		<logout logout-success-url="/login.jsp"/>
              		     
              		<session-management invalid-session-url="/expiredSession.jsp?error=2">
              			<concurrency-control max-sessions="1"
              				error-if-maximum-exceeded="false"
              				expired-url="/expiredSession.jsp?error=3"/>		
              		</session-management>
              	
              		<!-- Override existing RememberMeServices -->
              		<remember-me key="xyz" services-ref="myTokenBasedRememberMeServices"/>
              
              	</http>
              
              	<!-- My RememberMeServices -->
              	<beans:bean id="myTokenBasedRememberMeServices" class="com.afs.web.filter.MyTokenBasedRememberMeServices">
              		<beans:property name="key" value="xyz"/>
              		<beans:property name="tokenValiditySeconds" value="2592000"/>
              		<beans:property name="userDetailsService" ref="userService"/>
              	</beans:bean>
              Code:
              public class MyTokenBasedRememberMeServices extends TokenBasedRememberMeServices {
              
              	@Override
                  protected Authentication createSuccessfulAuthentication(HttpServletRequest request, UserDetails user) {
              				
              		// Set a isRememberMe flag so that the app knows the user was authenticated via 
              		request.getSession().setAttribute("isRememberMe", true);		
                                       // Run the rest of the method
              		return super.createSuccessfulAuthentication(request, user);
              	}
              
              }

              Comment


              • #8
                Originally posted by burtonrhodes View Post
                This may help.... For me I wanted to add an "isRememberMe" flag to the session when the user the successfully authenticated via RememberMeServices so I could show a redirect page when this happened. I used your method of just replacing the "services-ref" field in the <remember-me/> tag. I then added additional code to the createSuccessfulAuthentication() method. The tricky part for me was to make sure you set the "key" value to BOTH the <remember-me/> tag and in the "myTokenBasedRememberMeServices" class.

                Hope this helps. This should allow you to "do stuff" when a user logs in successfully using RememberMeServices....

                Code:
                	snip
                Thanks for the reply, I've implemented that also but it's not fully what I want. The UsernamePasswordAuthenticationFilter calls successHandler.onAuthenticationSuccess(request, response, authResult) when a valid Authentication object exists, I effectively want to call the same successHandler when the RememberMeFilter creates a valid Authentication object - sounds simple enough, but I've not been able to find a nice way to do it....yet!

                Comment


                • #9
                  What if you did exactly what I did and set a 'rememberme' flag in the session for the createSuccessfulAuthentication method? That way you could check to see if remember me has been run and have this in your onAuthenticationSuccess method (pseudo code):

                  If (session.get('rememberMe')==true) {
                  // Do stuff

                  // Clear flag
                  session.put('rememberMe', false);
                  }

                  Have no idea if this would work, but its the best I can think of at the moment.

                  Comment


                  • #10
                    I've got there in the end. I basically ditched the XML Namespace elements for form-login, logout and remember me and defined all the required beans, using my custom implementations where I needed them.

                    I was trying to do as little typing as possible. The XML Namespace elements are great for typical case use however.

                    Comment


                    • #11
                      Great!

                      @burtonrhodes: Your sample helpped me a lot! Thans!
                      Code:
                       ...
                       request.getSession().setAttribute("isRememberMe", true);
                       ...
                      And with this code I got attribute in myAuthenticationProvider:
                      Code:
                              ...
                              ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                              Boolean isRememberMe = (Boolean) attr.getAttribute("isRememberMe", ServletRequestAttributes.SCOPE_SESSION);     
                              ...

                      Comment

                      Working...
                      X