Announcement Announcement Module
Collapse
No announcement yet.
login by code Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • login by code

    Hi,

    I am attempting to perform login and logout programmatically, the following twp routines seems to be working:

    Code:
    public class SecurityService {
    
        private final AuthenticationManager mAuthManager;
    
        public int login(String username, String password, String remoteAddr, HttpSession session) {
            if (session != null) {
                session.removeAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY);
                session.removeAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY);
            }
            AuthenticationException authEx;
            try {
                UsernamePasswordAuthenticationToken upat = new UsernamePasswordAuthenticationToken(username, password);
                upat.setDetails(remoteAddr);
                Authentication auth = mAuthManager.authenticate(upat);
                if (session != null)
                    session.setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY, auth);
                Context c = ContextHolder.getContext();
                if (c instanceof SecureContext) ((SecureContext)c).setAuthentication(auth);
                return LOGIN_SUCCESS;
            }
            catch (AuthenticationException e) {
            log.info("Authentication request failed: " + e);
            if (session != null)
                session.setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, authEx);
                return -1;
            }
        }
    
        public void logout(HttpSession session) {
            if (session != null) session.invalidate();
            Context c = ContextHolder.getContext();
            if (c instanceof SecureContext) ((SecureContext)c).setAuthentication(null);
        }
    
    }
    Can any guru glance it over for any potential problem ? thanx.

    -cs

  • #2
    You don't need to work with the HttpSession at all - only ContextHolder.

    The HttpSession will be refreshed automatically via the HttpSessionIntegrationFilter. Do a search in the forums or read its JavaDocs or the reference guide for more details.

    Comment


    • #3
      Originally posted by Ben Alex
      You don't need to work with the HttpSession at all - only ContextHolder.

      The HttpSession will be refreshed automatically via the HttpSessionIntegrationFilter. Do a search in the forums or read its JavaDocs or the reference guide for more details.
      Does this means for the login, I would do this (without the session handling code):

      Code:
                  Authentication auth = mAuthManager.authenticate(upat);
                  Context c = ContextHolder.getContext();
                  if (c instanceof SecureContext) ((SecureContext)c).setAuthentication(auth);
      What happens if Context c is null, or not a SecureContext ? Or is it that Context c will always be present and an instanceof SecureContext ? Or I should do a ContextHolder.setContext() instead ?

      Thanx.

      -cs

      Comment


      • #4
        Unable to login after removing the session.setAttribute() code... hmm...

        Does the interceptor copies auth from session to context or from context to session ?

        -cs

        Comment


        • #5
          See http://forum.springframework.org/showthread.php?t=10530
          Last edited by robyn; May 19th, 2006, 05:05 AM.

          Comment


          • #6
            Hey,

            i just tried the programmatic authentication. Im using DAO based authentication with the MD5 password encoder. After registration the user gets a email with a verification ticket. Then klicking on the link with the ticket, the enrollment completes and the user gets logged in.

            It basically works, but there is a problem with the encoded password. After I do a login programmatically like this:

            Code:
            	private void login(User user, HttpServletRequest request) {
            		UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword());
            
            		auth.setAuthenticated(true);
            		auth.setDetails(request.getRemoteAddr());
            		auth.setAuthorities(user.getAuthorities());
            
            		Context c = ContextHolder.getContext();
                        if (c instanceof SecureContext) ((SecureContext)c).setAuthentication(auth);
            
            	}
            The authentication works till the next request. Then i get a worng password error and the login dialog pops up. DaoAuthenticationProvider seems to encode the password _again_ and then check against the already encoded password.

            The problem is that i don't know the plain password at this stage.

            Any quick hints how to get around this?

            The only solution I see now is writing my own DaoAuthenticationProvider that can detect wether a password is encoded or not and act accordingly (use password encoder or not). I don't like to use plain passwords in the database at all.

            Ideas?

            l8er
            -andi

            PS: I suspect the same problem would occur if I (optionally) encode the password on the client side (via javascript) and send the encoded password over the net.

            Comment


            • #7
              Originally posted by thyrell
              PS: I suspect the same problem would occur if I (optionally) encode the password on the client side (via javascript) and send the encoded password over the net.
              Would that defeat the whole purpose of encoding in the first place? Because a hacked database could then be used to send a HTTP request containing the hashed code as it was stored in the database. No knowledge of the cleartext password would ever be needed.

              Back to your enrollment question, I think your easiest solution is for your MVC controller that validates the signup ticket should place a unique Authentication instance on the ContextHolder, say an AutomatedSignInAuthenticationToken. There would be a corresponding AutomatedSignInAuthenticationProvider which can recognise the token and treat it as valid, populating the GrantedAuthority[]s and user details from the same AuthenticationDao as was used by DaoAuthenticationProvider for normal, interactive authentication attempts. The benefit of this model is your AutomatedSignInAuthenticationToken can extend from say RememberMeAuthenticationToken, which the net.sf.acegisecurity.AuthenticationTrustResolverIm pl will immediately recognise as being some sort of of remember-me-like token. This can be helpful if you wish your AccessDecisionManager to throw an InsufficientAuthenticationException for certain high-security operations (instead of a standard AccessDeniedException).

              Comment


              • #8
                Hi Ben,

                thanks for your kind help.

                >> MD5 clientside >>
                Would that defeat the whole purpose of encoding in the first place?
                Of course, you are absolutely right about this. Makes nullifies encoding in the database. Sometimes I don't think before i write

                Ok, so you suggest using the remember-me support, basically? But do I need to create the extra provider? In my EnrollmentController the User object (implements UserDetails) is already loaded. So what I need is that I can put my principal on the context, marked as authenticated and that's it.

                Can't I just put a RememberMeToken on the context and set-up the remember me services like described in the docs?:

                Code:
                private void login(User user, HttpServletRequest request) { 
                      RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken("springRocks", user, user.getAuthorities()); 
                
                      auth.setAuthenticated(true); 
                
                      Context c = ContextHolder.getContext(); 
                            if (c instanceof SecureContext) ((SecureContext)c).setAuthentication(auth); 
                
                   }
                Code:
                <bean id="rememberMeProcessingFilter" class="net.sf.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
                  <property name="rememberMeServices"><ref local="rememberMeServices"/></property>
                </bean>
                
                <bean id="rememberMeServices" class="net.sf.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
                  <property name="authenticationDao"><ref local="myDao"/></property>
                  <property name="key"><value>springRocks</value></property>
                </bean>
                   
                <bean id="rememberMeAuthenticationProvider" class="net.sf.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
                  <property name="key"><value>springRocks</value></property>
                </bean>
                I'm suprised that nobody had that problem before. This auto-sign in after password-change (or verified enrollment( adds much to user-friendlyness of a site.


                -andi

                Comment


                • #9
                  Originally posted by thyrell
                  Can't I just put a RememberMeToken on the context and set-up the remember me services like described in the docs?
                  Indeed you can. That sounds a lot simpler to me than writing another provider.

                  Comment


                  • #10
                    Hi Ben,

                    ... and it works perfectly fine Thanks a lot for lining it out.

                    -andi

                    Comment


                    • #11
                      Update for Spring 2.5

                      I apologize for resurrecting a thread that's over three years old now, but this is the only thread I saw for this particular topic (programmatic login after a user self-registration) and there's an update for Spring 2.5. The technique described still works just fine, but "Context" has become "SecurityContext" and "ContextHolder" has become "SecurityContextHolder". (Both in package org.acegisecurity.context.) Everything else is the same. So here is the code that I used:

                      Code:
                      UsernamePasswordAuthenticationToken upat =
                          new UsernamePasswordAuthenticationToken(username, password);
                      Authentication auth = authMgr.authenticate(upat);
                      SecurityContext ctx = SecurityContextHolder.getContext();
                      ctx.setAuthentication(auth);
                      Hope somebody finds that useful.

                      Comment


                      • #12
                        Spring 2.5? These changes were made in Acegi Security 0.9

                        http://acegisecurity.org/upgrade/upgrade-080-090.html

                        :-)

                        Comment


                        • #13
                          Has anything else been updated in the last several years to make this extremely common signup verification and forgotten password technique easier to implement with ACEGI?

                          Comment


                          • #14
                            An other way to bypass double encoding is simply to change it just before login

                            Code:
                            DaoAuthenticationProvider daoProvider = ((DaoAuthenticationProvider)SpringApplicationContext.getBean("daoAuthenticationProvider"));
                            daoProvider.setPasswordEncoder((PasswordEncoder)SpringApplicationContext.getBean("plainTextPasswordEncoder"));
                            daoProvider.setSaltSource(null);
                            and then reactive it :

                            Code:
                            daoProvider.setPasswordEncoder((PasswordEncoder)SpringApplicationContext.getBean("md5PasswordEncoder"));
                            daoProvider.setSaltSource((SaltSource)SpringApplicationContext.getBean("reflectionSaltSource"));

                            Comment

                            Working...
                            X