For security reasons, you should always store passwords in hashed form, so that if an unauthorized person gains access to your database, he or she will not be able to retrieve the actual passwords of your users. Hashing performs a one-way transformation of the password, encrypting it in a way that makes it extremely difficult to reconstruct the original password.
When a user attempts to log in, the supplied password is hashed and compared with the hashed value stored in the database. If the two values match, the login is successful.
There are several mathematically complex hashing algorithms available. Although they all perform one-way encryption, stronger algorithms are ones that produce hashes that are more difficult to reproduce through trial and error. The goal is to use an algorithm of sufficient complexity, so that attempts to reproduce its results require enormous computation time.
Of course, as computers grow more powerful, it becomes easier to reproduce algorithms that were once impractical. Therefore it is a good practice to periodically replace your hashing algorithm with a more complex one. However, doing this can create a migration problem. Replacing the hasher can invalidate the logins of users whose passwords were encrypted with an earlier algorithm, because the encrypted passwords no longer match the values stored in the profile repository.
To avoid this migration problem, the Oracle Commerce Platform uses a cryptographic agility scheme that allows you to change the hasher without invalidating existing logins. The scheme works like this:
When a new user profile is created, the password is encrypted using the current hasher. An identifier indicating the hasher used is stored in the repository with the user profile.
Each time the user logs in, the password entered is hashed using the hasher specified in the user profile and compared to the encrypted password stored in the database.
During log in, the system checks whether the hasher associated with the profile is the current one. If the associated algorithm is not the current hasher (because the current hasher has been changed since the user’s last login), the login succeeds (assuming the supplied credentials are valid), but the system then hashes the password using the new hasher, and replaces the hashed password and the identifier in the profile data stored in the repository.
This scheme ensures that even after the current encryption method is changed, users can still log in using an older encryption method, and it automatically updates their profiles to use the new hasher for future logins.
The cryptographic agility scheme and the settings discussed in this section are used by the following repositories:
/atg/userprofiling/ProfileAdapterRepository
– Profiles for external users (site customers)./atg/userprofiling/InternalProfileRepository
– Profiles for internal users of the Business Control Center, such as merchandisers./atg/dynamo/security/AdminSqlRepository
– Logins for the Dynamo Server Admin.
Specifying the Hashing Algorithms
The current hashing algorithm is specified through the passwordHasher
property of the /atg/dynamo/security/PasswordHasherConfigurer
component. The value of this property is a component of a class that implements the atg.security.PasswordHasher
interface. By default, passwordHasher
is set to /atg/dynamo/security/PBKDF2PasswordHasherMultipass-10000
, which is of class atg.security.PBKDF2PasswordHasherMultiPass
. When a new user account is created, the password is hashed using this component.
In addition to passwordHashe
r, the PasswordHasherConfigurer
component has two other key properties:
alternateUserPasswordHasher
Specifies the hasher component to use if there is currently no hasher associated with the profile. By default, this is set to:
alternateUserPasswordHasher=\
/atg/dynamo/security/SaltedDigestPasswordHasher
cryptoAgilityPasswordHashers
A Map that serves as a registry of hashers available to the cryptographic agility scheme. The Map keys are integers and the values are available hasher components. By default, this property is set to:
cryptoAgilityPasswordHashers=\
0=/atg/dynamo/security/SaltedDigestPasswordHasher,\
1=/atg/dynamo/security/PBKDF2PasswordHasher-64000,\
2=/atg/dynamo/security/SaltedMD5PasswordHasher,\
3=/atg/dynamo/security/DigestPasswordHasher,\
4=/atg/dynamo/security/MD5PasswordHasher,\
5=/atg/dynamo/security/PBKDF2PasswordHasher-10000,\
6=/atg/dynamo/security/PBKDF2PasswordHasherMultiPass-10000,\
7=/atg/dynamo/security/PBKDF2PasswordHasherMultiPass-64000
Note that the values of the passwordHasher
, alternateUserPasswordHasher
, and cryptoAgilityPasswordHashers
properties of the PasswordHasherConfigurer
component are used to set the values of equivalent properties of the /atg/userprofiling/PropertyManager
component. You should always set these properties in the PasswordHasherConfigurer
component rather than setting them directly in the PropertyManager
component.
Determining Which Hasher to Use
When a user logs in, the system looks at the passwordKeyDerivationFunction
property of the user profile property to determine the hasher to use. The value of passwordKeyDerivationFunction
is an integer that is used as a key for looking up the hasher in the PasswordHasherConfigurer.cryptoAgilityPasswordHashers
Map property. For example, assuming the configuration shown above, if passwordKeyDerivationFunction
is currently 3, the password is hashed using /atg/dynamo/security/DigestPasswordHasher
.
In addition, if the hasher specified in the profile does not match the current hasher, the system updates the user’s account to use the current hasher for future logins. To do this, it hashes the password with the current hasher, replaces the value of the profile’s password
property with the new hashed value, and updates the profile’s passwordKeyDerivationFunction
property to the Map key for the current hasher.
Note that if a profile’s passwordKeyDerivationFunction
property is null, the system uses the hasher specified in the alternateUserPasswordHasher
property of PasswordHasherConfigurer
. By default, this property is set to /atg/dynamo/security/SaltedDigestPasswordHasher
, which was the default hasher in earlier releases. This enables existing users to log in to an older Oracle Commerce Platform environment that has been upgraded to Oracle Commerce 11, while ensuring that their accounts are then updated to use the current hasher. If you were using a different hasher from SaltedDigestPasswordHasher
, you should change the value of alternateUserPasswordHasher
to match the component you were using.
Available Hashers
To work with the cryptographic agility scheme, a password hasher must be of a class that implements the atg.security.PasswordHasher
interface. If the hasher also uses a salt, the class should extend the abstract class atg.security.PasswordHasher2Adapter
. This class implements atg.security.PasswordHasher
and adds a generateSalt()
method.
By default, the /atg/dynamo/security/PBKDF2PasswordHasherMultiPass-10000
component is configured to be the current hasher. This component is of class atg.security.PBKDF2PasswordHasherMultiPass
, which implements the Password-Based Key Derivation Function 2 encryption method developed by RSA. This method applies a pseudo-random function to the password with a random salt, and iteratively rehashes the result. The class has several properties that configure its behavior:
algorithm
The pseudo-random function to use. In thePBKDF2PasswordHasherMultiPass-10000
component, this property is set toHmacSHA1
.
hashIterations
The number of times to iteratively rehash the result. Using more iterations makes the hash harder to reproduce, but increases the computation time for logins. In thePBKDF2PasswordHasherMultiPass-10000
component, this property is set to10000
. APBKDF2PasswordHasherMultiPass-64000
component is also supplied that sets this property to64000
. As the machines you run your sites on get more powerful, you can create new components that use more iterations, and update thePasswordHasherConfigurer
component to use these new hasher components.
saltSize
The size of the salt in bytes. The default is 20.
encoding
The encoding to use to convert the result to a String. In thePBKDF2PasswordHasherMultiPass-10000
component, this property is set tobase16
.
pwdHasherComponent
The Nucleus path to this component. This value must match the pathname for the component in thecryptoAgilityPasswordHashers
property of thePasswordHasherConfigurer
component. For thePBKDF2PasswordHasherMultiPass-10000
component, this property is set to/atg/dynamo/security/PBKDF2PasswordHasherMultiPass-10000
.
The following list describes the other hashers that are registered with the PasswordHasherConfigurer
component:
The
/atg/dynamo/security/SaltedDigestPasswordHasher
component, of classatg.security.SaltedDigestPasswordHasher
, hashes the password using the SHA-256 algorithm with the login name as a salt, iteratively rehashes the result 1000 times, and then converts the hash to a String using base 16 encoding.The
/atg/dynamo/security/DigestPasswordHasher
component, of classatg.security.DigestPasswordHasher
, hashes the password using the MD5 algorithm and then converts the hash to a String using base 16 encoding. It does not use a salt.The
/atg/dynamo/security/SaltedMD5PasswordHasher
component, of classatg.security.SaltedMD5PasswordHasher
, hashes the password using the MD5 algorithm with the login name as a salt.The
/atg/dynamo/security/MD5PasswordHasher
component, of classatg.security.MD5PasswordHasher
, hashes the password using the MD5 algorithm. It does not use a salt.The
/atg/dynamo/security/PBKDF2PasswordHasher-10000
and/atg/dynamo/security/PBKDF2PasswordHasher-64000
components are of classatg.security.PBKDF2PasswordHasher
. These components should not be used, as this class has been superseded byatg.security.PBKDF2PasswordHasherMultiPass
. They are included in thePasswordHasherConfigurer.cryptoAgilityPasswordHashers
Map so that users they were assigned to previously can be migrated to the current default hasher.
Upgrading All Users to a New Hasher
As discussed above, the cryptographic agility scheme eliminates the need to migrate user accounts when you switch to a new hasher. Each individual user is migrated automatically upon logging in.
However, you may prefer to upgrade all users at once, so that their accounts all use the new hasher immediately. To enable this, the Oracle Commerce Platform provides the atg.userprofiling.upgrade.PasswordHasherUpgradeBatch
class for upgrading all of the users in a profile repository. The DPS
module includes a component of this class, /atg/userprofiling/PasswordHasherUpgradeBatch
, that is configured to upgrade all users in the external profile repository. The DPS.InternalUsers
module includes a component of this class, /atg/userprofiling/PasswordHasherUpgradeInternalUserBatch
, that is configured to upgrade all users in the internal profile repository.
Note that there is no PasswordHasherUpgradeBatch
component for the Dynamo Server Admin accounts. These accounts are upgraded individually upon logging in.
To upgrade all of the users in a profile repository, set the passwordHasher
property of the PasswordHasherConfigurer
component to the new hasher, and set the alternateUserPasswordHasher
property to the old hasher. Then invoke the batchPasswordHasherUpgrade()
method on the corresponding atg.userprofiling.PasswordHasherUpgradeBatch
component. You can invoke this method on the Dynamo Server Admin page for the component.
For each user profile, the batchPasswordHasherUpgrade()
method:
Takes the stored hashed password (which was hashed using the old hasher) and hashes the hashed value again, this time with the new hasher.
Stores this double-hashed password in the profile, and records which hashers were used. The first hash is assumed to have been performed by the hasher specified in the profile’s
passwordKeyDerivationFunction
property. IfpasswordKeyDerivationFunction
is null, the first hash is assumed to have been performed by the hasher specified by thePasswordHasherConfigurer.alternateUserPasswordHasher
property.
The first time a user logs in after the upgrade has been performed, the system performs the following steps:
Detects that the stored password was double-hashed.
Performs the same double-hashing on the password supplied by the user, and compares the result to the value stored in the profile. If the values match, the login succeeds.
Rehashes the supplied password using only the new hasher, and stores the hashed value in the profile for use in future logins.