blob: 46d3d6f9d0e19442a7eb45b0d1d87afda76f1730 [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>AuthenticatingRealm.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 :: All (aggregate jar)</a> &gt; <a href="../index.html" class="el_bundle">shiro-core</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.realm</a> &gt; <span class="el_source">AuthenticatingRealm.java</span></div><h1>AuthenticatingRealm.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.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.Initializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A top-level abstract implementation of the &lt;tt&gt;Realm&lt;/tt&gt; interface that only implements authentication support
* (log-in) operations and leaves authorization (access control) behavior to subclasses.
* &lt;h2&gt;Authentication Caching&lt;/h2&gt;
* For applications that perform frequent repeated authentication of the same accounts (e.g. as is often done in
* REST or Soap applications that authenticate on every request), it might be prudent to enable authentication
* caching to alleviate constant load on any back-end data sources.
* &lt;p/&gt;
* This feature is disabled by default to retain backwards-compatibility with Shiro 1.1 and earlier. It may be
* enabled by setting {@link #setAuthenticationCachingEnabled(boolean) authenticationCachingEnabled} = {@code true}
* (and configuring Shiro with a {@link CacheManager} of course), but &lt;b&gt;NOTE:&lt;/b&gt;
* &lt;p/&gt;
* &lt;b&gt;ONLY enable authentication caching if either of the following is true for your realm implementation:&lt;/b&gt;
* &lt;ul&gt;
* &lt;li&gt;The {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}
* implementation returns {@code AuthenticationInfo} instances where the
* {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are securely obfuscated and NOT
* plaintext (raw) credentials. For example,
* if your realm references accounts with passwords, that the {@code AuthenticationInfo}'s
* {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are safely hashed and salted or otherwise
* fully encrypted.&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;
* &lt;li&gt;The {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}
* implementation returns {@code AuthenticationInfo} instances where the
* {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are plaintext (raw) &lt;b&gt;AND&lt;/b&gt; the
* cache region storing the {@code AuthenticationInfo} instances WILL NOT overflow to disk and WILL NOT transmit cache
* entries over an unprotected (non TLS/SSL) network (as might be the case with a networked/distributed enterprise cache).
* This should be the case even in private/trusted/corporate networks.&lt;/li&gt;
* &lt;/ul&gt;
* &lt;p/&gt;
* These points are very important because if authentication caching is enabled, this abstract class implementation
* will place AuthenticationInfo instances returned from the subclass implementations directly into the cache, for
* example:
* &lt;pre&gt;
* cache.put(cacheKey, subclassAuthenticationInfoInstance);
* &lt;/pre&gt;
* &lt;p/&gt;
* Enabling authentication caching is ONLY safe to do if the above two scenarios apply. It is NOT safe to enable under
* any other scenario.
* &lt;p/&gt;
* When possible, always represent and store credentials in a safe form (hash+salt or encrypted) to eliminate plaintext
* visibility.
* &lt;h3&gt;Authentication Cache Invalidation on Logout&lt;/h3&gt;
* If authentication caching is enabled, this implementation will attempt to evict (remove) cached authentication data
* for an account during logout. This can only occur if the
* {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} and
* {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} methods return the exact same value.
* &lt;p/&gt;
* The default implementations of these methods expect that the
* {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal()} (what the user submits during login) and
* {@link #getAvailablePrincipal(org.apache.shiro.subject.PrincipalCollection) getAvailablePrincipal} (what is returned
* by the realm after account lookup) return
* the same exact value. For example, the user submitted username is also the primary account identifier.
* &lt;p/&gt;
* However, if your application uses, say, a username for end-user login, but returns a primary key ID as the
* primary principal after authentication, then you will need to override either
* {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken) getAuthenticationCacheKey(token)} or
* {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection) getAuthenticationCacheKey(principals)}
* (or both) to ensure that the same cache key can be used for either object.
* &lt;p/&gt;
* This guarantees that the same cache key used to cache the data during authentication (derived from the
* {@code AuthenticationToken}) will be used to remove the cached data during logout (derived from the
* {@code PrincipalCollection}).
* &lt;h4&gt;Unmatching Cache Key Values&lt;/h4&gt;
* If the return values from {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} and
* {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} are not identical, cached
* authentication data removal is at the mercy of your cache provider settings. For example, often cache
* implementations will evict cache entries based on a timeToIdle or timeToLive (TTL) value.
* &lt;p/&gt;
* If this lazy eviction capability of the cache product is not sufficient and you want discrete behavior
* (highly recommended for authentication data), ensure that the return values from those two methods are identical in
* the subclass implementation.
*
* @since 0.2
*/
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {
//TODO - complete JavaDoc
<span class="fc" id="L117"> private static final Logger log = LoggerFactory.getLogger(AuthenticatingRealm.class);</span>
<span class="fc" id="L119"> private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger();</span>
/**
* The default suffix appended to the realm name used for caching authentication data.
*
* @since 1.2
*/
private static final String DEFAULT_AUTHORIZATION_CACHE_SUFFIX = &quot;.authenticationCache&quot;;
/**
* Credentials matcher used to determine if the provided credentials match the credentials stored in the data store.
*/
private CredentialsMatcher credentialsMatcher;
private Cache&lt;Object, AuthenticationInfo&gt; authenticationCache;
private boolean authenticationCachingEnabled;
private String authenticationCacheName;
/**
* The class that this realm supports for authentication tokens. This is used by the
* default implementation of the {@link Realm#supports(org.apache.shiro.authc.AuthenticationToken)} method to
* determine whether or not the given authentication token is supported by this realm.
*/
private Class&lt;? extends AuthenticationToken&gt; authenticationTokenClass;
/*-------------------------------------------
| C O N S T R U C T O R S |
============================================*/
public AuthenticatingRealm() {
<span class="fc" id="L150"> this(null, new SimpleCredentialsMatcher());</span>
<span class="fc" id="L151"> }</span>
public AuthenticatingRealm(CacheManager cacheManager) {
<span class="fc" id="L154"> this(cacheManager, new SimpleCredentialsMatcher());</span>
<span class="fc" id="L155"> }</span>
public AuthenticatingRealm(CredentialsMatcher matcher) {
<span class="fc" id="L158"> this(null, matcher);</span>
<span class="fc" id="L159"> }</span>
<span class="fc" id="L161"> public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {</span>
<span class="fc" id="L162"> authenticationTokenClass = UsernamePasswordToken.class;</span>
//retain backwards compatibility for Shiro 1.1 and earlier. Setting to true by default will probably cause
//unexpected results for existing applications:
<span class="fc" id="L166"> this.authenticationCachingEnabled = false;</span>
<span class="fc" id="L168"> int instanceNumber = INSTANCE_COUNT.getAndIncrement();</span>
<span class="fc" id="L169"> this.authenticationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;</span>
<span class="fc bfc" id="L170" title="All 2 branches covered."> if (instanceNumber &gt; 0) {</span>
<span class="fc" id="L171"> this.authenticationCacheName = this.authenticationCacheName + &quot;.&quot; + instanceNumber;</span>
}
<span class="fc bfc" id="L174" title="All 2 branches covered."> if (cacheManager != null) {</span>
<span class="fc" id="L175"> setCacheManager(cacheManager);</span>
}
<span class="pc bpc" id="L177" title="1 of 2 branches missed."> if (matcher != null) {</span>
<span class="fc" id="L178"> setCredentialsMatcher(matcher);</span>
}
<span class="fc" id="L180"> }</span>
/*--------------------------------------------
| A C C E S S O R S / M O D I F I E R S |
============================================*/
/**
* Returns the &lt;code&gt;CredentialsMatcher&lt;/code&gt; used during an authentication attempt to verify submitted
* credentials with those stored in the system.
* &lt;p/&gt;
* &lt;p&gt;Unless overridden by the {@link #setCredentialsMatcher setCredentialsMatcher} method, the default
* value is a {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher SimpleCredentialsMatcher} instance.
*
* @return the &lt;code&gt;CredentialsMatcher&lt;/code&gt; used during an authentication attempt to verify submitted
* credentials with those stored in the system.
*/
public CredentialsMatcher getCredentialsMatcher() {
<span class="fc" id="L197"> return credentialsMatcher;</span>
}
/**
* Sets the CrendialsMatcher used during an authentication attempt to verify submitted credentials with those
* stored in the system. The implementation of this matcher can be switched via configuration to
* support any number of schemes, including plain text comparisons, hashing comparisons, and others.
* &lt;p/&gt;
* &lt;p&gt;Unless overridden by this method, the default value is a
* {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher} instance.
*
* @param credentialsMatcher the matcher to use.
*/
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
<span class="fc" id="L211"> this.credentialsMatcher = credentialsMatcher;</span>
<span class="fc" id="L212"> }</span>
/**
* Returns the authenticationToken class supported by this realm.
* &lt;p/&gt;
* &lt;p&gt;The default value is &lt;tt&gt;{@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken.class}&lt;/tt&gt;, since
* about 90% of realms use username/password authentication, regardless of their protocol (e.g. over jdbc, ldap,
* kerberos, http, etc).
* &lt;p/&gt;
* &lt;p&gt;If subclasses haven't already overridden the {@link Realm#supports Realm.supports(AuthenticationToken)} method,
* they must {@link #setAuthenticationTokenClass(Class) set a new class} if they won't support
* &lt;tt&gt;UsernamePasswordToken&lt;/tt&gt; authentication token submissions.
*
* @return the authenticationToken class supported by this realm.
* @see #setAuthenticationTokenClass
*/
public Class getAuthenticationTokenClass() {
<span class="fc" id="L229"> return authenticationTokenClass;</span>
}
/**
* Sets the authenticationToken class supported by this realm.
* &lt;p/&gt;
* &lt;p&gt;Unless overridden by this method, the default value is
* {@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken.class} to support the majority of applications.
*
* @param authenticationTokenClass the class of authentication token instances supported by this realm.
* @see #getAuthenticationTokenClass getAuthenticationTokenClass() for more explanation.
*/
public void setAuthenticationTokenClass(Class&lt;? extends AuthenticationToken&gt; authenticationTokenClass) {
<span class="fc" id="L242"> this.authenticationTokenClass = authenticationTokenClass;</span>
<span class="fc" id="L243"> }</span>
/**
* Sets an explicit {@link Cache} instance to use for authentication caching. If not set and authentication
* caching is {@link #isAuthenticationCachingEnabled() enabled}, any available
* {@link #getCacheManager() cacheManager} will be used to acquire the cache instance if available.
* &lt;p/&gt;
* &lt;b&gt;WARNING:&lt;/b&gt; Only set this property if safe caching conditions apply, as documented at the top
* of this page in the class-level JavaDoc.
*
* @param authenticationCache an explicit {@link Cache} instance to use for authentication caching or
* {@code null} if the cache should possibly be obtained another way.
* @see #isAuthenticationCachingEnabled()
* @since 1.2
*/
public void setAuthenticationCache(Cache&lt;Object, AuthenticationInfo&gt; authenticationCache) {
<span class="fc" id="L259"> this.authenticationCache = authenticationCache;</span>
<span class="fc" id="L260"> }</span>
/**
* Returns a {@link Cache} instance to use for authentication caching, or {@code null} if no cache has been
* set.
*
* @return a {@link Cache} instance to use for authentication caching, or {@code null} if no cache has been
* set.
* @see #setAuthenticationCache(org.apache.shiro.cache.Cache)
* @see #isAuthenticationCachingEnabled()
* @since 1.2
*/
public Cache&lt;Object, AuthenticationInfo&gt; getAuthenticationCache() {
<span class="fc" id="L273"> return this.authenticationCache;</span>
}
/**
* Returns the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
* a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
* &lt;p/&gt;
* This name will only be used to look up a cache if authentication caching is
* {@link #isAuthenticationCachingEnabled() enabled}.
* &lt;p/&gt;
* &lt;b&gt;WARNING:&lt;/b&gt; Only set this property if safe caching conditions apply, as documented at the top
* of this page in the class-level JavaDoc.
*
* @return the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
* a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
* @see #isAuthenticationCachingEnabled()
* @since 1.2
*/
public String getAuthenticationCacheName() {
<span class="fc" id="L292"> return this.authenticationCacheName;</span>
}
/**
* Sets the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
* a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
* &lt;p/&gt;
* This name will only be used to look up a cache if authentication caching is
* {@link #isAuthenticationCachingEnabled() enabled}.
*
* @param authenticationCacheName the name of a {@link Cache} to lookup from any available
* {@link #getCacheManager() cacheManager} if a cache is not explicitly configured
* via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
* @see #isAuthenticationCachingEnabled()
* @since 1.2
*/
public void setAuthenticationCacheName(String authenticationCacheName) {
<span class="fc" id="L309"> this.authenticationCacheName = authenticationCacheName;</span>
<span class="fc" id="L310"> }</span>
/**
* Returns {@code true} if authentication caching should be utilized if a {@link CacheManager} has been
* {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise.
* &lt;p/&gt;
* The default value is {@code true}.
*
* @return {@code true} if authentication caching should be utilized, {@code false} otherwise.
*/
public boolean isAuthenticationCachingEnabled() {
<span class="pc bpc" id="L321" title="1 of 4 branches missed."> return this.authenticationCachingEnabled &amp;&amp; isCachingEnabled();</span>
}
/**
* Sets whether or not authentication caching should be utilized if a {@link CacheManager} has been
* {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise.
* &lt;p/&gt;
* The default value is {@code false} to retain backwards compatibility with Shiro 1.1 and earlier.
* &lt;p/&gt;
* &lt;b&gt;WARNING:&lt;/b&gt; Only set this property to {@code true} if safe caching conditions apply, as documented at the top
* of this page in the class-level JavaDoc.
*
* @param authenticationCachingEnabled the value to set
*/
@SuppressWarnings({&quot;UnusedDeclaration&quot;})
public void setAuthenticationCachingEnabled(boolean authenticationCachingEnabled) {
<span class="fc" id="L337"> this.authenticationCachingEnabled = authenticationCachingEnabled;</span>
<span class="pc bpc" id="L338" title="1 of 2 branches missed."> if (authenticationCachingEnabled) {</span>
<span class="fc" id="L339"> setCachingEnabled(true);</span>
}
<span class="fc" id="L341"> }</span>
public void setName(String name) {
<span class="fc" id="L344"> super.setName(name);</span>
<span class="fc" id="L345"> String authcCacheName = this.authenticationCacheName;</span>
<span class="pc bpc" id="L346" title="2 of 4 branches missed."> if (authcCacheName != null &amp;&amp; authcCacheName.startsWith(getClass().getName())) {</span>
//get rid of the default heuristically-created cache name. Create a more meaningful one
//based on the application-unique Realm name:
<span class="fc" id="L349"> this.authenticationCacheName = name + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;</span>
}
<span class="fc" id="L351"> }</span>
/*--------------------------------------------
| M E T H O D S |
============================================*/
/**
* Convenience implementation that returns
* &lt;tt&gt;getAuthenticationTokenClass().isAssignableFrom( token.getClass() );&lt;/tt&gt;. Can be overridden
* by subclasses for more complex token checking.
* &lt;p&gt;Most configurations will only need to set a different class via
* {@link #setAuthenticationTokenClass}, as opposed to overriding this method.
*
* @param token the token being submitted for authentication.
* @return true if this authentication realm can process the submitted token instance of the class, false otherwise.
*/
public boolean supports(AuthenticationToken token) {
<span class="pc bpc" id="L369" title="2 of 4 branches missed."> return token != null &amp;&amp; getAuthenticationTokenClass().isAssignableFrom(token.getClass());</span>
}
/**
* Initializes this realm and potentially enables an authentication cache, depending on configuration. Based on
* the availability of an authentication cache, this class functions as follows:
* &lt;ol&gt;
* &lt;li&gt;If the {@link #setAuthenticationCache cache} property has been set, it will be
* used to cache the AuthenticationInfo objects returned from {@link #getAuthenticationInfo}
* method invocations.
* All future calls to {@link #getAuthenticationInfo} will attempt to use this cache first
* to alleviate any potentially unnecessary calls to an underlying data store.&lt;/li&gt;
* &lt;li&gt;If the {@link #setAuthenticationCache cache} property has &lt;b&gt;not&lt;/b&gt; been set,
* the {@link #setCacheManager cacheManager} property will be checked.
* If a {@code cacheManager} has been set, it will be used to eagerly acquire an authentication
* {@code cache}, and this cache which will be used as specified in #1.&lt;/li&gt;
* &lt;li&gt;If neither the {@link #setAuthenticationCache (org.apache.shiro.cache.Cache) authenticationCache}
* or {@link #setCacheManager(org.apache.shiro.cache.CacheManager) cacheManager}
* properties are set, caching will not be utilized and authentication look-ups will be delegated to
* subclass implementations for each authentication attempt.&lt;/li&gt;
* &lt;/ol&gt;
* &lt;p/&gt;
* This method finishes by calling {@link #onInit()} is to allow subclasses to perform any init behavior desired.
*
* @since 1.2
*/
public final void init() {
//trigger obtaining the authorization cache if possible
<span class="fc" id="L397"> getAvailableAuthenticationCache();</span>
<span class="fc" id="L398"> onInit();</span>
<span class="fc" id="L399"> }</span>
/**
* Template method for subclasses to implement any initialization logic. Called from
* {@link #init()}.
*
* @since 1.2
*/
protected void onInit() {
<span class="fc" id="L408"> }</span>
/**
* This implementation attempts to acquire an authentication cache if one is not already configured.
*
* @since 1.2
*/
protected void afterCacheManagerSet() {
//trigger obtaining the authorization cache if possible
<span class="fc" id="L417"> getAvailableAuthenticationCache();</span>
<span class="fc" id="L418"> }</span>
/**
* Returns any available {@link Cache} instance to use for authentication caching. This functions as follows:
* &lt;ol&gt;
* &lt;li&gt;If an {@link #setAuthenticationCache(org.apache.shiro.cache.Cache) authenticationCache} has been explicitly
* configured (it is not null), it is returned.&lt;/li&gt;
* &lt;li&gt;If there is no {@link #getAuthenticationCache() authenticationCache} configured:
* &lt;ol&gt;
* &lt;li&gt;If authentication caching is {@link #isAuthenticationCachingEnabled() enabled}, any available
* {@link #getCacheManager() cacheManager} will be consulted to obtain an available authentication cache.
* &lt;/li&gt;
* &lt;li&gt;If authentication caching is disabled, this implementation does nothing.&lt;/li&gt;
* &lt;/ol&gt;
* &lt;/li&gt;
* &lt;/ol&gt;
*
* @return any available {@link Cache} instance to use for authentication caching.
*/
private Cache&lt;Object, AuthenticationInfo&gt; getAvailableAuthenticationCache() {
<span class="fc" id="L438"> Cache&lt;Object, AuthenticationInfo&gt; cache = getAuthenticationCache();</span>
<span class="fc" id="L439"> boolean authcCachingEnabled = isAuthenticationCachingEnabled();</span>
<span class="fc bfc" id="L440" title="All 4 branches covered."> if (cache == null &amp;&amp; authcCachingEnabled) {</span>
<span class="fc" id="L441"> cache = getAuthenticationCacheLazy();</span>
}
<span class="fc" id="L443"> return cache;</span>
}
/**
* Checks to see if the authenticationCache class attribute is null, and if so, attempts to acquire one from
* any configured {@link #getCacheManager() cacheManager}. If one is acquired, it is set as the class attribute.
* The class attribute is then returned.
*
* @return an available cache instance to be used for authentication caching or {@code null} if one is not available.
* @since 1.2
*/
private Cache&lt;Object, AuthenticationInfo&gt; getAuthenticationCacheLazy() {
<span class="pc bpc" id="L456" title="1 of 2 branches missed."> if (this.authenticationCache == null) {</span>
<span class="fc" id="L458"> log.trace(&quot;No authenticationCache instance set. Checking for a cacheManager...&quot;);</span>
<span class="fc" id="L460"> CacheManager cacheManager = getCacheManager();</span>
<span class="pc bpc" id="L462" title="1 of 2 branches missed."> if (cacheManager != null) {</span>
<span class="fc" id="L463"> String cacheName = getAuthenticationCacheName();</span>
<span class="fc" id="L464"> log.debug(&quot;CacheManager [{}] configured. Building authentication cache '{}'&quot;, cacheManager, cacheName);</span>
<span class="fc" id="L465"> this.authenticationCache = cacheManager.getCache(cacheName);</span>
}
}
<span class="fc" id="L469"> return this.authenticationCache;</span>
}
/**
* Returns any cached AuthenticationInfo corresponding to the specified token or {@code null} if there currently
* isn't any cached data.
*
* @param token the token submitted during the authentication attempt.
* @return any cached AuthenticationInfo corresponding to the specified token or {@code null} if there currently
* isn't any cached data.
* @since 1.2
*/
private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token) {
<span class="fc" id="L482"> AuthenticationInfo info = null;</span>
<span class="fc" id="L484"> Cache&lt;Object, AuthenticationInfo&gt; cache = getAvailableAuthenticationCache();</span>
<span class="pc bpc" id="L485" title="1 of 4 branches missed."> if (cache != null &amp;&amp; token != null) {</span>
<span class="fc" id="L486"> log.trace(&quot;Attempting to retrieve the AuthenticationInfo from cache.&quot;);</span>
<span class="fc" id="L487"> Object key = getAuthenticationCacheKey(token);</span>
<span class="fc" id="L488"> info = cache.get(key);</span>
<span class="fc bfc" id="L489" title="All 2 branches covered."> if (info == null) {</span>
<span class="fc" id="L490"> log.trace(&quot;No AuthorizationInfo found in cache for key [{}]&quot;, key);</span>
} else {
<span class="fc" id="L492"> log.trace(&quot;Found cached AuthorizationInfo for key [{}]&quot;, key);</span>
}
}
<span class="fc" id="L496"> return info;</span>
}
/**
* Caches the specified info if authentication caching
* {@link #isAuthenticationCachingEnabled(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) isEnabled}
* for the specific token/info pair and a cache instance is available to be used.
*
* @param token the authentication token submitted which resulted in a successful authentication attempt.
* @param info the AuthenticationInfo to cache as a result of the successful authentication attempt.
* @since 1.2
*/
private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) {
<span class="fc bfc" id="L509" title="All 2 branches covered."> if (!isAuthenticationCachingEnabled(token, info)) {</span>
<span class="fc" id="L510"> log.debug(&quot;AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].&quot;, info, token);</span>
//return quietly, caching is disabled for this token/info pair:
<span class="fc" id="L512"> return;</span>
}
<span class="fc" id="L515"> Cache&lt;Object, AuthenticationInfo&gt; cache = getAvailableAuthenticationCache();</span>
<span class="pc bpc" id="L516" title="1 of 2 branches missed."> if (cache != null) {</span>
<span class="fc" id="L517"> Object key = getAuthenticationCacheKey(token);</span>
<span class="fc" id="L518"> cache.put(key, info);</span>
<span class="fc" id="L519"> log.trace(&quot;Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].&quot;, key, info);</span>
}
<span class="fc" id="L521"> }</span>
/**
* Returns {@code true} if authentication caching should be utilized based on the specified
* {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise.
* &lt;p/&gt;
* The default implementation simply delegates to {@link #isAuthenticationCachingEnabled()}, the general-case
* authentication caching setting. Subclasses can override this to turn on or off caching at runtime
* based on the specific submitted runtime values.
*
* @param token the submitted authentication token
* @param info the {@code AuthenticationInfo} acquired from data source lookup via
* {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)}
* @return {@code true} if authentication caching should be utilized based on the specified
* {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise.
* @since 1.2
*/
protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, AuthenticationInfo info) {
<span class="fc" id="L539"> return isAuthenticationCachingEnabled();</span>
}
/**
* This implementation functions as follows:
* &lt;ol&gt;
* &lt;li&gt;It attempts to acquire any cached {@link AuthenticationInfo} corresponding to the specified
* {@link AuthenticationToken} argument. If a cached value is found, it will be used for credentials matching,
* alleviating the need to perform any lookups with a data source.&lt;/li&gt;
* &lt;li&gt;If there is no cached {@link AuthenticationInfo} found, delegate to the
* {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} method to perform the actual
* lookup. If authentication caching is enabled and possible, any returned info object will be
* {@link #cacheAuthenticationInfoIfPossible(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) cached}
* to be used in future authentication attempts.&lt;/li&gt;
* &lt;li&gt;If an AuthenticationInfo instance is not found in the cache or by lookup, {@code null} is returned to
* indicate an account cannot be found.&lt;/li&gt;
* &lt;li&gt;If an AuthenticationInfo instance is found (either cached or via lookup), ensure the submitted
* AuthenticationToken's credentials match the expected {@code AuthenticationInfo}'s credentials using the
* {@link #getCredentialsMatcher() credentialsMatcher}. This means that credentials are always verified
* for an authentication attempt.&lt;/li&gt;
* &lt;/ol&gt;
*
* @param token the submitted account principal and credentials.
* @return the AuthenticationInfo corresponding to the given {@code token}, or {@code null} if no
* AuthenticationInfo could be found.
* @throws AuthenticationException if authentication failed.
*/
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
<span class="fc" id="L568"> AuthenticationInfo info = getCachedAuthenticationInfo(token);</span>
<span class="fc bfc" id="L569" title="All 2 branches covered."> if (info == null) {</span>
//otherwise not cached, perform the lookup:
<span class="fc" id="L571"> info = doGetAuthenticationInfo(token);</span>
<span class="fc" id="L572"> log.debug(&quot;Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo&quot;, info);</span>
<span class="pc bpc" id="L573" title="1 of 4 branches missed."> if (token != null &amp;&amp; info != null) {</span>
<span class="fc" id="L574"> cacheAuthenticationInfoIfPossible(token, info);</span>
}
} else {
<span class="fc" id="L577"> log.debug(&quot;Using cached authentication info [{}] to perform credentials matching.&quot;, info);</span>
}
<span class="fc bfc" id="L580" title="All 2 branches covered."> if (info != null) {</span>
<span class="fc" id="L581"> assertCredentialsMatch(token, info);</span>
} else {
<span class="fc" id="L583"> log.debug(&quot;No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.&quot;, token);</span>
}
<span class="fc" id="L586"> return info;</span>
}
/**
* Asserts that the submitted {@code AuthenticationToken}'s credentials match the stored account
* {@code AuthenticationInfo}'s credentials, and if not, throws an {@link AuthenticationException}.
*
* @param token the submitted authentication token
* @param info the AuthenticationInfo corresponding to the given {@code token}
* @throws AuthenticationException if the token's credentials do not match the stored account credentials.
*/
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
<span class="fc" id="L598"> CredentialsMatcher cm = getCredentialsMatcher();</span>
<span class="fc bfc" id="L599" title="All 2 branches covered."> if (cm != null) {</span>
<span class="fc bfc" id="L600" title="All 2 branches covered."> if (!cm.doCredentialsMatch(token, info)) {</span>
//not successful - throw an exception to indicate this:
<span class="fc" id="L602"> String msg = &quot;Submitted credentials for token [&quot; + token + &quot;] did not match the expected credentials.&quot;;</span>
<span class="fc" id="L603"> throw new IncorrectCredentialsException(msg);</span>
}
} else {
<span class="fc" id="L606"> throw new AuthenticationException(&quot;A CredentialsMatcher must be configured in order to verify &quot; +</span>
&quot;credentials during authentication. If you do not wish for credentials to be examined, you &quot; +
<span class="fc" id="L608"> &quot;can configure an &quot; + AllowAllCredentialsMatcher.class.getName() + &quot; instance.&quot;);</span>
}
<span class="fc" id="L610"> }</span>
/**
* Returns the key under which {@link AuthenticationInfo} instances are cached if authentication caching is enabled.
* This implementation defaults to returning the token's
* {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal() principal}, which is usually a username in
* most applications.
* &lt;h3&gt;Cache Invalidation on Logout&lt;/h3&gt;
* &lt;b&gt;NOTE:&lt;/b&gt; If you want to be able to invalidate an account's cached {@code AuthenticationInfo} on logout, you
* must ensure the {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} method returns
* the same value as this method.
*
* @param token the authentication token for which any successful authentication will be cached.
* @return the cache key to use to cache the associated {@link AuthenticationInfo} after a successful authentication.
* @since 1.2
*/
protected Object getAuthenticationCacheKey(AuthenticationToken token) {
<span class="pc bpc" id="L627" title="1 of 2 branches missed."> return token != null ? token.getPrincipal() : null;</span>
}
/**
* Returns the key under which {@link AuthenticationInfo} instances are cached if authentication caching is enabled.
* This implementation delegates to
* {@link #getAvailablePrincipal(org.apache.shiro.subject.PrincipalCollection)}, which returns the primary principal
* associated with this particular Realm.
* &lt;h3&gt;Cache Invalidation on Logout&lt;/h3&gt;
* &lt;b&gt;NOTE:&lt;/b&gt; If you want to be able to invalidate an account's cached {@code AuthenticationInfo} on logout, you
* must ensure that this method returns the same value as the
* {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} method!
*
* @param principals the principals of the account for which to set or remove cached {@code AuthenticationInfo}.
* @return the cache key to use when looking up cached {@link AuthenticationInfo} instances.
* @since 1.2
*/
protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
<span class="fc" id="L645"> return getAvailablePrincipal(principals);</span>
}
/**
* This implementation clears out any cached authentication data by calling
* {@link #clearCachedAuthenticationInfo(org.apache.shiro.subject.PrincipalCollection)}.
* If overriding in a subclass, be sure to call {@code super.doClearCache} to ensure this behavior is maintained.
*
* @param principals principals the principals of the account for which to clear any cached data.
* @since 1.2
*/
@Override
protected void doClearCache(PrincipalCollection principals) {
<span class="fc" id="L658"> super.doClearCache(principals);</span>
<span class="fc" id="L659"> clearCachedAuthenticationInfo(principals);</span>
<span class="fc" id="L660"> }</span>
private static boolean isEmpty(PrincipalCollection pc) {
<span class="pc bpc" id="L663" title="2 of 4 branches missed."> return pc == null || pc.isEmpty();</span>
}
/**
* Clears out the AuthenticationInfo cache entry for the specified account.
* &lt;p/&gt;
* This method is provided as a convenience to subclasses so they can invalidate a cache entry when they
* change an account's authentication data (e.g. reset password) during runtime. Because an account's
* AuthenticationInfo can be cached, there needs to be a way to invalidate the cache for only that account so that
* subsequent authentication operations don't used the (old) cached value if account data changes.
* &lt;p/&gt;
* After this method is called, the next authentication for that same account will result in a call to
* {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}, and the
* resulting return value will be cached before being returned so it can be reused for later authentications.
* &lt;p/&gt;
* If you wish to clear out all associated cached data (and not just authentication data), use the
* {@link #clearCache(org.apache.shiro.subject.PrincipalCollection)} method instead (which will in turn call this
* method by default).
*
* @param principals the principals of the account for which to clear the cached AuthorizationInfo.
* @see #clearCache(org.apache.shiro.subject.PrincipalCollection)
* @since 1.2
*/
protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
<span class="pc bpc" id="L687" title="1 of 2 branches missed."> if (!isEmpty(principals)) {</span>
<span class="fc" id="L688"> Cache&lt;Object, AuthenticationInfo&gt; cache = getAvailableAuthenticationCache();</span>
//cache instance will be non-null if caching is enabled:
<span class="fc bfc" id="L690" title="All 2 branches covered."> if (cache != null) {</span>
<span class="fc" id="L691"> Object key = getAuthenticationCacheKey(principals);</span>
<span class="fc" id="L692"> cache.remove(key);</span>
}
}
<span class="fc" id="L695"> }</span>
/**
* Retrieves authentication data from an implementation-specific datasource (RDBMS, LDAP, etc) for the given
* authentication token.
* &lt;p/&gt;
* For most datasources, this means just 'pulling' authentication data for an associated subject/user and nothing
* more and letting Shiro do the rest. But in some systems, this method could actually perform EIS specific
* log-in logic in addition to just retrieving data - it is up to the Realm implementation.
* &lt;p/&gt;
* A {@code null} return value means that no account could be associated with the specified token.
*
* @param token the authentication token containing the user's principal and credentials.
* @return an {@link AuthenticationInfo} object containing account data resulting from the
* authentication ONLY if the lookup is successful (i.e. account exists and is valid, etc.)
* @throws AuthenticationException if there is an error acquiring data or performing
* realm-specific authentication logic for the specified &lt;tt&gt;token&lt;/tt&gt;
*/
protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.eclemma.org/jacoco">JaCoCo</a> 0.7.7.201606060606</span></div></body></html>