Announcement Announcement Module
Collapse
No announcement yet.
Authentication Fails when PasswordEncoder is being used. Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Authentication Fails when PasswordEncoder is being used.

    All,

    I have setup Acegi to use form based authentication. The password encoder is declared and set on my DaoAuthenticationProvider. When I enter the username and password and try to login, it always fails. When I unset the password encoder, it logs in fine.

    I also created a PasswordHelper class that I used when enrolling users. This encryps the password before it gets stored into the database. This works fine. I can optionally set this on the enrollment form so that If I don't want encrypted password, I don't need them.

    Enrollment with encrypted passwords works fine. I can not, however, login after the user gets created.

    Here is what is in my acegiContext.xml (the relevent parts):
    <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthe nticationProvider">
    <property name="authenticationDao"><ref local="customAuthenticationDao" /></property>
    <property name="userCache"><ref local="userCache"/></property>
    <property name="passwordEncoder"><ref local="passwordEncoder" /></property>
    </bean>

    <bean id="passwordEncoder" class="net.sf.acegisecurity.providers.encoding.Sha PasswordEncoder" />

    Here is what is in my hibernateTest-servlet.xml
    <bean id="enrollFormWizard" class="org.dmfrey.app.mvc.forms.controllers.enroll .EnrollFormWizardController">
    <property name="sessionForm"><value>true</value></property>
    <property name="commandName"><value>command</value></property>
    <property name="commandClass"><value>org.dmfrey.app.mvc.form s.commands.enroll.EnrollCommand</value></property>
    <property name="pages">
    <list>
    <value>enrollView</value>
    <value>enrollUserInfoView</value>
    <value>enrollUserIdView</value>
    <value>enrollConfirmView</value>
    </list>
    </property>
    <property name="userManager"><ref bean="userManager" /></property>
    <property name="successView"><value>enrollSuccessView</value></property>
    <property name="cancelView"><value>welcomeView</value></property>
    <property name="passwordHelper"><ref bean="passwordHelper" /></property>
    </bean>

    <bean id="passwordHelper" class="org.dmfrey.app.mvc.security.PasswordHelper" >
    <property name="passwordEncoder"><ref bean="passwordEncoder" /></property>
    </bean>


    So, to recap. During Enrollment, passwords, optionally, encrypted and stored in the database. The login fails when when the passwordEncoder is set on the authenticationDao.

    Any help would be greatly appreciated.

    Dan

  • #2
    It's probably a subtle issue to do with SALT handling. Are you passing a SALT to encodePassword(String rawPass, Object salt)? If so, you must ensure that same SALT will be used by DaoAuthenticationProvider by setting its saltSource property. If you're passing null to encodePassword you should not have a saltSouce property set on DaoAuthenticationProvider.

    Is the issue a database related one? For example is your database dropping the last characters of the encoded password?

    I a little concerned about giving users the choice to encode passwords. To support that will be difficult, as DaoAuthenticationProvider must use one PasswordEncoder or the other. The PasswordEncoder doesn't have access to the UserDetails so it can't decide the format and delegate appropriately. If you really must support this use case, you'll need to to override DaoAuthenticationProvider.isPasswordCorrect(Authen tication, UserDetails) and delegate to the appropriate PasswordEncoder.

    Comment


    • #3
      Ben,

      Thanks for the response. I had my database field size set too small, so it was truncating the encoded value.

      In your response you mentioned the salt source. I think using the salt is a good idea. I decided to look at the reflection salt source. This requires a user object in order to retrieve the salt. When creating an enrollment wizard, you are public and don't have a user. Is this as simple as creating a new user, even though it will never be used or stored, just to create a salt? Or, should there be some other way to retrieve the salt. The same applies to the system wide salt, you still need a user object to obtain a salt.

      In the system that I am working on, I am using Hibernate, Spring and Acegi. I have an object called UserInfo, that maps to the user_info table. The UserInfo object contains a Hibernate Component that identifies the userid, password, enabled/disabled status and a set of roles the user can see. I chose to make this a Component, first off to eliminate the need for a second table to hold user login information. Second, the users login information is only relevent to the website and not the overall business model of the application I am trying to write.

      Enrollment is a simple as collecting the user's information and making an entry in the database. Enrollment should not requre an instance of a UserDetails object, especially since you are still in the public domain during enrollment, not in an area secured by Acegi. I am already coupling my enrollment process to Acegi for by requiring the Acegi password encoder. This is an optional piece, so I do not need to supply the password encoder if one client wants encrypted passwords and another does not.

      I would be interested to hear your thoughts on this. Did I go about performing enrollment in the wrong manner? Is there are perfered way to perform enrollment that best utilizes Acegi?

      Thanks again,
      Dan

      Comment


      • #4
        I always create a new dedicated "salt" property on my Party/User/Person/Organization (as applicable to the particular application). I just use a random number usually. Thus I can have my domain object itself create the random number at construction time (Hibernate can still do a setSalt(int) to change it to the correct value). Then you can use encodePassword(String rawPass, domainObject.getSalt()).

        HTH

        Comment


        • #5
          Would login name be an equally suitable salt (if login names are not changeable in our application). Or since its something that may be known externally, it makes dictionary attacks easier compared to using a randomly generated salt.

          Are they any other desirable properties of a salt other that it having a stable value?

          Comment


          • #6
            If your logon name is never ever ever ever :P going to change it would be an acceptable salt. Be sure to lowercase the login name or something before using it as a salt though. Differences in case will of course mess everything up.

            The salt doesn't help prevent any sort of external attack. What it does prevent is all your hashed passwords from looking the same in the database. Without a salt, 10 users with the same password will all have the same hash, if that hash is salted they will all be different.

            Comment


            • #7
              Authentication failed with password encryption

              I'm using ACEGI 1.0.3, the authentication process works fine if I don't encrypt password but once I used password encryption the authentication fails with 'Bad Credentials'. There is no database problem and also I'm using the same SALT and MD5PasswordEncoder for encrypting the password in the database. The acegi daoAuthenticationProvider is configured as follows -


              <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenti cationProvider">
              <property name="userDetailsService" ref="userDetailsService"/>
              <property name="passwordEncoder"><ref bean="passwordEncoder"/></property>
              <property name="saltSource"><ref bean="saltSource"/></property>
              <property name="userCache">
              <bean class="org.acegisecurity.providers.dao.cache.EhCac heBasedUserCache">
              <property name="cache">
              <bean class="org.springframework.cache.ehcache.EhCacheFa ctoryBean">
              <property name="cacheManager">
              <bean class="org.springframework.cache.ehcache.EhCacheMa nagerFactoryBean"/>
              </property>
              <property name="cacheName" value="userCache"/>
              </bean>
              </property>
              </bean>
              </property>
              </bean>

              <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5Pas swordEncoder">
              </bean>

              <bean id="saltSource" class="org.acegisecurity.providers.dao.salt.System WideSaltSource">
              <property name="systemWideSalt"><value>12345</value></property>
              </bean>


              Any help would be highly appreciated. Thank you very much in advance.
              Regards,
              Sagol

              Comment


              • #8
                I guess the main thing here is to ensure the same encoder is being used to set the passwords in the database and then to authenticate. You could write a simple test case to retrieve the user and check his password.
                Last edited by karldmoore; Aug 29th, 2007, 12:25 PM.

                Comment


                • #9
                  Yes here lies the problem in fact. What I did is - I extended DaoAuthenticationProvider and debugged using the DaoAuthenticationProvider.additionalAuthentication Checks method. To my surprise I found that the followings -

                  1. I used the same MD5PasswordEncoder and SystemWideSaltSource beans defined in the application context and passed to the DaoAuthenticationProvider to encrypt the passwords in the database.

                  2. The encrypted password that returned from UserDetails object within DaoAuthenticationProvider.additionalAuthentication Checks method is different from the encrypted password I encrypted from the password/credential in the authentication object within the same method using the same encoder and salt. When I see printing out the salt string - is the same as I passed from the application context.

                  3. If I remove the saltSource from passing to the DaoAuthenticationProvider and passing null to the database password encryption, then the above point 2 is wrong, means the two generated and encrypted passwords are the same - meaning that the authentication succeeds if I don't use a salt.

                  I'm confused how the salt can change while I'm using the same encoder and salt source? Can you throw me some more light on this?

                  Thanks,
                  Sagol

                  Comment


                  • #10
                    I'm slightly confused about the chain of events here. You encode the password for a user and save it in the database. If you use PasswordEncoder.isPasswordValid(..) is it successful? You shouldn't need to change any Acegi code to enable this, just simply inject the PasswordEncoder and Salt. If you debug the Dao that retrieves the User is the password as expected?
                    Last edited by karldmoore; Aug 29th, 2007, 12:25 PM.

                    Comment


                    • #11
                      The password returned (encrypted) from the userdetails object is as expected, the one stored in the database. the PasswordEncoder.isPasswordValid(..) fails; when I incrypt the raw password from the authentication object using the same encoder and salt, the outcome is different from the one in the userdetails object.

                      But I'm using the same encoder and salt for password encryption and authentication through spring injection, how can the salt be changed? As I mentioned, everything work fine if I don't use a salt. Any clue?

                      Comment


                      • #12
                        Ok, it all works if you don't use the salt. If you look at the SystemWideSaltSource code, all it does is hold a String....... that's it. I don't see how that can break your code. The only thing I can think is going wrong is that the password in the database isn't encoded with the salt. I'm presuming you have some code like the one below and you are injecting in the same passwordEncoder and saltSource. Other than that I'm at a loss, I can't see why it wouldn't work. Could you post your applicationContext.xml and the code that you've written for this?

                        Code:
                        public class MyClass {
                            private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
                            private SaltSource saltSource;
                        
                            public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
                                this.passwordEncoder = passwordEncoder;
                            }
                        
                            public void setSaltSource(SaltSource saltSource) {
                                this.saltSource = saltSource;
                            }
                        
                            public String encode(String toEncode) {
                                Object salt = null;
                                if (this.saltSource != null) {
                                    salt = this.saltSource.getSalt(userDetails);
                                }
                                this.passwordEncoder.encodePassword(toEncode, saltSource);
                            }
                        }
                        http://www.acegisecurity.org/multipr...altSource.html
                        Last edited by karldmoore; Aug 29th, 2007, 12:25 PM.

                        Comment


                        • #13
                          Did you end up solving this? I'd be interested to find out!
                          Last edited by karldmoore; Aug 29th, 2007, 12:25 PM.

                          Comment


                          • #14
                            I've seemed to run into this same issue also.

                            It seems the that salt used in salting the password is coming from SystemWideSaltSource.toString()

                            from BasePasswordEncoder.mergePasswordAndSalt():

                            if ((salt == null) || "".equals(salt)) {
                            return password;
                            } else {
                            return password + "{" + salt.toString() + "}";
                            }

                            Since SystemWideSaltSource has no implementation for toString() the resultant String has the object's hashcode which is not guaranteed to be the same between invocations of the JVM.

                            -db

                            Comment


                            • #15
                              I don't follow your thinking. There is difference between salt and saltSource. If you look at the code sample I posted, you ask the saltSource for the salt. For SystemWideSaltSource.getSalt(..) this is going to return the same value everytime. This is the thing that is passed into the encoder and is toString'd.
                              Last edited by karldmoore; Aug 29th, 2007, 12:24 PM.

                              Comment

                              Working...
                              X