Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: ShaPasswordEncoder - Authentication problem

  1. #1
    Join Date
    May 2012
    Posts
    15

    Default ShaPasswordEncoder - Authentication problem

    Hi,

    I am taking a hands-on approach to Spring Security by trying to implement it on a website that I am creating. I have successfully managed to:

    - login with the default login form
    - login with my own login form (and logout too!)
    - login using credentials stored in database (plaintext)

    ...but I have got stuck with trying to login using encryption. Here are the relevant code snippets:

    spring-security.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans:beans xmlns="http://www.springframework.org/schema/security"
    	xmlns:beans="http://www.springframework.org/schema/beans" 
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    	http://www.springframework.org/schema/security
    	http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
     
    	<http auto-config="true">
    		<intercept-url pattern="/login.htm" access="ROLE_ANONYMOUS" />
    		<intercept-url pattern="/logout.htm" access="ROLE_ANONYMOUS" />
    		<intercept-url pattern="/resources/**" filters="none" />
    		<intercept-url pattern="/**" access="ROLE_USER" />
    		<form-login login-page="/login.htm" default-target-url="/home.htm" authentication-failure-url="/login.htm?error=true" />
    		<logout logout-success-url="/logout.htm" />
    	</http>
     
    	<authentication-manager>
    	  <authentication-provider>
    	  	<!--<password-encoder hash="sha"/>-->
    	  	<password-encoder base64="true" ref="passwordEncoder"/>
    	  	
    	  	<jdbc-user-service data-source-ref="dataSource"
    	  		users-by-username-query="select USER_NAME, PASSWORD, ENABLED from apphub.users where USER_NAME=?"
    	  		authorities-by-username-query="select u.USER_NAME, ur.AUTHORITY from apphub.users u, apphub.user_roles ur where u.USER_ID = ur.USER_ID and u.USER_NAME=?" 
    		/>	    
    	  </authentication-provider>
    	</authentication-manager>
    	
    </beans:beans>


    <app_name>-servlet.xml
    Code:
        <!-- Start: Datasources -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/apphub" />
    		<property name="username" value="root" />
    		<property name="password" value="password" />
       	</bean>
       	<!-- End: Datasources -->
       	
       	
       	
       	<!-- Start: Password Encoder -->
       	<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
       	
       	<bean class="com.classifieds.security.DatabaseBootstrapPasswordEncoder" init-method="secureDatabase" depends-on="dataSource">
      		<property name="dataSource" ref="dataSource" />
      		<property name="passwordEncoder" ref="passwordEncoder" />
      	</bean>
       	<!-- End: Password Encoder -->
                
    </beans>

    DatabaseBootstrapPasswordEncoder.java
    Code:
    package com.classifieds.security;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.jdbc.core.RowCallbackHandler;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    import org.springframework.security.authentication.encoding.PasswordEncoder;
    
    
    /**
     * A class, which will encode the bootstrap passwords loaded via SQL. 
     * 
     * NB: the application assumes a number of accounts will have been set up in the database
     * using a SQL script. These are considered 'bootstrap' accounts and the passwords for 
     * these accounts will appear in the database in plain-text. The purpose of this class is
     * to encode the plain-text passwords of the bootstrap accounts. The class executes an init 
     * method, which is invoked after the embedded-database bean is instantiated.
     * 
     * @author Dan.Mortimer
     */
    public class DatabaseBootstrapPasswordEncoder extends JdbcDaoSupport {
    	private PasswordEncoder passwordEncoder;
    	
    	private final Log logger = LogFactory.getLog(getClass());
    
    	/**
    	 * @param passwordEncoder the passwordEncoder to set
    	 */
    	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
    		this.passwordEncoder = passwordEncoder;
    	}
    	
    	/**
    	 * The init method, which is invoked after the embedded-database bean is instantiated.
    	 * Spring JdbcTemplate functionality is used to loop through all the users in the database 
    	 * and encode the password using the injected PasswordEncoder reference. Each password is 
    	 * updated individually.
    	 */
    	public void secureDatabase() {
    	    getJdbcTemplate().query("select USER_NAME, PASSWORD from apphub.users",
    	                             new RowCallbackHandler() {
    	      public void processRow(ResultSet rs) throws SQLException {
    	    	  String username = rs.getString(1);
    	          String password = rs.getString(2);
    	          
    	          String encodedPassword = passwordEncoder.encodePassword(password, null);
    	          
    	          getJdbcTemplate().update("update apphub.users set PASSWORD = ? where USER_NAME = ?", encodedPassword, username);
    	          
    	          logger.info("Updating password for username:" + username + " to:" + encodedPassword);
    	      }
    	    });
    	}
    }
    I have turned up the logging for Spring and I can see the following error:

    2012-07-23 14:05:40,125 DaoAuthenticationProvider [DEBUG] Authentication failed: password does not match stored value

    The problem is that the password I get directly out of the database DOES match with what gets created in the java class. So I cannot understand what is going wrong.

    I'd be very grateful for some advice, please!

  2. #2
    Join Date
    Mar 2007
    Posts
    561

    Default

    <password-encoder base64="true" ref="passwordEncoder"/>

    I think you have now one encoder with hex and one with base64 encoding.

  3. #3
    Join Date
    May 2012
    Posts
    15

    Default

    Hi spgmx,

    Thanks for getting in touch!

    Is there any way you could shed a little more light on this one for me please...? I'll keep digging around in the meantime!

    Thanks!

  4. #4
    Join Date
    May 2012
    Posts
    15

    Default

    Hi,

    I have struggled with this one some more, but I am still getting the same problem. Here's the change...

    <app_name>-servlet.xml
    Code:
    <!-- Start: Datasources -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/apphub" />
    		<property name="username" value="root" />
    		<property name="password" value="password" />
       	</bean>
       	<!-- End: Datasources -->
       	
       	
       	
       	<!-- Start: Password Encoder -->
       	<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder">
       		<property name="encodeHashAsBase64">
      			<value>false</value>
      		</property>
       	</bean>
       	
       	<bean class="com.classifieds.security.DatabaseBootstrapPasswordEncoder" init-method="secureDatabase" depends-on="dataSource">
      		<property name="dataSource" ref="dataSource" />
      		<property name="passwordEncoder" ref="passwordEncoder" />
      	</bean>
       	<!-- End: Password Encoder -->
    As you can see, I have tried to specify the value for the encodeHashAsBase64 property. This has not allowed me to login successfully.

    With Spring Logging turned up, I still get:

    2012-07-24 11:51:47,059 DaoAuthenticationProvider [DEBUG] Authentication failed: password does not match stored value

    I'd be very grateful for a bit more assistance with this one, please...

    Cheers!

  5. #5
    Join Date
    Mar 2007
    Posts
    561

    Default

    Ähm...

    <password-encoder base64="true" ref="passwordEncoder"/>

    vs.

    <property name="encodeHashAsBase64">
    <value>false</value>
    </property>

  6. #6
    Join Date
    May 2012
    Posts
    15

    Default

    Hi spgmx,

    Thanks for posting another reply...

    Apologies - I didn't post my other config file, did I?

    I can assure you that I have actually:
    - set both the fields you have highlighted to false and I cannot login
    - set both the fields you have highlighted to true and I cannot login

    In each case, I get the same error in my 'turned-up' Spring logging:
    2012-07-24 11:51:47,059 DaoAuthenticationProvider [DEBUG] Authentication failed: password does not match stored value

    Please let me know if I need to post anything else...

    Any further suggestions would be greatly appreciated.

  7. #7
    Join Date
    Mar 2007
    Posts
    561

    Default

    I would debug the PasswordEncoder now...
    If you are using maven: select the Encoder, hit F3, wait until the source is downloaded, set your breakpoint and debug...

  8. #8
    Join Date
    May 2012
    Posts
    15

    Default

    spgmx,

    I'm not using Maven, but I have done some debugging (of sorts) using the class I wrote, DatabaseBootstrapPasswordEncoder.java. The upddated source is here:

    DatabaseBootstrapPasswordEncoder.java
    Code:
    package com.classifieds.security;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.jdbc.core.RowCallbackHandler;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    import org.springframework.security.authentication.encoding.PasswordEncoder;
    
    
    /**
     * A class, which will encode the bootstrap passwords loaded via SQL. 
     * 
     * NB: the application assumes a number of accounts will have been set up in the database
     * using a SQL script. These are considered 'bootstrap' accounts and the passwords for 
     * these accounts will appear in the database in plain-text. The purpose of this class is
     * to encode the plain-text passwords of the bootstrap accounts. The class executes an init 
     * method, which is invoked after the embedded-database bean is instantiated.
     * 
     * @author Dan.Mortimer
     */
    public class DatabaseBootstrapPasswordEncoder extends JdbcDaoSupport {
    	private PasswordEncoder passwordEncoder;
    	
    	private final Log logger = LogFactory.getLog(getClass());
    
    	/**
    	 * @param passwordEncoder the passwordEncoder to set
    	 */
    	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
    		this.passwordEncoder = passwordEncoder;
    	}
    	
    	/**
    	 * The init method, which is invoked after the embedded-database bean is instantiated.
    	 * Spring JdbcTemplate functionality is used to loop through all the users in the database 
    	 * and encode the password using the injected PasswordEncoder reference. Each password is 
    	 * updated individually.
    	 */
    	public void secureDatabase() {
    	    getJdbcTemplate().query("select USER_NAME, PASSWORD from apphub.users",
    	                             new RowCallbackHandler() {
    	      public void processRow(ResultSet rs) throws SQLException {
    	    	  String username = rs.getString(1);
    	          String password = rs.getString(2);
    	          logger.info("Username:" + username + " Password:" + password);
    	          
    	          String encodedPassword = passwordEncoder.encodePassword(password, null);
    	          logger.info("Username:" + username + " Password:" + password + " encodedPassword" + encodedPassword);
    	          
    	          getJdbcTemplate().update("update apphub.users set PASSWORD = ? where USER_NAME = ?", encodedPassword, username);
    	          
    	          logger.info("Updating password for username:" + username + " to:" + encodedPassword);
    	          
    	          if (passwordEncoder.isPasswordValid(encodedPassword, password, null)) {
    	        	  logger.info("Password is valid - encoded:" + encodedPassword + " raw:" + password);
    	          } else {
    	        	  logger.info("Password NOT valid - encoded:" + encodedPassword + " raw:" + password);
    	          }
    	      }
    	    });
    	}
    }


    For a given user account (User:testuser Passwordassword), output in the log is as follows:
    2012-07-24 14:05:13,279 DatabaseBootstrapPasswordEncoder [INFO] Username:testuser Password:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
    (...surely this should be 'Passwordassword' - looks like some encoding has taken place already...???)

    2012-07-24 14:05:13,279 DatabaseBootstrapPasswordEncoder [INFO] Username:testuser Password:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 encodedPassword353e8061f2befecb6818ba0c034c632fb0b cae1b
    (...here, '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8' is getting encoded, not 'password')

    2012-07-24 14:05:13,295 DatabaseBootstrapPasswordEncoder [INFO] Updating password for username:testuser to:353e8061f2befecb6818ba0c034c632fb0bcae1b
    2012-07-24 14:05:13,295 DatabaseBootstrapPasswordEncoder [INFO] Password is valid - encoded:353e8061f2befecb6818ba0c034c632fb0bcae1b raw:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8


    So, in my website frontend, I can log in with the credentials:
    User:testuser
    Password: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8



    But I cannot login with (this is the behaviour, I want):
    User:testuser
    Password: password


    Why is it that I am not getting the plain-text value ('password') out of the database in the class?
    (I am getting what looks like an already encoded value)

    Thank you!

  9. #9
    Join Date
    Mar 2007
    Posts
    561

    Default

    You must debug the Encoder!

    And: You will never see the password in cleartext again because hashing is a oneway encryption.

  10. #10
    Join Date
    Mar 2007
    Posts
    561

    Default

    Quote Originally Posted by spgmx View Post
    You must debug the Encoder!
    The ShaPasswordEncoder... not your own DatabaseBootstrapPasswordEncoder

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •