View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.realm;
20  
21  import org.apache.shiro.authc.AuthenticationException;
22  import org.apache.shiro.authc.AuthenticationInfo;
23  import org.apache.shiro.authc.AuthenticationToken;
24  import org.apache.shiro.authc.IncorrectCredentialsException;
25  import org.apache.shiro.authc.UsernamePasswordToken;
26  import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
27  import org.apache.shiro.authc.credential.CredentialsMatcher;
28  import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
29  import org.apache.shiro.cache.Cache;
30  import org.apache.shiro.cache.CacheManager;
31  import org.apache.shiro.subject.PrincipalCollection;
32  import org.apache.shiro.util.Initializable;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  import java.util.concurrent.atomic.AtomicInteger;
37  
38  
39  /**
40   * A top-level abstract implementation of the <tt>Realm</tt> interface that only implements authentication support
41   * (log-in) operations and leaves authorization (access control) behavior to subclasses.
42   * <h2>Authentication Caching</h2>
43   * For applications that perform frequent repeated authentication of the same accounts (e.g. as is often done in
44   * REST or Soap applications that authenticate on every request), it might be prudent to enable authentication
45   * caching to alleviate constant load on any back-end data sources.
46   * <p/>
47   * This feature is disabled by default to retain backwards-compatibility with Shiro 1.1 and earlier.  It may be
48   * enabled by setting {@link #setAuthenticationCachingEnabled(boolean) authenticationCachingEnabled} = {@code true}
49   * (and configuring Shiro with a {@link CacheManager} of course), but <b>NOTE:</b>
50   * <p/>
51   * <b>ONLY enable authentication caching if either of the following is true for your realm implementation:</b>
52   * <ul>
53   * <li>The {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}
54   * implementation returns {@code AuthenticationInfo} instances where the
55   * {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are securely obfuscated and NOT
56   * plaintext (raw) credentials. For example,
57   * if your realm references accounts with passwords, that the {@code AuthenticationInfo}'s
58   * {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are safely hashed and salted or otherwise
59   * fully encrypted.<br/><br/></li>
60   * <li>The {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}
61   * implementation returns {@code AuthenticationInfo} instances where the
62   * {@link org.apache.shiro.authc.AuthenticationInfo#getCredentials() credentials} are plaintext (raw) <b>AND</b> the
63   * cache region storing the {@code AuthenticationInfo} instances WILL NOT overflow to disk and WILL NOT transmit cache
64   * entries over an unprotected (non TLS/SSL) network (as might be the case with a networked/distributed enterprise cache).
65   * This should be the case even in private/trusted/corporate networks.</li>
66   * </ul>
67   * <p/>
68   * These points are very important because if authentication caching is enabled, this abstract class implementation
69   * will place AuthenticationInfo instances returned from the subclass implementations directly into the cache, for
70   * example:
71   * <pre>
72   * cache.put(cacheKey, subclassAuthenticationInfoInstance);
73   * </pre>
74   * <p/>
75   * Enabling authentication caching is ONLY safe to do if the above two scenarios apply.  It is NOT safe to enable under
76   * any other scenario.
77   * <p/>
78   * When possible, always represent and store credentials in a safe form (hash+salt or encrypted) to eliminate plaintext
79   * visibility.
80   * <h3>Authentication Cache Invalidation on Logout</h3>
81   * If authentication caching is enabled, this implementation will attempt to evict (remove) cached authentication data
82   * for an account during logout.  This can only occur if the
83   * {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} and
84   * {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} methods return the exact same value.
85   * <p/>
86   * The default implementations of these methods expect that the
87   * {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal()} (what the user submits during login) and
88   * {@link #getAvailablePrincipal(org.apache.shiro.subject.PrincipalCollection) getAvailablePrincipal} (what is returned
89   * by the realm after account lookup) return
90   * the same exact value.  For example, the user submitted username is also the primary account identifier.
91   * <p/>
92   * However, if your application uses, say, a username for end-user login, but returns a primary key ID as the
93   * primary principal after authentication, then you will need to override either
94   * {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken) getAuthenticationCacheKey(token)} or
95   * {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection) getAuthenticationCacheKey(principals)}
96   * (or both) to ensure that the same cache key can be used for either object.
97   * <p/>
98   * This guarantees that the same cache key used to cache the data during authentication (derived from the
99   * {@code AuthenticationToken}) will be used to remove the cached data during logout (derived from the
100  * {@code PrincipalCollection}).
101  * <h4>Unmatching Cache Key Values</h4>
102  * If the return values from {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} and
103  * {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} are not identical, cached
104  * authentication data removal is at the mercy of your cache provider settings.  For example, often cache
105  * implementations will evict cache entries based on a timeToIdle or timeToLive (TTL) value.
106  * <p/>
107  * If this lazy eviction capability of the cache product is not sufficient and you want discrete behavior
108  * (highly recommended for authentication data), ensure that the return values from those two methods are identical in
109  * the subclass implementation.
110  *
111  * @since 0.2
112  */
113 public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {
114 
115     //TODO - complete JavaDoc
116 
117     private static final Logger log = LoggerFactory.getLogger(AuthenticatingRealm.class);
118 
119     private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger();
120 
121     /**
122      * The default suffix appended to the realm name used for caching authentication data.
123      *
124      * @since 1.2
125      */
126     private static final String DEFAULT_AUTHENTICATION_CACHE_SUFFIX = ".authenticationCache";
127 
128     /**
129      * Credentials matcher used to determine if the provided credentials match the credentials stored in the data store.
130      */
131     private CredentialsMatcher credentialsMatcher;
132 
133 
134     private Cache<Object, AuthenticationInfo> authenticationCache;
135 
136     private boolean authenticationCachingEnabled;
137     private String authenticationCacheName;
138 
139     /**
140      * The class that this realm supports for authentication tokens.  This is used by the
141      * default implementation of the {@link Realm#supports(org.apache.shiro.authc.AuthenticationToken)} method to
142      * determine whether or not the given authentication token is supported by this realm.
143      */
144     private Class<? extends AuthenticationToken> authenticationTokenClass;
145 
146     /*-------------------------------------------
147     |         C O N S T R U C T O R S           |
148     ============================================*/
149     public AuthenticatingRealm() {
150         this(null, new SimpleCredentialsMatcher());
151     }
152 
153     public AuthenticatingRealm(CacheManager cacheManager) {
154         this(cacheManager, new SimpleCredentialsMatcher());
155     }
156 
157     public AuthenticatingRealm(CredentialsMatcher matcher) {
158         this(null, matcher);
159     }
160 
161     public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
162         authenticationTokenClass = UsernamePasswordToken.class;
163 
164         //retain backwards compatibility for Shiro 1.1 and earlier.  Setting to true by default will probably cause
165         //unexpected results for existing applications:
166         this.authenticationCachingEnabled = false;
167 
168         int instanceNumber = INSTANCE_COUNT.getAndIncrement();
169         this.authenticationCacheName = getClass().getName() + DEFAULT_AUTHENTICATION_CACHE_SUFFIX;
170         if (instanceNumber > 0) {
171             this.authenticationCacheName = this.authenticationCacheName + "." + instanceNumber;
172         }
173 
174         if (cacheManager != null) {
175             setCacheManager(cacheManager);
176         }
177         if (matcher != null) {
178             setCredentialsMatcher(matcher);
179         }
180     }
181 
182     /*--------------------------------------------
183     |  A C C E S S O R S / M O D I F I E R S    |
184     ============================================*/
185 
186     /**
187      * Returns the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted
188      * credentials with those stored in the system.
189      * <p/>
190      * <p>Unless overridden by the {@link #setCredentialsMatcher setCredentialsMatcher} method, the default
191      * value is a {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher SimpleCredentialsMatcher} instance.
192      *
193      * @return the <code>CredentialsMatcher</code> used during an authentication attempt to verify submitted
194      *         credentials with those stored in the system.
195      */
196     public CredentialsMatcher getCredentialsMatcher() {
197         return credentialsMatcher;
198     }
199 
200     /**
201      * Sets the CrendialsMatcher used during an authentication attempt to verify submitted credentials with those
202      * stored in the system.  The implementation of this matcher can be switched via configuration to
203      * support any number of schemes, including plain text comparisons, hashing comparisons, and others.
204      * <p/>
205      * <p>Unless overridden by this method, the default value is a
206      * {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher} instance.
207      *
208      * @param credentialsMatcher the matcher to use.
209      */
210     public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
211         this.credentialsMatcher = credentialsMatcher;
212     }
213 
214     /**
215      * Returns the authenticationToken class supported by this realm.
216      * <p/>
217      * <p>The default value is <tt>{@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken.class}</tt>, since
218      * about 90% of realms use username/password authentication, regardless of their protocol (e.g. over jdbc, ldap,
219      * kerberos, http, etc).
220      * <p/>
221      * <p>If subclasses haven't already overridden the {@link Realm#supports Realm.supports(AuthenticationToken)} method,
222      * they must {@link #setAuthenticationTokenClass(Class) set a new class} if they won't support
223      * <tt>UsernamePasswordToken</tt> authentication token submissions.
224      *
225      * @return the authenticationToken class supported by this realm.
226      * @see #setAuthenticationTokenClass
227      */
228     public Class getAuthenticationTokenClass() {
229         return authenticationTokenClass;
230     }
231 
232     /**
233      * Sets the authenticationToken class supported by this realm.
234      * <p/>
235      * <p>Unless overridden by this method, the default value is
236      * {@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken.class} to support the majority of applications.
237      *
238      * @param authenticationTokenClass the class of authentication token instances supported by this realm.
239      * @see #getAuthenticationTokenClass getAuthenticationTokenClass() for more explanation.
240      */
241     public void setAuthenticationTokenClass(Class<? extends AuthenticationToken> authenticationTokenClass) {
242         this.authenticationTokenClass = authenticationTokenClass;
243     }
244 
245     /**
246      * Sets an explicit {@link Cache} instance to use for authentication caching.  If not set and authentication
247      * caching is {@link #isAuthenticationCachingEnabled() enabled}, any available
248      * {@link #getCacheManager() cacheManager} will be used to acquire the cache instance if available.
249      * <p/>
250      * <b>WARNING:</b> Only set this property if safe caching conditions apply, as documented at the top
251      * of this page in the class-level JavaDoc.
252      *
253      * @param authenticationCache an explicit {@link Cache} instance to use for authentication caching or
254      *                            {@code null} if the cache should possibly be obtained another way.
255      * @see #isAuthenticationCachingEnabled()
256      * @since 1.2
257      */
258     public void setAuthenticationCache(Cache<Object, AuthenticationInfo> authenticationCache) {
259         this.authenticationCache = authenticationCache;
260     }
261 
262     /**
263      * Returns a {@link Cache} instance to use for authentication caching, or {@code null} if no cache has been
264      * set.
265      *
266      * @return a {@link Cache} instance to use for authentication caching, or {@code null} if no cache has been
267      *         set.
268      * @see #setAuthenticationCache(org.apache.shiro.cache.Cache)
269      * @see #isAuthenticationCachingEnabled()
270      * @since 1.2
271      */
272     public Cache<Object, AuthenticationInfo> getAuthenticationCache() {
273         return this.authenticationCache;
274     }
275 
276     /**
277      * Returns the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
278      * a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
279      * <p/>
280      * This name will only be used to look up a cache if authentication caching is
281      * {@link #isAuthenticationCachingEnabled() enabled}.
282      * <p/>
283      * <b>WARNING:</b> Only set this property if safe caching conditions apply, as documented at the top
284      * of this page in the class-level JavaDoc.
285      *
286      * @return the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
287      *         a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
288      * @see #isAuthenticationCachingEnabled()
289      * @since 1.2
290      */
291     public String getAuthenticationCacheName() {
292         return this.authenticationCacheName;
293     }
294 
295     /**
296      * Sets the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if
297      * a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
298      * <p/>
299      * This name will only be used to look up a cache if authentication caching is
300      * {@link #isAuthenticationCachingEnabled() enabled}.
301      *
302      * @param authenticationCacheName the name of a {@link Cache} to lookup from any available
303      *                                {@link #getCacheManager() cacheManager} if a cache is not explicitly configured
304      *                                via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}.
305      * @see #isAuthenticationCachingEnabled()
306      * @since 1.2
307      */
308     public void setAuthenticationCacheName(String authenticationCacheName) {
309         this.authenticationCacheName = authenticationCacheName;
310     }
311 
312     /**
313      * Returns {@code true} if authentication caching should be utilized if a {@link CacheManager} has been
314      * {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise.
315      * <p/>
316      * The default value is {@code true}.
317      *
318      * @return {@code true} if authentication caching should be utilized, {@code false} otherwise.
319      */
320     public boolean isAuthenticationCachingEnabled() {
321         return this.authenticationCachingEnabled && isCachingEnabled();
322     }
323 
324     /**
325      * Sets whether or not authentication caching should be utilized if a {@link CacheManager} has been
326      * {@link #setCacheManager(org.apache.shiro.cache.CacheManager) configured}, {@code false} otherwise.
327      * <p/>
328      * The default value is {@code false} to retain backwards compatibility with Shiro 1.1 and earlier.
329      * <p/>
330      * <b>WARNING:</b> Only set this property to {@code true} if safe caching conditions apply, as documented at the top
331      * of this page in the class-level JavaDoc.
332      *
333      * @param authenticationCachingEnabled the value to set
334      */
335     @SuppressWarnings({"UnusedDeclaration"})
336     public void setAuthenticationCachingEnabled(boolean authenticationCachingEnabled) {
337         this.authenticationCachingEnabled = authenticationCachingEnabled;
338         if (authenticationCachingEnabled) {
339             setCachingEnabled(true);
340         }
341     }
342 
343     public void setName(String name) {
344         super.setName(name);
345         String authcCacheName = this.authenticationCacheName;
346         if (authcCacheName != null && authcCacheName.startsWith(getClass().getName())) {
347             //get rid of the default heuristically-created cache name.  Create a more meaningful one
348             //based on the application-unique Realm name:
349             this.authenticationCacheName = name + DEFAULT_AUTHENTICATION_CACHE_SUFFIX;
350         }
351     }
352 
353 
354     /*--------------------------------------------
355     |               M E T H O D S               |
356     ============================================*/
357 
358     /**
359      * Convenience implementation that returns
360      * <tt>getAuthenticationTokenClass().isAssignableFrom( token.getClass() );</tt>.  Can be overridden
361      * by subclasses for more complex token checking.
362      * <p>Most configurations will only need to set a different class via
363      * {@link #setAuthenticationTokenClass}, as opposed to overriding this method.
364      *
365      * @param token the token being submitted for authentication.
366      * @return true if this authentication realm can process the submitted token instance of the class, false otherwise.
367      */
368     public boolean supports(AuthenticationToken token) {
369         return token != null && getAuthenticationTokenClass().isAssignableFrom(token.getClass());
370     }
371 
372     /**
373      * Initializes this realm and potentially enables an authentication cache, depending on configuration.  Based on
374      * the availability of an authentication cache, this class functions as follows:
375      * <ol>
376      * <li>If the {@link #setAuthenticationCache cache} property has been set, it will be
377      * used to cache the AuthenticationInfo objects returned from {@link #getAuthenticationInfo}
378      * method invocations.
379      * All future calls to {@link #getAuthenticationInfo} will attempt to use this cache first
380      * to alleviate any potentially unnecessary calls to an underlying data store.</li>
381      * <li>If the {@link #setAuthenticationCache cache} property has <b>not</b> been set,
382      * the {@link #setCacheManager cacheManager} property will be checked.
383      * If a {@code cacheManager} has been set, it will be used to eagerly acquire an authentication
384      * {@code cache}, and this cache which will be used as specified in #1.</li>
385      * <li>If neither the {@link #setAuthenticationCache (org.apache.shiro.cache.Cache) authenticationCache}
386      * or {@link #setCacheManager(org.apache.shiro.cache.CacheManager) cacheManager}
387      * properties are set, caching will not be utilized and authentication look-ups will be delegated to
388      * subclass implementations for each authentication attempt.</li>
389      * </ol>
390      * <p/>
391      * This method finishes by calling {@link #onInit()} is to allow subclasses to perform any init behavior desired.
392      *
393      * @since 1.2
394      */
395     public final void init() {
396         //trigger obtaining the authorization cache if possible
397         getAvailableAuthenticationCache();
398         onInit();
399     }
400 
401     /**
402      * Template method for subclasses to implement any initialization logic.  Called from
403      * {@link #init()}.
404      *
405      * @since 1.2
406      */
407     protected void onInit() {
408     }
409 
410     /**
411      * This implementation attempts to acquire an authentication cache if one is not already configured.
412      *
413      * @since 1.2
414      */
415     protected void afterCacheManagerSet() {
416         //trigger obtaining the authorization cache if possible
417         getAvailableAuthenticationCache();
418     }
419 
420     /**
421      * Returns any available {@link Cache} instance to use for authentication caching.  This functions as follows:
422      * <ol>
423      * <li>If an {@link #setAuthenticationCache(org.apache.shiro.cache.Cache) authenticationCache} has been explicitly
424      * configured (it is not null), it is returned.</li>
425      * <li>If there is no {@link #getAuthenticationCache() authenticationCache} configured:
426      * <ol>
427      * <li>If authentication caching is {@link #isAuthenticationCachingEnabled() enabled}, any available
428      * {@link #getCacheManager() cacheManager} will be consulted to obtain an available authentication cache.
429      * </li>
430      * <li>If authentication caching is disabled, this implementation does nothing.</li>
431      * </ol>
432      * </li>
433      * </ol>
434      *
435      * @return any available {@link Cache} instance to use for authentication caching.
436      */
437     private Cache<Object, AuthenticationInfo> getAvailableAuthenticationCache() {
438         Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
439         boolean authcCachingEnabled = isAuthenticationCachingEnabled();
440         if (cache == null && authcCachingEnabled) {
441             cache = getAuthenticationCacheLazy();
442         }
443         return cache;
444     }
445 
446     /**
447      * Checks to see if the authenticationCache class attribute is null, and if so, attempts to acquire one from
448      * any configured {@link #getCacheManager() cacheManager}.  If one is acquired, it is set as the class attribute.
449      * The class attribute is then returned.
450      *
451      * @return an available cache instance to be used for authentication caching or {@code null} if one is not available.
452      * @since 1.2
453      */
454     private Cache<Object, AuthenticationInfo> getAuthenticationCacheLazy() {
455 
456         if (this.authenticationCache == null) {
457 
458             log.trace("No authenticationCache instance set.  Checking for a cacheManager...");
459 
460             CacheManager cacheManager = getCacheManager();
461 
462             if (cacheManager != null) {
463                 String cacheName = getAuthenticationCacheName();
464                 log.debug("CacheManager [{}] configured.  Building authentication cache '{}'", cacheManager, cacheName);
465                 this.authenticationCache = cacheManager.getCache(cacheName);
466             }
467         }
468 
469         return this.authenticationCache;
470     }
471 
472     /**
473      * Returns any cached AuthenticationInfo corresponding to the specified token or {@code null} if there currently
474      * isn't any cached data.
475      *
476      * @param token the token submitted during the authentication attempt.
477      * @return any cached AuthenticationInfo corresponding to the specified token or {@code null} if there currently
478      *         isn't any cached data.
479      * @since 1.2
480      */
481     private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token) {
482         AuthenticationInfo info = null;
483 
484         Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
485         if (cache != null && token != null) {
486             log.trace("Attempting to retrieve the AuthenticationInfo from cache.");
487             Object key = getAuthenticationCacheKey(token);
488             info = cache.get(key);
489             if (info == null) {
490                 log.trace("No AuthorizationInfo found in cache for key [{}]", key);
491             } else {
492                 log.trace("Found cached AuthorizationInfo for key [{}]", key);
493             }
494         }
495 
496         return info;
497     }
498 
499     /**
500      * Caches the specified info if authentication caching
501      * {@link #isAuthenticationCachingEnabled(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) isEnabled}
502      * for the specific token/info pair and a cache instance is available to be used.
503      *
504      * @param token the authentication token submitted which resulted in a successful authentication attempt.
505      * @param info  the AuthenticationInfo to cache as a result of the successful authentication attempt.
506      * @since 1.2
507      */
508     private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) {
509         if (!isAuthenticationCachingEnabled(token, info)) {
510             log.debug("AuthenticationInfo caching is disabled for info [{}].  Submitted token: [{}].", info, token);
511             //return quietly, caching is disabled for this token/info pair:
512             return;
513         }
514 
515         Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
516         if (cache != null) {
517             Object key = getAuthenticationCacheKey(token);
518             cache.put(key, info);
519             log.trace("Cached AuthenticationInfo for continued authentication.  key=[{}], value=[{}].", key, info);
520         }
521     }
522 
523     /**
524      * Returns {@code true} if authentication caching should be utilized based on the specified
525      * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise.
526      * <p/>
527      * The default implementation simply delegates to {@link #isAuthenticationCachingEnabled()}, the general-case
528      * authentication caching setting.  Subclasses can override this to turn on or off caching at runtime
529      * based on the specific submitted runtime values.
530      *
531      * @param token the submitted authentication token
532      * @param info  the {@code AuthenticationInfo} acquired from data source lookup via
533      *              {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)}
534      * @return {@code true} if authentication caching should be utilized based on the specified
535      *         {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise.
536      * @since 1.2
537      */
538     protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, AuthenticationInfo info) {
539         return isAuthenticationCachingEnabled();
540     }
541 
542     /**
543      * This implementation functions as follows:
544      * <ol>
545      * <li>It attempts to acquire any cached {@link AuthenticationInfo} corresponding to the specified
546      * {@link AuthenticationToken} argument.  If a cached value is found, it will be used for credentials matching,
547      * alleviating the need to perform any lookups with a data source.</li>
548      * <li>If there is no cached {@link AuthenticationInfo} found, delegate to the
549      * {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} method to perform the actual
550      * lookup.  If authentication caching is enabled and possible, any returned info object will be
551      * {@link #cacheAuthenticationInfoIfPossible(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) cached}
552      * to be used in future authentication attempts.</li>
553      * <li>If an AuthenticationInfo instance is not found in the cache or by lookup, {@code null} is returned to
554      * indicate an account cannot be found.</li>
555      * <li>If an AuthenticationInfo instance is found (either cached or via lookup), ensure the submitted
556      * AuthenticationToken's credentials match the expected {@code AuthenticationInfo}'s credentials using the
557      * {@link #getCredentialsMatcher() credentialsMatcher}.  This means that credentials are always verified
558      * for an authentication attempt.</li>
559      * </ol>
560      *
561      * @param token the submitted account principal and credentials.
562      * @return the AuthenticationInfo corresponding to the given {@code token}, or {@code null} if no
563      *         AuthenticationInfo could be found.
564      * @throws AuthenticationException if authentication failed.
565      */
566     public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
567 
568         AuthenticationInfo info = getCachedAuthenticationInfo(token);
569         if (info == null) {
570             //otherwise not cached, perform the lookup:
571             info = doGetAuthenticationInfo(token);
572             log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
573             if (token != null && info != null) {
574                 cacheAuthenticationInfoIfPossible(token, info);
575             }
576         } else {
577             log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
578         }
579 
580         if (info != null) {
581             assertCredentialsMatch(token, info);
582         } else {
583             log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
584         }
585 
586         return info;
587     }
588 
589     /**
590      * Asserts that the submitted {@code AuthenticationToken}'s credentials match the stored account
591      * {@code AuthenticationInfo}'s credentials, and if not, throws an {@link AuthenticationException}.
592      *
593      * @param token the submitted authentication token
594      * @param info  the AuthenticationInfo corresponding to the given {@code token}
595      * @throws AuthenticationException if the token's credentials do not match the stored account credentials.
596      */
597     protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
598         CredentialsMatcher cm = getCredentialsMatcher();
599         if (cm != null) {
600             if (!cm.doCredentialsMatch(token, info)) {
601                 //not successful - throw an exception to indicate this:
602                 String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
603                 throw new IncorrectCredentialsException(msg);
604             }
605         } else {
606             throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
607                     "credentials during authentication.  If you do not wish for credentials to be examined, you " +
608                     "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
609         }
610     }
611 
612     /**
613      * Returns the key under which {@link AuthenticationInfo} instances are cached if authentication caching is enabled.
614      * This implementation defaults to returning the token's
615      * {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal() principal}, which is usually a username in
616      * most applications.
617      * <h3>Cache Invalidation on Logout</h3>
618      * <b>NOTE:</b> If you want to be able to invalidate an account's cached {@code AuthenticationInfo} on logout, you
619      * must ensure the {@link #getAuthenticationCacheKey(org.apache.shiro.subject.PrincipalCollection)} method returns
620      * the same value as this method.
621      *
622      * @param token the authentication token for which any successful authentication will be cached.
623      * @return the cache key to use to cache the associated {@link AuthenticationInfo} after a successful authentication.
624      * @since 1.2
625      */
626     protected Object getAuthenticationCacheKey(AuthenticationToken token) {
627         return token != null ? token.getPrincipal() : null;
628     }
629 
630     /**
631      * Returns the key under which {@link AuthenticationInfo} instances are cached if authentication caching is enabled.
632      * This implementation delegates to
633      * {@link #getAvailablePrincipal(org.apache.shiro.subject.PrincipalCollection)}, which returns the primary principal
634      * associated with this particular Realm.
635      * <h3>Cache Invalidation on Logout</h3>
636      * <b>NOTE:</b> If you want to be able to invalidate an account's cached {@code AuthenticationInfo} on logout, you
637      * must ensure that this method returns the same value as the
638      * {@link #getAuthenticationCacheKey(org.apache.shiro.authc.AuthenticationToken)} method!
639      *
640      * @param principals the principals of the account for which to set or remove cached {@code AuthenticationInfo}.
641      * @return the cache key to use when looking up cached {@link AuthenticationInfo} instances.
642      * @since 1.2
643      */
644     protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
645         return getAvailablePrincipal(principals);
646     }
647 
648     /**
649      * This implementation clears out any cached authentication data by calling
650      * {@link #clearCachedAuthenticationInfo(org.apache.shiro.subject.PrincipalCollection)}.
651      * If overriding in a subclass, be sure to call {@code super.doClearCache} to ensure this behavior is maintained.
652      *
653      * @param principals principals the principals of the account for which to clear any cached data.
654      * @since 1.2
655      */
656     @Override
657     protected void doClearCache(PrincipalCollection principals) {
658         super.doClearCache(principals);
659         clearCachedAuthenticationInfo(principals);
660     }
661 
662     private static boolean isEmpty(PrincipalCollection pc) {
663         return pc == null || pc.isEmpty();
664     }
665 
666     /**
667      * Clears out the AuthenticationInfo cache entry for the specified account.
668      * <p/>
669      * This method is provided as a convenience to subclasses so they can invalidate a cache entry when they
670      * change an account's authentication data (e.g. reset password) during runtime.  Because an account's
671      * AuthenticationInfo can be cached, there needs to be a way to invalidate the cache for only that account so that
672      * subsequent authentication operations don't used the (old) cached value if account data changes.
673      * <p/>
674      * After this method is called, the next authentication for that same account will result in a call to
675      * {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) doGetAuthenticationInfo}, and the
676      * resulting return value will be cached before being returned so it can be reused for later authentications.
677      * <p/>
678      * If you wish to clear out all associated cached data (and not just authentication data), use the
679      * {@link #clearCache(org.apache.shiro.subject.PrincipalCollection)} method instead (which will in turn call this
680      * method by default).
681      *
682      * @param principals the principals of the account for which to clear the cached AuthorizationInfo.
683      * @see #clearCache(org.apache.shiro.subject.PrincipalCollection)
684      * @since 1.2
685      */
686     protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
687         if (!isEmpty(principals)) {
688             Cache<Object, AuthenticationInfo> cache = getAvailableAuthenticationCache();
689             //cache instance will be non-null if caching is enabled:
690             if (cache != null) {
691                 Object key = getAuthenticationCacheKey(principals);
692                 cache.remove(key);
693             }
694         }
695     }
696 
697     /**
698      * Retrieves authentication data from an implementation-specific datasource (RDBMS, LDAP, etc) for the given
699      * authentication token.
700      * <p/>
701      * For most datasources, this means just 'pulling' authentication data for an associated subject/user and nothing
702      * more and letting Shiro do the rest.  But in some systems, this method could actually perform EIS specific
703      * log-in logic in addition to just retrieving data - it is up to the Realm implementation.
704      * <p/>
705      * A {@code null} return value means that no account could be associated with the specified token.
706      *
707      * @param token the authentication token containing the user's principal and credentials.
708      * @return an {@link AuthenticationInfo} object containing account data resulting from the
709      *         authentication ONLY if the lookup is successful (i.e. account exists and is valid, etc.)
710      * @throws AuthenticationException if there is an error acquiring data or performing
711      *                                 realm-specific authentication logic for the specified <tt>token</tt>
712      */
713     protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
714 
715 }