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