| <?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 :: Jar Bundle</a> > <a href="../index.html" class="el_bundle">shiro-core</a> > <a href="index.source.html" class="el_package">org.apache.shiro.realm</a> > <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 |
| * "License"); 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 |
| * "AS IS" 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.*; |
| 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.CollectionUtils; |
| 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 <tt>Realm</tt> interface that only implements authentication support |
| * (log-in) operations and leaves authorization (access control) behavior to subclasses. |
| * <h2>Authentication Caching</h2> |
| * 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. |
| * <p/> |
| * 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 <b>NOTE:</b> |
| * <p/> |
| * <b>ONLY enable authentication caching if either of the following is true for your realm implementation:</b> |
| * <ul> |
| * <li>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.<br/><br/></li> |
| * <li>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) <b>AND</b> 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.</li> |
| * </ul> |
| * <p/> |
| * 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: |
| * <pre> |
| * cache.put(cacheKey, subclassAuthenticationInfoInstance); |
| * </pre> |
| * <p/> |
| * Enabling authentication caching is ONLY safe to do if the above two scenarios apply. It is NOT safe to enable under |
| * any other scenario. |
| * <p/> |
| * When possible, always represent and store credentials in a safe form (hash+salt or encrypted) to eliminate plaintext |
| * visibility. |
| * <h3>Authentication Cache Invalidation on Logout</h3> |
| * 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. |
| * <p/> |
| * 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. |
| * <p/> |
| * 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. |
| * <p/> |
| * 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}). |
| * <h4>Unmatching Cache Key Values</h4> |
| * 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. |
| * <p/> |
| * 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="L114"> private static final Logger log = LoggerFactory.getLogger(AuthenticatingRealm.class);</span> |
| |
| <span class="fc" id="L116"> 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 = ".authenticationCache"; |
| |
| /** |
| * Credentials matcher used to determine if the provided credentials match the credentials stored in the data store. |
| */ |
| private CredentialsMatcher credentialsMatcher; |
| |
| |
| private Cache<Object, AuthenticationInfo> 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<? extends AuthenticationToken> authenticationTokenClass; |
| |
| /*------------------------------------------- |
| | C O N S T R U C T O R S | |
| ============================================*/ |
| public AuthenticatingRealm() { |
| <span class="fc" id="L147"> this(null, new SimpleCredentialsMatcher());</span> |
| <span class="fc" id="L148"> }</span> |
| |
| public AuthenticatingRealm(CacheManager cacheManager) { |
| <span class="fc" id="L151"> this(cacheManager, new SimpleCredentialsMatcher());</span> |
| <span class="fc" id="L152"> }</span> |
| |
| public AuthenticatingRealm(CredentialsMatcher matcher) { |
| <span class="fc" id="L155"> this(null, matcher);</span> |
| <span class="fc" id="L156"> }</span> |
| |
| <span class="fc" id="L158"> public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {</span> |
| <span class="fc" id="L159"> 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="L163"> this.authenticationCachingEnabled = false;</span> |
| |
| <span class="fc" id="L165"> int instanceNumber = INSTANCE_COUNT.getAndIncrement();</span> |
| <span class="fc" id="L166"> this.authenticationCacheName = getClass().getName() + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;</span> |
| <span class="fc bfc" id="L167" title="All 2 branches covered."> if (instanceNumber > 0) {</span> |
| <span class="fc" id="L168"> this.authenticationCacheName = this.authenticationCacheName + "." + instanceNumber;</span> |
| } |
| |
| <span class="fc bfc" id="L171" title="All 2 branches covered."> if (cacheManager != null) {</span> |
| <span class="fc" id="L172"> setCacheManager(cacheManager);</span> |
| } |
| <span class="pc bpc" id="L174" title="1 of 2 branches missed."> if (matcher != null) {</span> |
| <span class="fc" id="L175"> setCredentialsMatcher(matcher);</span> |
| } |
| <span class="fc" id="L177"> }</span> |
| |
| /*-------------------------------------------- |
| | A C C E S S O R S / M O D I F I E R S | |
| ============================================*/ |
| |
| /** |
| * Returns the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted |
| * credentials with those stored in the system. |
| * <p/> |
| * <p>Unless overridden by the {@link #setCredentialsMatcher setCredentialsMatcher} method, the default |
| * value is a {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher SimpleCredentialsMatcher} instance. |
| * |
| * @return the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted |
| * credentials with those stored in the system. |
| */ |
| public CredentialsMatcher getCredentialsMatcher() { |
| <span class="fc" id="L194"> 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. |
| * <p/> |
| * <p>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="L208"> this.credentialsMatcher = credentialsMatcher;</span> |
| <span class="fc" id="L209"> }</span> |
| |
| /** |
| * Returns the authenticationToken class supported by this realm. |
| * <p/> |
| * <p>The default value is <tt>{@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken.class}</tt>, since |
| * about 90% of realms use username/password authentication, regardless of their protocol (e.g. over jdbc, ldap, |
| * kerberos, http, etc). |
| * <p/> |
| * <p>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 |
| * <tt>UsernamePasswordToken</tt> authentication token submissions. |
| * |
| * @return the authenticationToken class supported by this realm. |
| * @see #setAuthenticationTokenClass |
| */ |
| public Class getAuthenticationTokenClass() { |
| <span class="fc" id="L226"> return authenticationTokenClass;</span> |
| } |
| |
| /** |
| * Sets the authenticationToken class supported by this realm. |
| * <p/> |
| * <p>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<? extends AuthenticationToken> authenticationTokenClass) { |
| <span class="fc" id="L239"> this.authenticationTokenClass = authenticationTokenClass;</span> |
| <span class="fc" id="L240"> }</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. |
| * <p/> |
| * <b>WARNING:</b> 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<Object, AuthenticationInfo> authenticationCache) { |
| <span class="fc" id="L256"> this.authenticationCache = authenticationCache;</span> |
| <span class="fc" id="L257"> }</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<Object, AuthenticationInfo> getAuthenticationCache() { |
| <span class="fc" id="L270"> 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)}. |
| * <p/> |
| * This name will only be used to look up a cache if authentication caching is |
| * {@link #isAuthenticationCachingEnabled() enabled}. |
| * <p/> |
| * <b>WARNING:</b> 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="L289"> 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)}. |
| * <p/> |
| * 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="L306"> this.authenticationCacheName = authenticationCacheName;</span> |
| <span class="fc" id="L307"> }</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. |
| * <p/> |
| * 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="L318" title="1 of 4 branches missed."> return this.authenticationCachingEnabled && 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. |
| * <p/> |
| * The default value is {@code false} to retain backwards compatibility with Shiro 1.1 and earlier. |
| * <p/> |
| * <b>WARNING:</b> 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({"UnusedDeclaration"}) |
| public void setAuthenticationCachingEnabled(boolean authenticationCachingEnabled) { |
| <span class="fc" id="L334"> this.authenticationCachingEnabled = authenticationCachingEnabled;</span> |
| <span class="pc bpc" id="L335" title="1 of 2 branches missed."> if (authenticationCachingEnabled) {</span> |
| <span class="fc" id="L336"> setCachingEnabled(true);</span> |
| } |
| <span class="fc" id="L338"> }</span> |
| |
| public void setName(String name) { |
| <span class="fc" id="L341"> super.setName(name);</span> |
| <span class="fc" id="L342"> String authcCacheName = this.authenticationCacheName;</span> |
| <span class="pc bpc" id="L343" title="2 of 4 branches missed."> if (authcCacheName != null && 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="L346"> this.authenticationCacheName = name + DEFAULT_AUTHORIZATION_CACHE_SUFFIX;</span> |
| } |
| <span class="fc" id="L348"> }</span> |
| |
| |
| /*-------------------------------------------- |
| | M E T H O D S | |
| ============================================*/ |
| |
| /** |
| * Convenience implementation that returns |
| * <tt>getAuthenticationTokenClass().isAssignableFrom( token.getClass() );</tt>. Can be overridden |
| * by subclasses for more complex token checking. |
| * <p>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="L366" title="2 of 4 branches missed."> return token != null && 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: |
| * <ol> |
| * <li>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.</li> |
| * <li>If the {@link #setAuthenticationCache cache} property has <b>not</b> 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.</li> |
| * <li>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.</li> |
| * </ol> |
| * <p/> |
| * 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="L394"> getAvailableAuthenticationCache();</span> |
| <span class="fc" id="L395"> onInit();</span> |
| <span class="fc" id="L396"> }</span> |
| |
| /** |
| * Template method for subclasses to implement any initialization logic. Called from |
| * {@link #init()}. |
| * |
| * @since 1.2 |
| */ |
| protected void onInit() { |
| <span class="fc" id="L405"> }</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="L414"> getAvailableAuthenticationCache();</span> |
| <span class="fc" id="L415"> }</span> |
| |
| /** |
| * Returns any available {@link Cache} instance to use for authentication caching. This functions as follows: |
| * <ol> |
| * <li>If an {@link #setAuthenticationCache(org.apache.shiro.cache.Cache) authenticationCache} has been explicitly |
| * configured (it is not null), it is returned.</li> |
| * <li>If there is no {@link #getAuthenticationCache() authenticationCache} configured: |
| * <ol> |
| * <li>If authentication caching is {@link #isAuthenticationCachingEnabled() enabled}, any available |
| * {@link #getCacheManager() cacheManager} will be consulted to obtain an available authentication cache. |
| * </li> |
| * <li>If authentication caching is disabled, this implementation does nothing.</li> |
| * </ol> |
| * </li> |
| * </ol> |
| * |
| * @return any available {@link Cache} instance to use for authentication caching. |
| */ |
| private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() { |
| <span class="fc" id="L435"> Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();</span> |
| <span class="fc" id="L436"> boolean authcCachingEnabled = isAuthenticationCachingEnabled();</span> |
| <span class="fc bfc" id="L437" title="All 4 branches covered."> if (cache == null && authcCachingEnabled) {</span> |
| <span class="fc" id="L438"> cache = getAuthenticationCacheLazy();</span> |
| } |
| <span class="fc" id="L440"> 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<Object, AuthenticationInfo> getAuthenticationCacheLazy() { |
| |
| <span class="pc bpc" id="L453" title="1 of 2 branches missed."> if (this.authenticationCache == null) {</span> |
| |
| <span class="fc" id="L455"> log.trace("No authenticationCache instance set. Checking for a cacheManager...");</span> |
| |
| <span class="fc" id="L457"> CacheManager cacheManager = getCacheManager();</span> |
| |
| <span class="pc bpc" id="L459" title="1 of 2 branches missed."> if (cacheManager != null) {</span> |
| <span class="fc" id="L460"> String cacheName = getAuthenticationCacheName();</span> |
| <span class="fc" id="L461"> log.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName);</span> |
| <span class="fc" id="L462"> this.authenticationCache = cacheManager.getCache(cacheName);</span> |
| } |
| } |
| |
| <span class="fc" id="L466"> 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="L479"> AuthenticationInfo info = null;</span> |
| |
| <span class="fc" id="L481"> Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();</span> |
| <span class="pc bpc" id="L482" title="1 of 4 branches missed."> if (cache != null && token != null) {</span> |
| <span class="fc" id="L483"> log.trace("Attempting to retrieve the AuthenticationInfo from cache.");</span> |
| <span class="fc" id="L484"> Object key = getAuthenticationCacheKey(token);</span> |
| <span class="fc" id="L485"> info = cache.get(key);</span> |
| <span class="fc bfc" id="L486" title="All 2 branches covered."> if (info == null) {</span> |
| <span class="fc" id="L487"> log.trace("No AuthorizationInfo found in cache for key [{}]", key);</span> |
| } else { |
| <span class="fc" id="L489"> log.trace("Found cached AuthorizationInfo for key [{}]", key);</span> |
| } |
| } |
| |
| <span class="fc" id="L493"> 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="L506" title="All 2 branches covered."> if (!isAuthenticationCachingEnabled(token, info)) {</span> |
| <span class="fc" id="L507"> log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token);</span> |
| //return quietly, caching is disabled for this token/info pair: |
| <span class="fc" id="L509"> return;</span> |
| } |
| |
| <span class="fc" id="L512"> Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();</span> |
| <span class="pc bpc" id="L513" title="1 of 2 branches missed."> if (cache != null) {</span> |
| <span class="fc" id="L514"> Object key = getAuthenticationCacheKey(token);</span> |
| <span class="fc" id="L515"> cache.put(key, info);</span> |
| <span class="fc" id="L516"> log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info);</span> |
| } |
| <span class="fc" id="L518"> }</span> |
| |
| /** |
| * Returns {@code true} if authentication caching should be utilized based on the specified |
| * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise. |
| * <p/> |
| * 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="L536"> return isAuthenticationCachingEnabled();</span> |
| } |
| |
| /** |
| * This implementation functions as follows: |
| * <ol> |
| * <li>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.</li> |
| * <li>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.</li> |
| * <li>If an AuthenticationInfo instance is not found in the cache or by lookup, {@code null} is returned to |
| * indicate an account cannot be found.</li> |
| * <li>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.</li> |
| * </ol> |
| * |
| * @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="L565"> AuthenticationInfo info = getCachedAuthenticationInfo(token);</span> |
| <span class="fc bfc" id="L566" title="All 2 branches covered."> if (info == null) {</span> |
| //otherwise not cached, perform the lookup: |
| <span class="fc" id="L568"> info = doGetAuthenticationInfo(token);</span> |
| <span class="fc" id="L569"> log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);</span> |
| <span class="pc bpc" id="L570" title="1 of 4 branches missed."> if (token != null && info != null) {</span> |
| <span class="fc" id="L571"> cacheAuthenticationInfoIfPossible(token, info);</span> |
| } |
| } else { |
| <span class="fc" id="L574"> log.debug("Using cached authentication info [{}] to perform credentials matching.", info);</span> |
| } |
| |
| <span class="fc bfc" id="L577" title="All 2 branches covered."> if (info != null) {</span> |
| <span class="fc" id="L578"> assertCredentialsMatch(token, info);</span> |
| } else { |
| <span class="fc" id="L580"> log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);</span> |
| } |
| |
| <span class="fc" id="L583"> 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="L595"> CredentialsMatcher cm = getCredentialsMatcher();</span> |
| <span class="fc bfc" id="L596" title="All 2 branches covered."> if (cm != null) {</span> |
| <span class="fc bfc" id="L597" title="All 2 branches covered."> if (!cm.doCredentialsMatch(token, info)) {</span> |
| //not successful - throw an exception to indicate this: |
| <span class="fc" id="L599"> String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";</span> |
| <span class="fc" id="L600"> throw new IncorrectCredentialsException(msg);</span> |
| } |
| } else { |
| <span class="fc" id="L603"> throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +</span> |
| "credentials during authentication. If you do not wish for credentials to be examined, you " + |
| <span class="fc" id="L605"> "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");</span> |
| } |
| <span class="fc" id="L607"> }</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. |
| * <h3>Cache Invalidation on Logout</h3> |
| * <b>NOTE:</b> 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="L624" 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. |
| * <h3>Cache Invalidation on Logout</h3> |
| * <b>NOTE:</b> 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="L642"> 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="L655"> super.doClearCache(principals);</span> |
| <span class="fc" id="L656"> clearCachedAuthenticationInfo(principals);</span> |
| <span class="fc" id="L657"> }</span> |
| |
| /** |
| * Clears out the AuthenticationInfo cache entry for the specified account. |
| * <p/> |
| * 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. |
| * <p/> |
| * 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. |
| * <p/> |
| * 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="L680" title="1 of 2 branches missed."> if (!CollectionUtils.isEmpty(principals)) {</span> |
| <span class="fc" id="L681"> Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();</span> |
| //cache instance will be non-null if caching is enabled: |
| <span class="fc bfc" id="L683" title="All 2 branches covered."> if (cache != null) {</span> |
| <span class="fc" id="L684"> Object key = getAuthenticationCacheKey(principals);</span> |
| <span class="fc" id="L685"> cache.remove(key);</span> |
| } |
| } |
| <span class="fc" id="L688"> }</span> |
| |
| /** |
| * Retrieves authentication data from an implementation-specific datasource (RDBMS, LDAP, etc) for the given |
| * authentication token. |
| * <p/> |
| * 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. |
| * <p/> |
| * 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 <tt>token</tt> |
| */ |
| 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> |