org.apache.shiro.authc.credential
Class HashedCredentialsMatcher

java.lang.Object
  extended by org.apache.shiro.codec.CodecSupport
      extended by org.apache.shiro.authc.credential.SimpleCredentialsMatcher
          extended by org.apache.shiro.authc.credential.HashedCredentialsMatcher
All Implemented Interfaces:
CredentialsMatcher
Direct Known Subclasses:
Md2CredentialsMatcher, Md5CredentialsMatcher, Sha1CredentialsMatcher, Sha256CredentialsMatcher, Sha384CredentialsMatcher, Sha512CredentialsMatcher

public class HashedCredentialsMatcher
extends SimpleCredentialsMatcher

A HashedCredentialMatcher provides support for hashing of supplied AuthenticationToken credentials before being compared to those in the AuthenticationInfo from the data store.

Credential hashing is one of the most common security techniques when safeguarding a user's private credentials (passwords, keys, etc). Most developers never want to store their users' credentials in plain form, viewable by anyone, so they often hash the users' credentials before they are saved in the data store.

This class (and its subclasses) function as follows:

  1. Hash the AuthenticationToken credentials supplied by the user during their login.
  2. Compare this hashed value directly with the AuthenticationInfo credentials stored in the system (the stored account credentials are expected to already be in hashed form).
  3. If these two values are equal, the submitted credentials match, otherwise they do not.

Salting and Multiple Hash Iterations

Because simple hashing is usually not good enough for secure applications, this class also supports 'salting' and multiple hash iterations. Please read this excellent Hashing Java article to learn about salting and multiple iterations and why you might want to use them. (Note of sections 5 "Why add salt?" and 6 "Hardening against the attacker's attack"). We should also note here that all of Shiro's Hash implementations (for example, Md5Hash, Sha1Hash, etc) support salting and multiple hash iterations via overloaded constructors.

Real World Case Study

In April 2010, some public Atlassian Jira and Confluence installations (Apache Software Foundation, Codehaus, etc) were the target of account attacks and user accounts were compromised. The reason? Jira and Confluence at the time did not salt user passwords and attackers were able to use dictionary attacks to compromise user accounts (Atlassian has since fixed the problem of course).

The lesson?

ALWAYS, ALWAYS, ALWAYS SALT USER PASSWORDS!

Salting

Prior to Shiro 1.1, salts could be obtained based on the end-user submitted AuthenticationToken via the now-deprecated getSalt(AuthenticationToken) method. This however could constitute a security hole since ideally salts should never be obtained based on what a user can submit. User-submitted salt mechanisms are much more susceptible to dictionary attacks and SHOULD NOT be used in secure systems. Instead salts should ideally be a secure randomly-generated number that is generated when the user account is created. The secure number should never be disseminated to the user and always kept private by the application.

Shiro 1.1

As of Shiro 1.1, it is expected that any salt used to hash the submitted credentials will be obtained from the stored account information (represented as an AuthenticationInfo instance). This is much more secure because the salt value remains private to the application (Shiro will never store this value).

To enable this, Realms should return SaltedAuthenticationInfo instances during authentication. HashedCredentialsMatcher implementations will then use the provided credentialsSalt for hashing. To avoid security risks, it is highly recommended that any existing Realm implementations that support hashed credentials are updated to return SaltedAuthenticationInfo instances as soon as possible.

Shiro 1.0 Backwards Compatibility

Because of the identified security risk, Realm implementations that support credentials hashing should be updated to return SaltedAuthenticationInfo instances as soon as possible.

If this is not possible for some reason, this class will retain 1.0 backwards-compatible behavior of obtaining the salt via the now-deprecated getSalt(AuthenticationToken) method. This method will only be invoked if a Realm does not return SaltedAutenticationInfo instances and hashSalted is true. But please note that the hashSalted property and the getSalt(AuthenticationToken) methods will be removed before the Shiro 2.0 release.

Multiple Hash Iterations

If you hash your users' credentials multiple times before persisting to the data store, you will also need to set this class's hashIterations property. See the Hashing Java article's "Hardening against the attacker's attack" section to learn more about why you might want to use multiple hash iterations.

MD5 & SHA-1 Notice

MD5 and SHA-1 algorithms are now known to be vulnerable to compromise and/or collisions (read the linked pages for more). While most applications are ok with either of these two, if your application mandates high security, use the SHA-256 (or higher) hashing algorithms and their supporting CredentialsMatcher implementations.

Since:
0.9
See Also:
Md5Hash, Sha1Hash, Sha256Hash

Field Summary
 
Fields inherited from class org.apache.shiro.codec.CodecSupport
PREFERRED_ENCODING
 
Constructor Summary
HashedCredentialsMatcher()
          JavaBeans-compatibile no-arg constructor intended for use in IoC/Dependency Injection environments.
HashedCredentialsMatcher(String hashAlgorithmName)
          Creates an instance using the specified hashAlgorithmName to hash submitted credentials.
 
Method Summary
 boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
          This implementation first hashes the token's credentials, potentially using a salt if the info argument is a SaltedAuthenticationInfo.
protected  Object getCredentials(AuthenticationInfo info)
          Returns a Hash instance representing the already-hashed AuthenticationInfo credentials stored in the system.
 String getHashAlgorithmName()
          Returns the Hash algorithmName to use when performing hashes for credentials matching.
 int getHashIterations()
          Returns the number of times a submitted AuthenticationToken's credentials will be hashed before comparing to the credentials stored in the system.
protected  Object getSalt(AuthenticationToken token)
          Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

protected  Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info)
          Hash the provided token's credentials using the salt stored with the account if the info instance is an instanceof SaltedAuthenticationInfo (see the class-level JavaDoc for why this is the preferred approach).
protected  Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations)
          Hashes the provided credentials a total of hashIterations times, using the given salt.
 boolean isHashSalted()
          Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

 boolean isStoredCredentialsHexEncoded()
          Returns true if the system's stored credential hash is Hex encoded, false if it is Base64 encoded.
protected  AbstractHash newHashInstance()
          Returns a new, uninitialized instance, without its byte array set.
 void setHashAlgorithmName(String hashAlgorithmName)
          Sets the Hash algorithmName to use when performing hashes for credentials matching.
 void setHashIterations(int hashIterations)
          Sets the number of times a submitted AuthenticationToken's credentials will be hashed before comparing to the credentials stored in the system.
 void setHashSalted(boolean hashSalted)
          Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

 void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded)
          Sets the indicator if this system's stored credential hash is Hex encoded or not.
 
Methods inherited from class org.apache.shiro.authc.credential.SimpleCredentialsMatcher
equals, getCredentials
 
Methods inherited from class org.apache.shiro.codec.CodecSupport
isByteSource, objectToBytes, objectToString, toBytes, toBytes, toBytes, toBytes, toBytes, toBytes, toBytes, toChars, toChars, toString, toString, toString
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

HashedCredentialsMatcher

public HashedCredentialsMatcher()
JavaBeans-compatibile no-arg constructor intended for use in IoC/Dependency Injection environments. If you use this constructor, you MUST also additionally set the hashAlgorithmName property.


HashedCredentialsMatcher

public HashedCredentialsMatcher(String hashAlgorithmName)
Creates an instance using the specified hashAlgorithmName to hash submitted credentials.

Parameters:
hashAlgorithmName - the Hash algorithmName to use when performing hashes for credentials matching.
Since:
1.1
Method Detail

getHashAlgorithmName

public String getHashAlgorithmName()
Returns the Hash algorithmName to use when performing hashes for credentials matching.

Returns:
the Hash algorithmName to use when performing hashes for credentials matching.
Since:
1.1

setHashAlgorithmName

public void setHashAlgorithmName(String hashAlgorithmName)
Sets the Hash algorithmName to use when performing hashes for credentials matching.

Parameters:
hashAlgorithmName - the Hash algorithmName to use when performing hashes for credentials matching.
Since:
1.1

isStoredCredentialsHexEncoded

public boolean isStoredCredentialsHexEncoded()
Returns true if the system's stored credential hash is Hex encoded, false if it is Base64 encoded.

Default value is true for convenience - all of Shiro's Hash#toString() implementations return Hex encoded values by default, making this class's use with those implementations easier.

Returns:
true if the system's stored credential hash is Hex encoded, false if it is Base64 encoded. Default is true

setStoredCredentialsHexEncoded

public void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded)
Sets the indicator if this system's stored credential hash is Hex encoded or not.

A value of true will cause this class to decode the system credential from Hex, a value of false will cause this class to decode the system credential from Base64.

Unless overridden via this method, the default value is true for convenience - all of Shiro's Hash#toString() implementations return Hex encoded values by default, making this class's use with those implementations easier.

Parameters:
storedCredentialsHexEncoded - the indicator if this system's stored credential hash is Hex encoded or not ('not' automatically implying it is Base64 encoded).

isHashSalted

@Deprecated
public boolean isHashSalted()
Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

Returns true if a submitted AuthenticationToken's credentials should be salted when hashing, false if it should not be salted.

If enabled, the salt used will be obtained via the getSalt method.

The default value is false.

Returns:
true if a submitted AuthenticationToken's credentials should be salted when hashing, false if it should not be salted.

setHashSalted

@Deprecated
public void setHashSalted(boolean hashSalted)
Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

Sets whether or not to salt a submitted AuthenticationToken's credentials when hashing.

If enabled, the salt used will be obtained via the getCredentialsSalt method.

The default value is false.

Parameters:
hashSalted - whether or not to salt a submitted AuthenticationToken's credentials when hashing.

getHashIterations

public int getHashIterations()
Returns the number of times a submitted AuthenticationToken's credentials will be hashed before comparing to the credentials stored in the system.

Unless overridden, the default value is 1, meaning a normal hash execution will occur.

Returns:
the number of times a submitted AuthenticationToken's credentials will be hashed before comparing to the credentials stored in the system.

setHashIterations

public void setHashIterations(int hashIterations)
Sets the number of times a submitted AuthenticationToken's credentials will be hashed before comparing to the credentials stored in the system.

Unless overridden, the default value is 1, meaning a normal single hash execution will occur.

If this argument is less than 1 (i.e. 0 or negative), the default value of 1 is applied. There must always be at least 1 hash iteration (otherwise there would be no hash).

Parameters:
hashIterations - the number of times to hash a submitted AuthenticationToken's credentials.

getSalt

@Deprecated
protected Object getSalt(AuthenticationToken token)
Deprecated. since Shiro 1.1. Hash salting is now expected to be based on if the AuthenticationInfo returned from the Realm is a SaltedAuthenticationInfo instance and its getCredentialsSalt() method returns a non-null value. This method and the 1.0 behavior still exists for backwards compatibility if the Realm does not return SaltedAuthenticationInfo instances, but it is highly recommended that Realm implementations that support hashed credentials start returning SaltedAuthenticationInfo instances as soon as possible.

This is because salts should always be obtained from the stored account information and never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user are almost impossible to break. This method will be removed in Shiro 2.0.

Returns a salt value used to hash the token's credentials.

This default implementation merely returns token.getPrincipal(), effectively using the user's identity (username, user id, etc) as the salt, a most common technique. If you wish to provide the authentication token's salt another way, you may override this method.

Parameters:
token - the AuthenticationToken submitted during the authentication attempt.
Returns:
a salt value to use to hash the authentication token's credentials.

getCredentials

protected Object getCredentials(AuthenticationInfo info)
Returns a Hash instance representing the already-hashed AuthenticationInfo credentials stored in the system.

This method reconstructs a Hash instance based on a info.getCredentials call, but it does not hash that value - it is expected that method call will return an already-hashed value.

This implementation's reconstruction effort functions as follows:

  1. Convert account.getCredentials() to a byte array via the toBytes method.
  2. If account.getCredentials() was originally a String or char[] before toBytes was called, check for encoding:
  3. If storedCredentialsHexEncoded, Hex decode that byte array, otherwise Base64 decode the byte array
  4. Set the byte[] array directly on the Hash implementation and return it.

Overrides:
getCredentials in class SimpleCredentialsMatcher
Parameters:
info - the AuthenticationInfo from which to retrieve the credentials which assumed to be in already-hashed form.
Returns:
a Hash instance representing the given AuthenticationInfo's stored credentials.

doCredentialsMatch

public boolean doCredentialsMatch(AuthenticationToken token,
                                  AuthenticationInfo info)
This implementation first hashes the token's credentials, potentially using a salt if the info argument is a SaltedAuthenticationInfo. It then compares the hash against the AuthenticationInfo's already-hashed credentials. This method returns true if those two values are equal, false otherwise.

Specified by:
doCredentialsMatch in interface CredentialsMatcher
Overrides:
doCredentialsMatch in class SimpleCredentialsMatcher
Parameters:
token - the AuthenticationToken submitted during the authentication attempt.
info - the AuthenticationInfo stored in the system matching the token principal
Returns:
true if the provided token credentials hash match to the stored account credentials hash, false otherwise
Since:
1.1

hashProvidedCredentials

protected Object hashProvidedCredentials(AuthenticationToken token,
                                         AuthenticationInfo info)
Hash the provided token's credentials using the salt stored with the account if the info instance is an instanceof SaltedAuthenticationInfo (see the class-level JavaDoc for why this is the preferred approach).

If the info instance is not an instanceof SaltedAuthenticationInfo, the logic will fall back to Shiro 1.0 backwards-compatible logic: it will first check to see isHashSalted and if so, will try to acquire the salt from getSalt(AuthenticationToken). See the class-level JavaDoc for why this is not recommended. This 'fallback' logic exists only for backwards-compatibility. Realms should be updated as soon as possible to return SaltedAuthenticationInfo instances if account credentials salting is enabled (highly recommended for password-based systems).

Parameters:
token - the submitted authentication token from which its credentials will be hashed
info - the stored account data, potentially used to acquire a salt
Returns:
the token credentials hash
Since:
1.1

hashProvidedCredentials

protected Hash hashProvidedCredentials(Object credentials,
                                       Object salt,
                                       int hashIterations)
Hashes the provided credentials a total of hashIterations times, using the given salt. The hash implementation/algorithm used is based on the hashAlgorithmName property.

Parameters:
credentials - the submitted authentication token's credentials to hash
salt - the value to salt the hash, or null if a salt will not be used.
hashIterations - the number of times to hash the credentials. At least one hash will always occur though, even if this argument is 0 or negative.
Returns:
the hashed value of the provided credentials, according to the specified salt and hash iterations.

newHashInstance

protected AbstractHash newHashInstance()
Returns a new, uninitialized instance, without its byte array set. Used as a utility method in the getCredentials(AuthenticationInfo) implementation.

Returns:
a new, uninitialized instance, without its byte array set.


Copyright © 2004-2012 The Apache Software Foundation. All Rights Reserved.