blob: b0dc914504303060f914a7f2b1ec9a2d5a33e78f [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>HashedCredentialsMatcher.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Apache Shiro :: Test Coverage</a> &gt; <a href="../index.html" class="el_bundle">shiro-core</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.authc.credential</a> &gt; <span class="el_source">HashedCredentialsMatcher.java</span></div><h1>HashedCredentialsMatcher.java</h1><pre class="source lang-java linenums">/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* &quot;License&quot;); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.authc.credential;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SaltedAuthenticationInfo;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.hash.AbstractHash;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.StringUtils;
/**
* A {@code HashedCredentialMatcher} provides support for hashing of supplied {@code AuthenticationToken} credentials
* before being compared to those in the {@code AuthenticationInfo} from the data store.
* &lt;p/&gt;
* 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.
* &lt;p/&gt;
* This class (and its subclasses) function as follows:
* &lt;ol&gt;
* &lt;li&gt;Hash the {@code AuthenticationToken} credentials supplied by the user during their login.&lt;/li&gt;
* &lt;li&gt;Compare this hashed value directly with the {@code AuthenticationInfo} credentials stored in the system
* (the stored account credentials are expected to already be in hashed form).&lt;/li&gt;
* &lt;li&gt;If these two values are {@link #equals(Object, Object) equal}, the submitted credentials match, otherwise
* they do not.&lt;/li&gt;
* &lt;/ol&gt;
* &lt;h2&gt;Salting and Multiple Hash Iterations&lt;/h2&gt;
* Because simple hashing is usually not good enough for secure applications, this class also supports 'salting'
* and multiple hash iterations. Please read this excellent
* &lt;a href=&quot;http://www.owasp.org/index.php/Hashing_Java&quot; _target=&quot;blank&quot;&gt;Hashing Java article&lt;/a&gt; to learn about
* salting and multiple iterations and why you might want to use them. (Note of sections 5
* &amp;quot;Why add salt?&amp;quot; and 6 &quot;Hardening against the attacker's attack&quot;). We should also note here that all of
* Shiro's Hash implementations (for example, {@link org.apache.shiro.crypto.hash.Md5Hash Md5Hash},
* {@link org.apache.shiro.crypto.hash.Sha1Hash Sha1Hash}, etc) support salting and multiple hash iterations via
* overloaded constructors.
* &lt;h4&gt;Real World Case Study&lt;/h4&gt;
* 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
* &lt;a href=&quot;http://blogs.atlassian.com/news/2010/04/oh_man_what_a_day_an_update_on_our_security_breach.html&quot;&gt;
* fixed the problem&lt;/a&gt; of course).
* &lt;p/&gt;
* The lesson?
* &lt;p/&gt;
* &lt;b&gt;ALWAYS, ALWAYS, ALWAYS SALT USER PASSWORDS!&lt;/b&gt;
* &lt;p/&gt;
* &lt;h3&gt;Salting&lt;/h3&gt;
* Prior to Shiro 1.1, salts could be obtained based on the end-user submitted
* {@link AuthenticationToken AuthenticationToken} via the now-deprecated
* {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) 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 &lt;em&gt;much&lt;/em&gt; more susceptible to dictionary attacks and &lt;b&gt;SHOULD NOT&lt;/b&gt; 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.
* &lt;h4&gt;Shiro 1.1&lt;/h4&gt;
* 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 {@link AuthenticationInfo AuthenticationInfo} instance). This is much
* more secure because the salt value remains private to the application (Shiro will never store this value).
* &lt;p/&gt;
* To enable this, {@code Realm}s should return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances
* during authentication. {@code HashedCredentialsMatcher} implementations will then use the provided
* {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt credentialsSalt} for hashing. To avoid
* security risks,
* &lt;b&gt;it is highly recommended that any existing {@code Realm} implementations that support hashed credentials are
* updated to return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances as soon as possible&lt;/b&gt;.
* &lt;h4&gt;Shiro 1.0 Backwards Compatibility&lt;/h4&gt;
* Because of the identified security risk, {@code Realm} implementations that support credentials hashing should
* be updated to return {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} instances as
* soon as possible.
* &lt;p/&gt;
* 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 {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)} method. This
* method will only be invoked if a {@code Realm} &lt;em&gt;does not&lt;/em&gt; return
* {@link SaltedAuthenticationInfo SaltedAutenticationInfo} instances and {@link #isHashSalted() hashSalted} is
* {@code true}.
* But please note that the {@link #isHashSalted() hashSalted} property and the
* {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)} methods will be removed before the Shiro 2.0
* release.
* &lt;h3&gt;Multiple Hash Iterations&lt;/h3&gt;
* If you hash your users' credentials multiple times before persisting to the data store, you will also need to
* set this class's {@link #setHashIterations(int) hashIterations} property. See the
* &lt;a href=&quot;http://www.owasp.org/index.php/Hashing_Java&quot; _target=&quot;blank&quot;&gt;Hashing Java article&lt;/a&gt;'s
* &lt;a href=&quot;http://www.owasp.org/index.php/Hashing_Java#Hardening_against_the_attacker.27s_attack&quot;&gt;
* &amp;quot;Hardening against the attacker's attack&amp;quot;&lt;/a&gt; section to learn more about why you might want to use
* multiple hash iterations.
* &lt;h2&gt;MD5 &amp;amp; SHA-1 Notice&lt;/h2&gt;
* &lt;a href=&quot;http://en.wikipedia.org/wiki/MD5&quot;&gt;MD5&lt;/a&gt; and
* &lt;a href=&quot;http://en.wikipedia.org/wiki/SHA_hash_functions&quot;&gt;SHA-1&lt;/a&gt; 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 {@code CredentialsMatcher} implementations.
*
* @see org.apache.shiro.crypto.hash.Md5Hash
* @see org.apache.shiro.crypto.hash.Sha1Hash
* @see org.apache.shiro.crypto.hash.Sha256Hash
* @since 0.9
*/
public class HashedCredentialsMatcher extends SimpleCredentialsMatcher {
/**
* @since 1.1
*/
private String hashAlgorithm;
private int hashIterations;
private boolean hashSalted;
private boolean storedCredentialsHexEncoded;
/**
* JavaBeans-compatible no-arg constructor intended for use in IoC/Dependency Injection environments. If you
* use this constructor, you &lt;em&gt;MUST&lt;/em&gt; also additionally set the
* {@link #setHashAlgorithmName(String) hashAlgorithmName} property.
*/
<span class="fc" id="L135"> public HashedCredentialsMatcher() {</span>
<span class="fc" id="L136"> this.hashAlgorithm = null;</span>
<span class="fc" id="L137"> this.hashSalted = false;</span>
<span class="fc" id="L138"> this.hashIterations = 1;</span>
<span class="fc" id="L139"> this.storedCredentialsHexEncoded = true; //false means Base64-encoded</span>
<span class="fc" id="L140"> }</span>
/**
* Creates an instance using the specified {@link #getHashAlgorithmName() hashAlgorithmName} to hash submitted
* credentials.
* @param hashAlgorithmName the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName}
* to use when performing hashes for credentials matching.
* @since 1.1
*/
public HashedCredentialsMatcher(String hashAlgorithmName) {
<span class="fc" id="L150"> this();</span>
<span class="pc bpc" id="L151" title="1 of 2 branches missed."> if (!StringUtils.hasText(hashAlgorithmName) ) {</span>
<span class="nc" id="L152"> throw new IllegalArgumentException(&quot;hashAlgorithmName cannot be null or empty.&quot;);</span>
}
<span class="fc" id="L154"> this.hashAlgorithm = hashAlgorithmName;</span>
<span class="fc" id="L155"> }</span>
/**
* Returns the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use
* when performing hashes for credentials matching.
*
* @return the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use
* when performing hashes for credentials matching.
* @since 1.1
*/
public String getHashAlgorithmName() {
<span class="fc" id="L166"> return hashAlgorithm;</span>
}
/**
* Sets the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use
* when performing hashes for credentials matching.
*
* @param hashAlgorithmName the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName}
* to use when performing hashes for credentials matching.
* @since 1.1
*/
public void setHashAlgorithmName(String hashAlgorithmName) {
<span class="fc" id="L178"> this.hashAlgorithm = hashAlgorithmName;</span>
<span class="fc" id="L179"> }</span>
/**
* Returns {@code true} if the system's stored credential hash is Hex encoded, {@code false} if it
* is Base64 encoded.
* &lt;p/&gt;
* Default value is {@code true} for convenience - all of Shiro's {@link Hash Hash#toString()}
* implementations return Hex encoded values by default, making this class's use with those implementations
* easier.
*
* @return {@code true} if the system's stored credential hash is Hex encoded, {@code false} if it
* is Base64 encoded. Default is {@code true}
*/
public boolean isStoredCredentialsHexEncoded() {
<span class="fc" id="L193"> return storedCredentialsHexEncoded;</span>
}
/**
* Sets the indicator if this system's stored credential hash is Hex encoded or not.
* &lt;p/&gt;
* A value of {@code true} will cause this class to decode the system credential from Hex, a
* value of {@code false} will cause this class to decode the system credential from Base64.
* &lt;p/&gt;
* Unless overridden via this method, the default value is {@code true} for convenience - all of Shiro's
* {@link Hash Hash#toString()} implementations return Hex encoded values by default, making this class's use with
* those implementations easier.
*
* @param storedCredentialsHexEncoded the indicator if this system's stored credential hash is Hex
* encoded or not ('not' automatically implying it is Base64 encoded).
*/
public void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded) {
<span class="nc" id="L210"> this.storedCredentialsHexEncoded = storedCredentialsHexEncoded;</span>
<span class="nc" id="L211"> }</span>
/**
* Returns {@code true} if a submitted {@code AuthenticationToken}'s credentials should be salted when hashing,
* {@code false} if it should not be salted.
* &lt;p/&gt;
* If enabled, the salt used will be obtained via the {@link #getSalt(AuthenticationToken) getSalt} method.
* &lt;p/&gt;
* The default value is {@code false}.
*
* @return {@code true} if a submitted {@code AuthenticationToken}'s credentials should be salted when hashing,
* {@code false} if it should not be salted.
* @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo}
* returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its
* {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value.
* This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return
* {@code SaltedAuthenticationInfo} instances, but &lt;b&gt;it is highly recommended that {@code Realm} implementations
* that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo}
* instances as soon as possible&lt;/b&gt;.
* &lt;p/&gt;
* 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.
*/
@Deprecated
public boolean isHashSalted() {
<span class="fc" id="L238"> return hashSalted;</span>
}
/**
* Sets whether or not to salt a submitted {@code AuthenticationToken}'s credentials when hashing.
* &lt;p/&gt;
* If enabled, the salt used will be obtained via the {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getCredentialsSalt} method.
* &lt;/p&gt;
* The default value is {@code false}.
*
* @param hashSalted whether or not to salt a submitted {@code AuthenticationToken}'s credentials when hashing.
* @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo}
* returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its
* {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value.
* This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return
* {@code SaltedAuthenticationInfo} instances, but &lt;b&gt;it is highly recommended that {@code Realm} implementations
* that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo}
* instances as soon as possible&lt;/b&gt;.
* &lt;p/&gt;
* 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.
*/
@Deprecated
public void setHashSalted(boolean hashSalted) {
<span class="fc" id="L264"> this.hashSalted = hashSalted;</span>
<span class="fc" id="L265"> }</span>
/**
* Returns the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before
* comparing to the credentials stored in the system.
* &lt;p/&gt;
* Unless overridden, the default value is {@code 1}, meaning a normal hash execution will occur.
*
* @return the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before
* comparing to the credentials stored in the system.
*/
public int getHashIterations() {
<span class="fc" id="L277"> return hashIterations;</span>
}
/**
* Sets the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before comparing
* to the credentials stored in the system.
* &lt;p/&gt;
* Unless overridden, the default value is {@code 1}, meaning a normal single hash execution will occur.
* &lt;p/&gt;
* 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).
*
* @param hashIterations the number of times to hash a submitted {@code AuthenticationToken}'s credentials.
*/
public void setHashIterations(int hashIterations) {
<span class="nc bnc" id="L292" title="All 2 branches missed."> if (hashIterations &lt; 1) {</span>
<span class="nc" id="L293"> this.hashIterations = 1;</span>
} else {
<span class="nc" id="L295"> this.hashIterations = hashIterations;</span>
}
<span class="nc" id="L297"> }</span>
/**
* Returns a salt value used to hash the token's credentials.
* &lt;p/&gt;
* This default implementation merely returns {@code 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.
*
* @param token the AuthenticationToken submitted during the authentication attempt.
* @return a salt value to use to hash the authentication token's credentials.
* @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo}
* returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its
* {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value.
* This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return
* {@code SaltedAuthenticationInfo} instances, but &lt;b&gt;it is highly recommended that {@code Realm} implementations
* that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo}
* instances as soon as possible&lt;/b&gt;.&lt;p/&gt;
* 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.
*/
@Deprecated
protected Object getSalt(AuthenticationToken token) {
<span class="fc" id="L322"> return token.getPrincipal();</span>
}
/**
* Returns a {@link Hash Hash} instance representing the already-hashed AuthenticationInfo credentials stored in the system.
* &lt;p/&gt;
* This method reconstructs a {@link Hash Hash} instance based on a {@code info.getCredentials} call,
* but it does &lt;em&gt;not&lt;/em&gt; hash that value - it is expected that method call will return an already-hashed value.
* &lt;p/&gt;
* This implementation's reconstruction effort functions as follows:
* &lt;ol&gt;
* &lt;li&gt;Convert {@code account.getCredentials()} to a byte array via the {@link #toBytes toBytes} method.
* &lt;li&gt;If {@code account.getCredentials()} was originally a String or char[] before {@code toBytes} was
* called, check for encoding:
* &lt;li&gt;If {@link #storedCredentialsHexEncoded storedCredentialsHexEncoded}, Hex decode that byte array, otherwise
* Base64 decode the byte array&lt;/li&gt;
* &lt;li&gt;Set the byte[] array directly on the {@code Hash} implementation and return it.&lt;/li&gt;
* &lt;/ol&gt;
*
* @param info the AuthenticationInfo from which to retrieve the credentials which assumed to be in already-hashed form.
* @return a {@link Hash Hash} instance representing the given AuthenticationInfo's stored credentials.
*/
protected Object getCredentials(AuthenticationInfo info) {
<span class="fc" id="L345"> Object credentials = info.getCredentials();</span>
<span class="fc" id="L347"> byte[] storedBytes = toBytes(credentials);</span>
<span class="fc bfc" id="L349" title="All 4 branches covered."> if (credentials instanceof String || credentials instanceof char[]) {</span>
//account.credentials were a char[] or String, so
//we need to do text decoding first:
<span class="pc bpc" id="L352" title="1 of 2 branches missed."> if (isStoredCredentialsHexEncoded()) {</span>
<span class="fc" id="L353"> storedBytes = Hex.decode(storedBytes);</span>
} else {
<span class="nc" id="L355"> storedBytes = Base64.decode(storedBytes);</span>
}
}
<span class="fc" id="L358"> AbstractHash hash = newHashInstance();</span>
<span class="fc" id="L359"> hash.setBytes(storedBytes);</span>
<span class="fc" id="L360"> return hash;</span>
}
/**
* This implementation first hashes the {@code token}'s credentials, potentially using a
* {@code salt} if the {@code info} argument is a
* {@link org.apache.shiro.authc.SaltedAuthenticationInfo SaltedAuthenticationInfo}. It then compares the hash
* against the {@code AuthenticationInfo}'s
* {@link #getCredentials(org.apache.shiro.authc.AuthenticationInfo) already-hashed credentials}. This method
* returns {@code true} if those two values are {@link #equals(Object, Object) equal}, {@code false} otherwise.
*
* @param token the {@code AuthenticationToken} submitted during the authentication attempt.
* @param info the {@code AuthenticationInfo} stored in the system matching the token principal
* @return {@code true} if the provided token credentials hash match to the stored account credentials hash,
* {@code false} otherwise
* @since 1.1
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
<span class="fc" id="L379"> Object tokenHashedCredentials = hashProvidedCredentials(token, info);</span>
<span class="fc" id="L380"> Object accountCredentials = getCredentials(info);</span>
<span class="fc" id="L381"> return equals(tokenHashedCredentials, accountCredentials);</span>
}
/**
* Hash the provided {@code token}'s credentials using the salt stored with the account if the
* {@code info} instance is an {@code instanceof} {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} (see
* the class-level JavaDoc for why this is the preferred approach).
* &lt;p/&gt;
* If the {@code info} instance is &lt;em&gt;not&lt;/em&gt;
* an {@code instanceof} {@code SaltedAuthenticationInfo}, the logic will fall back to Shiro 1.0
* backwards-compatible logic: it will first check to see {@link #isHashSalted() isHashSalted} and if so, will try
* to acquire the salt from {@link #getSalt(AuthenticationToken) getSalt(AuthenticationToken)}. See the class-level
* JavaDoc for why this is not recommended. This 'fallback' logic exists only for backwards-compatibility.
* {@code Realm}s should be updated as soon as possible to return {@code SaltedAuthenticationInfo} instances
* if account credentials salting is enabled (highly recommended for password-based systems).
*
* @param token the submitted authentication token from which its credentials will be hashed
* @param info the stored account data, potentially used to acquire a salt
* @return the token credentials hash
* @since 1.1
*/
protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) {
<span class="fc" id="L403"> Object salt = null;</span>
<span class="fc bfc" id="L404" title="All 2 branches covered."> if (info instanceof SaltedAuthenticationInfo) {</span>
<span class="fc" id="L405"> salt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();</span>
} else {
//retain 1.0 backwards compatibility:
<span class="fc bfc" id="L408" title="All 2 branches covered."> if (isHashSalted()) {</span>
<span class="fc" id="L409"> salt = getSalt(token);</span>
}
}
<span class="fc" id="L412"> return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations());</span>
}
/**
* Returns the {@link #getHashAlgorithmName() hashAlgorithmName} property, but will throw an
* {@link IllegalStateException} if it has not been set.
*
* @return the required {@link #getHashAlgorithmName() hashAlgorithmName} property
* @throws IllegalStateException if the property has not been set prior to calling this method.
* @since 1.1
*/
private String assertHashAlgorithmName() throws IllegalStateException {
<span class="fc" id="L424"> String hashAlgorithmName = getHashAlgorithmName();</span>
<span class="pc bpc" id="L425" title="1 of 2 branches missed."> if (hashAlgorithmName == null) {</span>
<span class="nc" id="L426"> String msg = &quot;Required 'hashAlgorithmName' property has not been set. This is required to execute &quot; +</span>
&quot;the hashing algorithm.&quot;;
<span class="nc" id="L428"> throw new IllegalStateException(msg);</span>
}
<span class="fc" id="L430"> return hashAlgorithmName;</span>
}
/**
* Hashes the provided credentials a total of {@code hashIterations} times, using the given salt. The hash
* implementation/algorithm used is based on the {@link #getHashAlgorithmName() hashAlgorithmName} property.
*
* @param credentials the submitted authentication token's credentials to hash
* @param salt the value to salt the hash, or {@code null} if a salt will not be used.
* @param 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.
* @return the hashed value of the provided credentials, according to the specified salt and hash iterations.
*/
protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
<span class="fc" id="L444"> String hashAlgorithmName = assertHashAlgorithmName();</span>
<span class="fc" id="L445"> return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);</span>
}
/**
* Returns a new, &lt;em&gt;uninitialized&lt;/em&gt; instance, without its byte array set. Used as a utility method in the
* {@link SimpleCredentialsMatcher#getCredentials(org.apache.shiro.authc.AuthenticationInfo) getCredentials(AuthenticationInfo)} implementation.
*
* @return a new, &lt;em&gt;uninitialized&lt;/em&gt; instance, without its byte array set.
*/
protected AbstractHash newHashInstance() {
<span class="fc" id="L455"> String hashAlgorithmName = assertHashAlgorithmName();</span>
<span class="fc" id="L456"> return new SimpleHash(hashAlgorithmName);</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html>