← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17570: Various improvements to PasswordManager and friends: System wide password and token hash backward...

 

------------------------------------------------------------
revno: 17570
committer: Halvdan Hoem Grelland <halvdanhg@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2014-11-24 15:15:14 +0100
message:
  Various improvements to PasswordManager and friends: System wide password and token hash backwards compatibility. Expired MD5 passwords will now be accepted for renewal on match. Minor refactoring of PasswordManager and MigrationPasswordManager to clarify separation. Minor fixes and additions to javadoc. Added missing license headers.
removed:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationSpringSecurityPasswordManager.java
added:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/SpringSecurityMigrationPasswordManager.java
modified:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/PasswordManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationAuthenticationProvider.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationPasswordManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/spring/SpringSecurityPasswordManager.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/PasswordManagerTest.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AccountController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/DatabaseAutomaticAccessProvider.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/UpdateUserAccountAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/DeleteCurrentUserAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java	2014-11-08 23:03:17 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/DefaultSecurityService.java	2014-11-24 14:15:14 +0000
@@ -144,7 +144,7 @@
 
         user.setSurname( "(TBD)" );
         user.setFirstName( "(TBD)" );
-        user.getUserCredentials().setPassword( passwordManager.encodePassword( rawPassword ) );
+        user.getUserCredentials().setPassword( passwordManager.encode( rawPassword ) );
 
         return true;
     }
@@ -249,8 +249,8 @@
         String token = restoreOptions.getTokenPrefix() + CodeGenerator.generateCode( RESTORE_TOKEN_LENGTH );
         String code = CodeGenerator.generateCode( RESTORE_CODE_LENGTH );
 
-        String hashedToken = passwordManager.encodePassword( token );
-        String hashedCode = passwordManager.encodePassword( code );
+        String hashedToken = passwordManager.encode( token );
+        String hashedCode = passwordManager.encode( code );
 
         RestoreType restoreType = restoreOptions.getRestoreType();
 
@@ -280,7 +280,7 @@
             return false;
         }
 
-        newPassword = passwordManager.encodePassword( newPassword );
+        newPassword = passwordManager.encode( newPassword );
 
         credentials.setPassword( newPassword );
 
@@ -375,7 +375,7 @@
             return "account_restore_code_is_null";
         }
 
-        boolean validCode = passwordManager.tokenMatches( code, restoreCode, credentials.getUsername() );
+        boolean validCode = passwordManager.legacyOrCurrentMatches( code, restoreCode, credentials.getUsername() );
 
         return validCode ? null : "code_does_not_match_restoreCode - code: '"+ code + "' restoreCode: '" + restoreCode + "'" ;
     }
@@ -437,7 +437,7 @@
             return "could_not_verify_token";
         }
 
-        boolean validToken = passwordManager.tokenMatches( token, restoreToken, credentials.getUsername() );
+        boolean validToken = passwordManager.legacyOrCurrentMatches( token, restoreToken, credentials.getUsername() );
 
         return validToken ? null : "restore_token_does_not_match_supplied_token";
     }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/PasswordManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/PasswordManager.java	2014-08-25 15:29:21 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/PasswordManager.java	2014-11-24 14:15:14 +0000
@@ -29,6 +29,11 @@
  */
 
 /**
+ * This interface provides access to the system configured password hashing method.
+ * It is used for encoding passwords and tokens as well as checking the authenticity
+ * of a given password or token. The underlying PasswordEncoder should be the same as
+ * used by Spring Security to perform password checking on user authentication.
+ *
  * @author Torgeir Lorange Ostby
  * @author Halvdan Hoem Grelland
  */
@@ -43,7 +48,7 @@
      * @param password password to encode.
      * @return the hashed password.
      */
-    String encodePassword( String password );
+    String encode( String password );
 
     /**
      * Determines whether the supplied password equals the encoded password or not.

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationAuthenticationProvider.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationAuthenticationProvider.java	2014-08-26 12:00:27 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationAuthenticationProvider.java	2014-11-24 14:15:14 +0000
@@ -64,13 +64,13 @@
         String username = userDetails.getUsername();
 
         // If legacyHash(password, username) matches stored hash, re-hash password with current method and switch with stored hash
-        if( passwordManager.legacyMatches( userDetails.getPassword(), password, username ) )
+        if( passwordManager.legacyMatches( password, userDetails.getPassword(), username ) )
         {
             UserCredentials userCredentials = userService.getUserCredentialsByUsername( username );
 
             if ( userCredentials != null )
             {
-                userCredentials.setPassword( passwordManager.encodePassword( password ) );
+                userCredentials.setPassword( passwordManager.encode( password ) );
                 userCredentials.setPasswordLastUpdated( new Date() );
                 userService.updateUser( userCredentials.getUser() );
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationPasswordManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationPasswordManager.java	2014-10-14 13:58:05 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationPasswordManager.java	2014-11-24 14:15:14 +0000
@@ -1,13 +1,44 @@
 package org.hisp.dhis.security.migration;
 
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 import org.hisp.dhis.security.PasswordManager;
 
 /**
  * Drop-in replacement for PasswordManager which provides access to legacy password hashing methods as
  * well as the currently used hashing methods. This is useful in implementing seamless migration to
- * a new and more secure password hashing method. In such a migration phase the system will need to
- * be able to accept login requests from users whose passwords are stored using legacy hash method
- * in order to re-hash and store the user password hash using the new (current) method (handled elsewhere).
+ * a new and more secure password hashing method.
+ * In such a migration phase the system will need to be able to authenticate passwords and tokens
+ * which are encoded using both the legacy hash method and the current one.
+ * Specific methods for encoding and matching using the legacy hashing method are provided alongside the
+ * current ones. The {@link #legacyOrCurrentMatches(String, String,String) legacyOrCurrentMatches}
+ * method should be used to provide backwards compatibility where applicable.
  *
  * @author Halvdan Hoem Grelland
  */
@@ -15,37 +46,42 @@
     extends PasswordManager
 {
     /**
-     * Cryptographically hash a password using a legacy method.
+     * Cryptographically hash a password using a legacy encoder.
      * Useful for access to the former (legacy) hash method when implementing migration to a new method.
+     *
      * @param password the password to encode.
      * @param username the username (used for seeding salt generation).
      * @return the encoded (hashed) password.
      */
-    public String legacyEncodePassword( String password, String username );
+    public String legacyEncode( String password, String username );
 
     /**
      * Determines whether the supplied password equals the encoded password or not.
      * Uses the legacy hashing method to do so and is useful in implementing migration to a new method.
+     *
+     * @param rawPassword the password.
      * @param encodedPassword the encoded password.
-     * @param password the password to match.
      * @param username the username (used for salt generation).
      * @return true if the password matches the encoded password, false otherwise.
      */
-    public boolean legacyMatches( String encodedPassword, String password, String username );
-
+    public boolean legacyMatches( String rawPassword, String encodedPassword, String username );
 
     /**
-     * Determines whether encodedToken is a valid hash of token.
-     * This method is a wrapper for passwordManager.matches() in order to support
-     * authenticating tokens which were generated using the legacy hash implementation in addition
-     * to the current hashing scheme.
+     * Determines whether encodedPassword is a valid hash of password using either the legacy or
+     * current encoder (hashing method).
+     * This method is a migration specific wrapper for the {@link org.hisp.dhis.security.PasswordManager#matches(String, String) matches}
+     * method in order to support authenticating hashes which were generated using the legacy hash
+     * implementation in addition to the current hashing scheme.
+     * Use this method to provide backwards compatibility for hashes.
+     * Replace with {@link org.hisp.dhis.security.PasswordManager#matches(String, String) matches}
+     * when disabling (ending) backwards compatibility.
      *
-     * @param token the unencoded token as supplied from the user.
-     * @param encodedToken the encoded token to match against.
+     * @param rawPassword the un-encoded token as supplied from the user.
+     * @param encodedPassword the encoded token to match against.
      * @param username the username associated with the token (used for salting by the legacy password encoder).
      * @return true if the token matches for either the legacy or current hashing scheme, false otherwise.
      */
-    public boolean tokenMatches( String token, String encodedToken, String username );
+    public boolean legacyOrCurrentMatches( String rawPassword, String encodedPassword, String username );
 
     /**
      * Return the class name of the legacy password encoder.

=== removed file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationSpringSecurityPasswordManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationSpringSecurityPasswordManager.java	2014-10-14 14:38:16 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/MigrationSpringSecurityPasswordManager.java	1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
-package org.hisp.dhis.security.migration;
-
-import org.hisp.dhis.security.UsernameSaltSource;
-import org.hisp.dhis.security.spring.SpringSecurityPasswordManager;
-import org.springframework.security.authentication.encoding.PasswordEncoder;
-
-/**
- * @author Halvdan Hoem Grelland
- */
-public class MigrationSpringSecurityPasswordManager
-    extends SpringSecurityPasswordManager
-    implements MigrationPasswordManager
-{
-    public static String legacyPasswordEncoderClassName;
-
-    // -------------------------------------------------------------------------
-    // Dependencies
-    // -------------------------------------------------------------------------
-
-    private PasswordEncoder legacyPasswordEncoder;
-
-    public void setLegacyPasswordEncoder( PasswordEncoder legacyPasswordEncoder )
-    {
-        this.legacyPasswordEncoder = legacyPasswordEncoder;
-        legacyPasswordEncoderClassName = legacyPasswordEncoder.getClass().getName();
-    }
-
-    private UsernameSaltSource usernameSaltSource;
-
-    public void setUsernameSaltSource( UsernameSaltSource usernameSaltSource )
-    {
-        this.usernameSaltSource = usernameSaltSource;
-    }
-
-    // -------------------------------------------------------------------------
-    // MigrationPasswordManager implementation
-    // -------------------------------------------------------------------------
-
-    @Override
-    public String legacyEncodePassword( String password, String username )
-    {
-        return legacyPasswordEncoder.encodePassword( password, usernameSaltSource.getSalt( username ) );
-    }
-
-    @Override
-    public boolean legacyMatches( String encodedPassword, String password, String username )
-    {
-        return legacyPasswordEncoder.isPasswordValid( encodedPassword, password, usernameSaltSource.getSalt( username ) );
-    }
-
-    @Override
-    public boolean tokenMatches( String token, String encodedToken, String username )
-    {
-        return legacyMatches( encodedToken, token, username ) || super.matches( token, encodedToken );
-    }
-
-    @Override
-    public String getLegacyPasswordEncoderClassName()
-    {
-        return legacyPasswordEncoder.getClass().getName();
-    }
-}

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/SpringSecurityMigrationPasswordManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/SpringSecurityMigrationPasswordManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/migration/SpringSecurityMigrationPasswordManager.java	2014-11-24 14:15:14 +0000
@@ -0,0 +1,62 @@
+package org.hisp.dhis.security.migration;
+
+import org.hisp.dhis.security.UsernameSaltSource;
+import org.hisp.dhis.security.spring.SpringSecurityPasswordManager;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+
+/**
+ * @author Halvdan Hoem Grelland
+ */
+public class SpringSecurityMigrationPasswordManager
+    extends SpringSecurityPasswordManager
+    implements MigrationPasswordManager
+{
+    public static String legacyPasswordEncoderClassName;
+
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private PasswordEncoder legacyPasswordEncoder;
+
+    public void setLegacyPasswordEncoder( PasswordEncoder legacyPasswordEncoder )
+    {
+        this.legacyPasswordEncoder = legacyPasswordEncoder;
+        legacyPasswordEncoderClassName = legacyPasswordEncoder.getClass().getName();
+    }
+
+    private UsernameSaltSource usernameSaltSource;
+
+    public void setUsernameSaltSource( UsernameSaltSource usernameSaltSource )
+    {
+        this.usernameSaltSource = usernameSaltSource;
+    }
+
+    // -------------------------------------------------------------------------
+    // MigrationPasswordManager implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public final String legacyEncode( String password, String username )
+    {
+        return legacyPasswordEncoder.encodePassword( password, usernameSaltSource.getSalt( username ) );
+    }
+
+    @Override
+    public boolean legacyMatches( String rawPassword, String encodedPassword, String username )
+    {
+        return legacyPasswordEncoder.isPasswordValid( encodedPassword, rawPassword, usernameSaltSource.getSalt( username ) );
+    }
+
+    @Override
+    public boolean legacyOrCurrentMatches( String rawPassword, String encodedPassword, String username )
+    {
+        return legacyMatches( rawPassword, encodedPassword, username ) || super.matches( rawPassword, encodedPassword );
+    }
+
+    @Override
+    public String getLegacyPasswordEncoderClassName()
+    {
+        return legacyPasswordEncoder.getClass().getName();
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/spring/SpringSecurityPasswordManager.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/spring/SpringSecurityPasswordManager.java	2014-08-27 13:26:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/security/spring/SpringSecurityPasswordManager.java	2014-11-24 14:15:14 +0000
@@ -54,7 +54,7 @@
     // -------------------------------------------------------------------------
 
     @Override
-    public final String encodePassword( String password )
+    public final String encode( String password )
     {
         return passwordEncoder.encode( password );
     }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml	2014-08-26 11:06:06 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/security.xml	2014-11-24 14:15:14 +0000
@@ -14,26 +14,25 @@
 
   <!--
     As of version 2.17 the password hashing method has been switched from MD5 to bCrypt. In order to migrate user records
-    seamlessly to the new hashing scheme, the MigrationSpringSecurityPasswordManager and MigrationAuthenticationProvider should
+    seamlessly to the new hashing scheme, the SpringSecurityMigrationPasswordManager and MigrationAuthenticationProvider should
     be used in lieu of SpringSecurityPasswordManager and the default spring AuthenticationProvider respectively.
 
     As soon as migration is deemed complete (in a later version, most likely 2.18 or 2.19) the org.hisp.dhis.security.migration
     package components should be replaced.
 
-    The (working) configuration SpringSecurityPasswordManager as it should be used in later versions is shown
-    (commented out) below. The authentication provider will need no bean definition as the default configuration (with bCryptPasswordEncoder
-    chosen as the password-encoder) should be used.
+    The configuration for SpringSecurityPasswordManager as it should be used in later versions is shown int the comments below.
+    To disable migration mode enable this and change any in class references from MigrationPasswordManager to PasswordManager.
   -->
 
   <!--
-    Replaced by MigrationSpringSecurityPasswordManager as long as the system is not fully migrated to bCrypt password hashes.
+    Replaced by MigrationSpringSecurityPasswordManager as while the system is not fully migrated to bCrypt password hashes.
 
   <bean id="org.hisp.dhis.security.PasswordManager" class="org.hisp.dhis.security.spring.SpringSecurityPasswordManager">
     <property name="passwordEncoder" ref="bCryptPasswordEncoder" />
   </bean>
   -->
 
-  <bean id="org.hisp.dhis.security.PasswordManager" class="org.hisp.dhis.security.migration.MigrationSpringSecurityPasswordManager">
+  <bean id="org.hisp.dhis.security.PasswordManager" class="org.hisp.dhis.security.migration.SpringSecurityMigrationPasswordManager">
     <property name="passwordEncoder" ref="bCryptPasswordEncoder" />
     <property name="legacyPasswordEncoder" ref="md5PasswordEncoder" />
     <property name="usernameSaltSource" ref="usernameSaltSource" />

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/PasswordManagerTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/PasswordManagerTest.java	2014-08-27 13:26:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/security/PasswordManagerTest.java	2014-11-24 14:15:14 +0000
@@ -1,5 +1,33 @@
 package org.hisp.dhis.security;
 
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 import org.hisp.dhis.DhisSpringTest;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -8,7 +36,6 @@
 import static org.junit.Assert.assertTrue;
 
 /**
- * Tests assume (and enforce) the passwordManager to use non-static salts.
  * @author Halvdan Hoem Grelland
  */
 public class PasswordManagerTest
@@ -22,8 +49,8 @@
     {
         String password = "district";
 
-        String encodedPassword1 = passwordManager.encodePassword( password );
-        String encodedPassword2 = passwordManager.encodePassword( password );
+        String encodedPassword1 = passwordManager.encode( password );
+        String encodedPassword2 = passwordManager.encode( password );
 
         assertFalse( encodedPassword1.equals( encodedPassword2 ) );
         assertFalse( password.equals( encodedPassword1 ) );

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2014-10-10 10:55:35 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2014-11-24 14:15:14 +0000
@@ -317,7 +317,7 @@
 
             if ( userCredentials.getPassword() != null )
             {
-                userCredentials.setPassword( passwordManager.encodePassword( userCredentials.getPassword() ) );
+                userCredentials.setPassword( passwordManager.encode( userCredentials.getPassword() ) );
             }
 
             Map<Field, Collection<Object>> collectionFieldsUserCredentials = detachCollectionFields( userCredentials );
@@ -417,7 +417,7 @@
 
                 if ( userCredentials != null && userCredentials.getPassword() != null )
                 {
-                    userCredentials.setPassword( passwordManager.encodePassword( userCredentials.getPassword() ) );
+                    userCredentials.setPassword( passwordManager.encode( userCredentials.getPassword() ) );
                 }
 
                 ((User) persistedObject).getUserCredentials().mergeWith( userCredentials );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AccountController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AccountController.java	2014-11-21 11:04:14 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AccountController.java	2014-11-24 14:15:14 +0000
@@ -34,10 +34,10 @@
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.configuration.ConfigurationService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
-import org.hisp.dhis.security.PasswordManager;
 import org.hisp.dhis.security.RestoreOptions;
 import org.hisp.dhis.security.RestoreType;
 import org.hisp.dhis.security.SecurityService;
+import org.hisp.dhis.security.migration.MigrationPasswordManager;
 import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.util.ValidationUtils;
 import org.hisp.dhis.user.User;
@@ -100,7 +100,7 @@
     private ConfigurationService configurationService;
 
     @Autowired
-    private PasswordManager passwordManager;
+    private MigrationPasswordManager passwordManager;
 
     @Autowired
     private SecurityService securityService;
@@ -399,7 +399,7 @@
                 username = credentials.getUsername();
             }
 
-            credentials.setPassword( passwordManager.encodePassword( password ) );
+            credentials.setPassword( passwordManager.encode( password ) );
 
             userService.updateUser( user );
             userService.updateUserCredentials( credentials );
@@ -421,7 +421,7 @@
 
             credentials = new UserCredentials();
             credentials.setUsername( username );
-            credentials.setPassword( passwordManager.encodePassword( password ) );
+            credentials.setPassword( passwordManager.encode( password ) );
             credentials.setSelfRegistered( true );
             credentials.setUser( user );
             credentials.getUserAuthorityGroups().add( userRole );
@@ -472,7 +472,7 @@
             return;
         }
 
-        if( !passwordManager.matches( oldPassword, credentials.getPassword() ) )
+        if( !passwordManager.legacyOrCurrentMatches( oldPassword, credentials.getPassword(), credentials.getUsername() ) )
         {
             result.put( "status", "NON_MATCHING_PASSWORD" );
             result.put( "message", "Old password is wrong, please correct and try again." );
@@ -499,7 +499,7 @@
             return;
         }
 
-        String passwordEncoded = passwordManager.encodePassword( password );
+        String passwordEncoded = passwordManager.encode( password );
 
         credentials.setPassword( passwordEncoded );
         credentials.setPasswordLastUpdated( new Date() );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java	2014-11-08 17:52:46 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java	2014-11-24 14:15:14 +0000
@@ -318,7 +318,7 @@
         user.getUserCredentials().getCatDimensionConstraints().addAll(
             currentUserService.getCurrentUser().getUserCredentials().getCatDimensionConstraints() );
 
-        String encodedPassword = passwordManager.encodePassword( user.getUserCredentials().getPassword() );
+        String encodedPassword = passwordManager.encode( user.getUserCredentials().getPassword() );
         user.getUserCredentials().setPassword( encodedPassword );
 
         ImportTypeSummary summary = importService.importObject( currentUserService.getCurrentUser().getUid(), user, ImportStrategy.CREATE );

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/DatabaseAutomaticAccessProvider.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/DatabaseAutomaticAccessProvider.java	2014-10-16 06:17:19 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/security/DatabaseAutomaticAccessProvider.java	2014-11-24 14:15:14 +0000
@@ -84,7 +84,7 @@
 
         UserCredentials userCredentials = new UserCredentials();
         userCredentials.setUsername( username );
-        userCredentials.setPassword( passwordManager.encodePassword( password ) );
+        userCredentials.setPassword( passwordManager.encode( password ) );
         userCredentials.setUser( user );
         userCredentials.getUserAuthorityGroups().add( userAuthorityGroup );
 

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/UpdateUserAccountAction.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/UpdateUserAccountAction.java	2014-10-16 06:17:19 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/useraccount/action/UpdateUserAccountAction.java	2014-11-24 14:15:14 +0000
@@ -29,7 +29,7 @@
  */
 
 import org.hisp.dhis.i18n.I18n;
-import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.migration.MigrationPasswordManager;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserCredentials;
 import org.hisp.dhis.user.UserService;
@@ -48,7 +48,7 @@
 
     private UserService userService;
 
-    private PasswordManager passwordManager;
+    private MigrationPasswordManager passwordManager;
 
     // -------------------------------------------------------------------------
     // Input
@@ -76,7 +76,7 @@
     // Getters && Setters
     // -------------------------------------------------------------------------
 
-    public void setPasswordManager( PasswordManager passwordManager )
+    public void setPasswordManager( MigrationPasswordManager passwordManager )
     {
         this.passwordManager = passwordManager;
     }
@@ -159,7 +159,7 @@
 
         String currentPassword = userCredentials.getPassword();
         
-        if ( !passwordManager.matches( oldPassword, currentPassword ) )
+        if ( !passwordManager.legacyOrCurrentMatches( oldPassword, currentPassword, user.getUsername() ) )
         {
             message = i18n.getString( "wrong_password" );
             return INPUT;
@@ -179,7 +179,7 @@
 
         if ( rawPassword != null )
         {
-            userCredentials.setPassword( passwordManager.encodePassword( rawPassword ) );
+            userCredentials.setPassword( passwordManager.encode( rawPassword ) );
 
             userService.updateUserCredentials( userCredentials );
         }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java	2014-10-16 17:23:01 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/AddUserAction.java	2014-11-24 14:15:14 +0000
@@ -364,7 +364,7 @@
             user.setEmail( email );
             user.setPhoneNumber( phoneNumber );
 
-            userCredentials.setPassword( passwordManager.encodePassword( rawPassword ) );
+            userCredentials.setPassword( passwordManager.encode( rawPassword ) );
         }
 
         if ( jsonAttributeValues != null )

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/DeleteCurrentUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/DeleteCurrentUserAction.java	2014-08-22 15:39:25 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/DeleteCurrentUserAction.java	2014-11-24 14:15:14 +0000
@@ -31,7 +31,7 @@
 import com.opensymphony.xwork2.Action;
 import java.util.Collection;
 import org.hisp.dhis.i18n.I18n;
-import org.hisp.dhis.security.PasswordManager;
+import org.hisp.dhis.security.migration.MigrationPasswordManager;
 import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.User;
 import org.hisp.dhis.user.UserCredentials;
@@ -48,9 +48,9 @@
         this.currentUserService = currentUserService;
     }
 
-    private PasswordManager passwordManager;
+    private MigrationPasswordManager passwordManager;
 
-    public void setPasswordManager( PasswordManager passwordManager )
+    public void setPasswordManager( MigrationPasswordManager passwordManager )
     {
         this.passwordManager = passwordManager;
     }
@@ -123,7 +123,7 @@
             return INPUT;
         }
 
-        if( !passwordManager.matches( oldPassword, oldPasswordFromDB ) )
+        if( !passwordManager.legacyOrCurrentMatches( oldPassword, oldPasswordFromDB, username ) )
         {
             message = i18n.getString( "wrong_password" );
             return INPUT;

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-10-16 06:17:19 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-user/src/main/java/org/hisp/dhis/user/action/UpdateUserAction.java	2014-11-24 14:15:14 +0000
@@ -323,7 +323,7 @@
 
         if ( rawPassword != null )
         {
-            userCredentials.setPassword( passwordManager.encodePassword( rawPassword ) );
+            userCredentials.setPassword( passwordManager.encode( rawPassword ) );
         }
 
         if ( jsonAttributeValues != null )