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.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    //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}