Coverage Report - org.apache.shiro.mgt.DefaultSecurityManager
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultSecurityManager
58%
102/173
36%
22/60
2.353
 
 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.mgt;
 20  
 
 21  
 import org.apache.shiro.authc.*;
 22  
 import org.apache.shiro.authz.Authorizer;
 23  
 import org.apache.shiro.realm.Realm;
 24  
 import org.apache.shiro.session.InvalidSessionException;
 25  
 import org.apache.shiro.session.Session;
 26  
 import org.apache.shiro.session.mgt.DefaultSessionContext;
 27  
 import org.apache.shiro.session.mgt.DefaultSessionKey;
 28  
 import org.apache.shiro.session.mgt.SessionContext;
 29  
 import org.apache.shiro.session.mgt.SessionKey;
 30  
 import org.apache.shiro.subject.PrincipalCollection;
 31  
 import org.apache.shiro.subject.Subject;
 32  
 import org.apache.shiro.subject.SubjectContext;
 33  
 import org.apache.shiro.subject.support.DefaultSubjectContext;
 34  
 import org.apache.shiro.util.CollectionUtils;
 35  
 import org.slf4j.Logger;
 36  
 import org.slf4j.LoggerFactory;
 37  
 
 38  
 import java.io.Serializable;
 39  
 import java.util.Collection;
 40  
 
 41  
 /**
 42  
  * The Shiro framework's default concrete implementation of the {@link SecurityManager} interface,
 43  
  * based around a collection of {@link org.apache.shiro.realm.Realm}s.  This implementation delegates its
 44  
  * authentication, authorization, and session operations to wrapped {@link Authenticator}, {@link Authorizer}, and
 45  
  * {@link org.apache.shiro.session.mgt.SessionManager SessionManager} instances respectively via superclass
 46  
  * implementation.
 47  
  * <p/>
 48  
  * To greatly reduce and simplify configuration, this implementation (and its superclasses) will
 49  
  * create suitable defaults for all of its required dependencies, <em>except</em> the required one or more
 50  
  * {@link Realm Realm}s.  Because {@code Realm} implementations usually interact with an application's data model,
 51  
  * they are almost always application specific;  you will want to specify at least one custom
 52  
  * {@code Realm} implementation that 'knows' about your application's data/security model
 53  
  * (via {@link #setRealm} or one of the overloaded constructors).  All other attributes in this class hierarchy
 54  
  * will have suitable defaults for most enterprise applications.
 55  
  * <p/>
 56  
  * <b>RememberMe notice</b>: This class supports the ability to configure a
 57  
  * {@link #setRememberMeManager RememberMeManager}
 58  
  * for {@code RememberMe} identity services for login/logout, BUT, a default instance <em>will not</em> be created
 59  
  * for this attribute at startup.
 60  
  * <p/>
 61  
  * Because RememberMe services are inherently client tier-specific and
 62  
  * therefore aplication-dependent, if you want {@code RememberMe} services enabled, you will have to specify an
 63  
  * instance yourself via the {@link #setRememberMeManager(RememberMeManager) setRememberMeManager}
 64  
  * mutator.  However if you're reading this JavaDoc with the
 65  
  * expectation of operating in a Web environment, take a look at the
 66  
  * {@code org.apache.shiro.web.DefaultWebSecurityManager} implementation, which
 67  
  * <em>does</em> support {@code RememberMe} services by default at startup.
 68  
  *
 69  
  * @since 0.2
 70  
  */
 71  
 public class DefaultSecurityManager extends SessionsSecurityManager {
 72  
 
 73  2
     private static final Logger log = LoggerFactory.getLogger(DefaultSecurityManager.class);
 74  
 
 75  
     protected RememberMeManager rememberMeManager;
 76  
     protected SubjectDAO subjectDAO;
 77  
     protected SubjectFactory subjectFactory;
 78  
 
 79  
     /**
 80  
      * Default no-arg constructor.
 81  
      */
 82  
     public DefaultSecurityManager() {
 83  72
         super();
 84  72
         this.subjectFactory = new DefaultSubjectFactory();
 85  72
         this.subjectDAO = new DefaultSubjectDAO();
 86  72
     }
 87  
 
 88  
     /**
 89  
      * Supporting constructor for a single-realm application.
 90  
      *
 91  
      * @param singleRealm the single realm used by this SecurityManager.
 92  
      */
 93  
     public DefaultSecurityManager(Realm singleRealm) {
 94  16
         this();
 95  16
         setRealm(singleRealm);
 96  16
     }
 97  
 
 98  
     /**
 99  
      * Supporting constructor for multiple {@link #setRealms realms}.
 100  
      *
 101  
      * @param realms the realm instances backing this SecurityManager.
 102  
      */
 103  
     public DefaultSecurityManager(Collection<Realm> realms) {
 104  0
         this();
 105  0
         setRealms(realms);
 106  0
     }
 107  
 
 108  
     /**
 109  
      * Returns the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application.
 110  
      *
 111  
      * @return the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application.
 112  
      */
 113  
     public SubjectFactory getSubjectFactory() {
 114  92
         return subjectFactory;
 115  
     }
 116  
 
 117  
     /**
 118  
      * Sets the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application.
 119  
      *
 120  
      * @param subjectFactory the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application.
 121  
      */
 122  
     public void setSubjectFactory(SubjectFactory subjectFactory) {
 123  0
         this.subjectFactory = subjectFactory;
 124  0
     }
 125  
 
 126  
     /**
 127  
      * Returns the {@code SubjectDAO} responsible for persisting Subject state, typically used after login or when an
 128  
      * Subject identity is discovered (eg after RememberMe services).  Unless configured otherwise, the default
 129  
      * implementation is a {@link DefaultSubjectDAO}.
 130  
      *
 131  
      * @return the {@code SubjectDAO} responsible for persisting Subject state, typically used after login or when an
 132  
      *         Subject identity is discovered (eg after RememberMe services).
 133  
      * @see DefaultSubjectDAO
 134  
      * @since 1.2
 135  
      */
 136  
     public SubjectDAO getSubjectDAO() {
 137  0
         return subjectDAO;
 138  
     }
 139  
 
 140  
     /**
 141  
      * Sets the {@code SubjectDAO} responsible for persisting Subject state, typically used after login or when an
 142  
      * Subject identity is discovered (eg after RememberMe services). Unless configured otherwise, the default
 143  
      * implementation is a {@link DefaultSubjectDAO}.
 144  
      *
 145  
      * @param subjectDAO the {@code SubjectDAO} responsible for persisting Subject state, typically used after login or when an
 146  
      *                   Subject identity is discovered (eg after RememberMe services).
 147  
      * @see DefaultSubjectDAO
 148  
      * @since 1.2
 149  
      */
 150  
     public void setSubjectDAO(SubjectDAO subjectDAO) {
 151  0
         this.subjectDAO = subjectDAO;
 152  0
     }
 153  
 
 154  
     public RememberMeManager getRememberMeManager() {
 155  118
         return rememberMeManager;
 156  
     }
 157  
 
 158  
     public void setRememberMeManager(RememberMeManager rememberMeManager) {
 159  0
         this.rememberMeManager = rememberMeManager;
 160  0
     }
 161  
 
 162  
     protected SubjectContext createSubjectContext() {
 163  34
         return new DefaultSubjectContext();
 164  
     }
 165  
 
 166  
     /**
 167  
      * Creates a {@code Subject} instance for the user represented by the given method arguments.
 168  
      *
 169  
      * @param token    the {@code AuthenticationToken} submitted for the successful authentication.
 170  
      * @param info     the {@code AuthenticationInfo} of a newly authenticated user.
 171  
      * @param existing the existing {@code Subject} instance that initiated the authentication attempt
 172  
      * @return the {@code Subject} instance that represents the context and session data for the newly
 173  
      *         authenticated subject.
 174  
      */
 175  
     protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {
 176  34
         SubjectContext context = createSubjectContext();
 177  34
         context.setAuthenticated(true);
 178  34
         context.setAuthenticationToken(token);
 179  34
         context.setAuthenticationInfo(info);
 180  34
         if (existing != null) {
 181  34
             context.setSubject(existing);
 182  
         }
 183  34
         return createSubject(context);
 184  
     }
 185  
 
 186  
     /**
 187  
      * Binds a {@code Subject} instance created after authentication to the application for later use.
 188  
      * <p/>
 189  
      * As of Shiro 1.2, this method has been deprecated in favor of {@link #save(org.apache.shiro.subject.Subject)},
 190  
      * which this implementation now calls.
 191  
      *
 192  
      * @param subject the {@code Subject} instance created after authentication to be bound to the application
 193  
      *                for later use.
 194  
      * @see #save(org.apache.shiro.subject.Subject)
 195  
      * @deprecated in favor of {@link #save(org.apache.shiro.subject.Subject) save(subject)}.
 196  
      */
 197  
     @Deprecated
 198  
     protected void bind(Subject subject) {
 199  0
         save(subject);
 200  0
     }
 201  
 
 202  
     protected void rememberMeSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
 203  34
         RememberMeManager rmm = getRememberMeManager();
 204  34
         if (rmm != null) {
 205  
             try {
 206  0
                 rmm.onSuccessfulLogin(subject, token, info);
 207  0
             } catch (Exception e) {
 208  0
                 if (log.isWarnEnabled()) {
 209  0
                     String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
 210  
                             "] threw an exception during onSuccessfulLogin.  RememberMe services will not be " +
 211  
                             "performed for account [" + info + "].";
 212  0
                     log.warn(msg, e);
 213  
                 }
 214  0
             }
 215  
         } else {
 216  34
             if (log.isTraceEnabled()) {
 217  68
                 log.trace("This " + getClass().getName() + " instance does not have a " +
 218  34
                         "[" + RememberMeManager.class.getName() + "] instance configured.  RememberMe services " +
 219  
                         "will not be performed for account [" + info + "].");
 220  
             }
 221  
         }
 222  34
     }
 223  
 
 224  
     protected void rememberMeFailedLogin(AuthenticationToken token, AuthenticationException ex, Subject subject) {
 225  8
         RememberMeManager rmm = getRememberMeManager();
 226  8
         if (rmm != null) {
 227  
             try {
 228  0
                 rmm.onFailedLogin(subject, token, ex);
 229  0
             } catch (Exception e) {
 230  0
                 if (log.isWarnEnabled()) {
 231  0
                     String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
 232  
                             "] threw an exception during onFailedLogin for AuthenticationToken [" +
 233  
                             token + "].";
 234  0
                     log.warn(msg, e);
 235  
                 }
 236  0
             }
 237  
         }
 238  8
     }
 239  
 
 240  
     protected void rememberMeLogout(Subject subject) {
 241  18
         RememberMeManager rmm = getRememberMeManager();
 242  18
         if (rmm != null) {
 243  
             try {
 244  0
                 rmm.onLogout(subject);
 245  0
             } catch (Exception e) {
 246  0
                 if (log.isWarnEnabled()) {
 247  0
                     String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
 248  
                             "] threw an exception during onLogout for subject with principals [" +
 249  0
                             (subject != null ? subject.getPrincipals() : null) + "]";
 250  0
                     log.warn(msg, e);
 251  
                 }
 252  0
             }
 253  
         }
 254  18
     }
 255  
 
 256  
     /**
 257  
      * First authenticates the {@code AuthenticationToken} argument, and if successful, constructs a
 258  
      * {@code Subject} instance representing the authenticated account's identity.
 259  
      * <p/>
 260  
      * Once constructed, the {@code Subject} instance is then {@link #bind bound} to the application for
 261  
      * subsequent access before being returned to the caller.
 262  
      *
 263  
      * @param token the authenticationToken to process for the login attempt.
 264  
      * @return a Subject representing the authenticated user.
 265  
      * @throws AuthenticationException if there is a problem authenticating the specified {@code token}.
 266  
      */
 267  
     public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
 268  
         AuthenticationInfo info;
 269  
         try {
 270  42
             info = authenticate(token);
 271  8
         } catch (AuthenticationException ae) {
 272  
             try {
 273  8
                 onFailedLogin(token, ae, subject);
 274  0
             } catch (Exception e) {
 275  0
                 if (log.isInfoEnabled()) {
 276  0
                     log.info("onFailedLogin method threw an " +
 277  
                             "exception.  Logging and propagating original AuthenticationException.", e);
 278  
                 }
 279  8
             }
 280  8
             throw ae; //propagate
 281  34
         }
 282  
 
 283  34
         Subject loggedIn = createSubject(token, info, subject);
 284  
 
 285  34
         onSuccessfulLogin(token, info, loggedIn);
 286  
 
 287  34
         return loggedIn;
 288  
     }
 289  
 
 290  
     protected void onSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
 291  34
         rememberMeSuccessfulLogin(token, info, subject);
 292  34
     }
 293  
 
 294  
     protected void onFailedLogin(AuthenticationToken token, AuthenticationException ae, Subject subject) {
 295  8
         rememberMeFailedLogin(token, ae, subject);
 296  8
     }
 297  
 
 298  
     protected void beforeLogout(Subject subject) {
 299  18
         rememberMeLogout(subject);
 300  18
     }
 301  
 
 302  
     protected SubjectContext copy(SubjectContext subjectContext) {
 303  92
         return new DefaultSubjectContext(subjectContext);
 304  
     }
 305  
 
 306  
     /**
 307  
      * This implementation functions as follows:
 308  
      * <p/>
 309  
      * <ol>
 310  
      * <li>Ensures the {@code SubjectContext} is as populated as it can be, using heuristics to acquire
 311  
      * data that may not have already been available to it (such as a referenced session or remembered principals).</li>
 312  
      * <li>Calls {@link #doCreateSubject(org.apache.shiro.subject.SubjectContext)} to actually perform the
 313  
      * {@code Subject} instance creation.</li>
 314  
      * <li>calls {@link #save(org.apache.shiro.subject.Subject) save(subject)} to ensure the constructed
 315  
      * {@code Subject}'s state is accessible for future requests/invocations if necessary.</li>
 316  
      * <li>returns the constructed {@code Subject} instance.</li>
 317  
      * </ol>
 318  
      *
 319  
      * @param subjectContext any data needed to direct how the Subject should be constructed.
 320  
      * @return the {@code Subject} instance reflecting the specified contextual data.
 321  
      * @see #ensureSecurityManager(org.apache.shiro.subject.SubjectContext)
 322  
      * @see #resolveSession(org.apache.shiro.subject.SubjectContext)
 323  
      * @see #resolvePrincipals(org.apache.shiro.subject.SubjectContext)
 324  
      * @see #doCreateSubject(org.apache.shiro.subject.SubjectContext)
 325  
      * @see #save(org.apache.shiro.subject.Subject)
 326  
      * @since 1.0
 327  
      */
 328  
     public Subject createSubject(SubjectContext subjectContext) {
 329  
         //create a copy so we don't modify the argument's backing map:
 330  92
         SubjectContext context = copy(subjectContext);
 331  
 
 332  
         //ensure that the context has a SecurityManager instance, and if not, add one:
 333  92
         context = ensureSecurityManager(context);
 334  
 
 335  
         //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before
 336  
         //sending to the SubjectFactory.  The SubjectFactory should not need to know how to acquire sessions as the
 337  
         //process is often environment specific - better to shield the SF from these details:
 338  92
         context = resolveSession(context);
 339  
 
 340  
         //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first
 341  
         //if possible before handing off to the SubjectFactory:
 342  92
         context = resolvePrincipals(context);
 343  
 
 344  92
         Subject subject = doCreateSubject(context);
 345  
 
 346  
         //save this subject for future reference if necessary:
 347  
         //(this is needed here in case rememberMe principals were resolved and they need to be stored in the
 348  
         //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).
 349  
         //Added in 1.2:
 350  92
         save(subject);
 351  
 
 352  92
         return subject;
 353  
     }
 354  
 
 355  
     /**
 356  
      * Actually creates a {@code Subject} instance by delegating to the internal
 357  
      * {@link #getSubjectFactory() subjectFactory}.  By the time this method is invoked, all possible
 358  
      * {@code SubjectContext} data (session, principals, et. al.) has been made accessible using all known heuristics
 359  
      * and will be accessible to the {@code subjectFactory} via the {@code subjectContext.resolve*} methods.
 360  
      *
 361  
      * @param context the populated context (data map) to be used by the {@code SubjectFactory} when creating a
 362  
      *                {@code Subject} instance.
 363  
      * @return a {@code Subject} instance reflecting the data in the specified {@code SubjectContext} data map.
 364  
      * @see #getSubjectFactory()
 365  
      * @see SubjectFactory#createSubject(org.apache.shiro.subject.SubjectContext)
 366  
      * @since 1.2
 367  
      */
 368  
     protected Subject doCreateSubject(SubjectContext context) {
 369  92
         return getSubjectFactory().createSubject(context);
 370  
     }
 371  
 
 372  
     /**
 373  
      * Saves the subject's state to a persistent location for future reference if necessary.
 374  
      * <p/>
 375  
      * This implementation merely delegates to the internal {@link #setSubjectDAO(SubjectDAO) subjectDAO} and calls
 376  
      * {@link SubjectDAO#save(org.apache.shiro.subject.Subject) subjectDAO.save(subject)}.
 377  
      *
 378  
      * @param subject the subject for which state will potentially be persisted
 379  
      * @see SubjectDAO#save(org.apache.shiro.subject.Subject)
 380  
      * @since 1.2
 381  
      */
 382  
     protected void save(Subject subject) {
 383  92
         this.subjectDAO.save(subject);
 384  92
     }
 385  
 
 386  
     /**
 387  
      * Removes (or 'unbinds') the Subject's state from the application, typically called during {@link #logout}..
 388  
      * <p/>
 389  
      * This implementation merely delegates to the internal {@link #setSubjectDAO(SubjectDAO) subjectDAO} and calls
 390  
      * {@link SubjectDAO#delete(org.apache.shiro.subject.Subject) delete(subject)}.
 391  
      *
 392  
      * @param subject the subject for which state will be removed
 393  
      * @see SubjectDAO#delete(org.apache.shiro.subject.Subject)
 394  
      * @since 1.2
 395  
      */
 396  
     protected void delete(Subject subject) {
 397  18
         this.subjectDAO.delete(subject);
 398  18
     }
 399  
 
 400  
     /**
 401  
      * Determines if there is a {@code SecurityManager} instance in the context, and if not, adds 'this' to the
 402  
      * context.  This ensures the SubjectFactory instance will have access to a SecurityManager during Subject
 403  
      * construction if necessary.
 404  
      *
 405  
      * @param context the subject context data that may contain a SecurityManager instance.
 406  
      * @return The SubjectContext to use to pass to a {@link SubjectFactory} for subject creation.
 407  
      * @since 1.0
 408  
      */
 409  
     @SuppressWarnings({"unchecked"})
 410  
     protected SubjectContext ensureSecurityManager(SubjectContext context) {
 411  92
         if (context.resolveSecurityManager() != null) {
 412  84
             log.trace("Context already contains a SecurityManager instance.  Returning.");
 413  84
             return context;
 414  
         }
 415  8
         log.trace("No SecurityManager found in context.  Adding self reference.");
 416  8
         context.setSecurityManager(this);
 417  8
         return context;
 418  
     }
 419  
 
 420  
     /**
 421  
      * Attempts to resolve any associated session based on the context and returns a
 422  
      * context that represents this resolved {@code Session} to ensure it may be referenced if necessary by the
 423  
      * invoked {@link SubjectFactory} that performs actual {@link Subject} construction.
 424  
      * <p/>
 425  
      * If there is a {@code Session} already in the context because that is what the caller wants to be used for
 426  
      * {@code Subject} construction, or if no session is resolved, this method effectively does nothing
 427  
      * returns the context method argument unaltered.
 428  
      *
 429  
      * @param context the subject context data that may resolve a Session instance.
 430  
      * @return The context to use to pass to a {@link SubjectFactory} for subject creation.
 431  
      * @since 1.0
 432  
      */
 433  
     @SuppressWarnings({"unchecked"})
 434  
     protected SubjectContext resolveSession(SubjectContext context) {
 435  92
         if (context.resolveSession() != null) {
 436  0
             log.debug("Context already contains a session.  Returning.");
 437  0
             return context;
 438  
         }
 439  
         try {
 440  
             //Context couldn't resolve it directly, let's see if we can since we have direct access to 
 441  
             //the session manager:
 442  92
             Session session = resolveContextSession(context);
 443  92
             if (session != null) {
 444  0
                 context.setSession(session);
 445  
             }
 446  0
         } catch (InvalidSessionException e) {
 447  0
             log.debug("Resolved SubjectContext context session is invalid.  Ignoring and creating an anonymous " +
 448  
                     "(session-less) Subject instance.", e);
 449  92
         }
 450  92
         return context;
 451  
     }
 452  
 
 453  
     protected Session resolveContextSession(SubjectContext context) throws InvalidSessionException {
 454  92
         SessionKey key = getSessionKey(context);
 455  92
         if (key != null) {
 456  0
             return getSession(key);
 457  
         }
 458  92
         return null;
 459  
     }
 460  
 
 461  
     protected SessionKey getSessionKey(SubjectContext context) {
 462  92
         Serializable sessionId = context.getSessionId();
 463  92
         if (sessionId != null) {
 464  0
             return new DefaultSessionKey(sessionId);
 465  
         }
 466  92
         return null;
 467  
     }
 468  
 
 469  
     /**
 470  
      * Attempts to resolve an identity (a {@link PrincipalCollection}) for the context using heuristics.  This
 471  
      * implementation functions as follows:
 472  
      * <ol>
 473  
      * <li>Check the context to see if it can already {@link SubjectContext#resolvePrincipals resolve an identity}.  If
 474  
      * so, this method does nothing and returns the method argument unaltered.</li>
 475  
      * <li>Check for a RememberMe identity by calling {@link #getRememberedIdentity}.  If that method returns a
 476  
      * non-null value, place the remembered {@link PrincipalCollection} in the context.</li>
 477  
      * </ol>
 478  
      *
 479  
      * @param context the subject context data that may provide (directly or indirectly through one of its values) a
 480  
      *                {@link PrincipalCollection} identity.
 481  
      * @return The Subject context to use to pass to a {@link SubjectFactory} for subject creation.
 482  
      * @since 1.0
 483  
      */
 484  
     @SuppressWarnings({"unchecked"})
 485  
     protected SubjectContext resolvePrincipals(SubjectContext context) {
 486  
 
 487  92
         PrincipalCollection principals = context.resolvePrincipals();
 488  
 
 489  92
         if (CollectionUtils.isEmpty(principals)) {
 490  58
             log.trace("No identity (PrincipalCollection) found in the context.  Looking for a remembered identity.");
 491  
 
 492  58
             principals = getRememberedIdentity(context);
 493  
 
 494  58
             if (!CollectionUtils.isEmpty(principals)) {
 495  0
                 log.debug("Found remembered PrincipalCollection.  Adding to the context to be used " +
 496  
                         "for subject construction by the SubjectFactory.");
 497  
 
 498  0
                 context.setPrincipals(principals);
 499  
 
 500  
                 // The following call was removed (commented out) in Shiro 1.2 because it uses the session as an
 501  
                 // implementation strategy.  Session use for Shiro's own needs should be controlled in a single place
 502  
                 // to be more manageable for end-users: there are a number of stateless (e.g. REST) applications that
 503  
                 // use Shiro that need to ensure that sessions are only used when desirable.  If Shiro's internal
 504  
                 // implementations used Subject sessions (setting attributes) whenever we wanted, it would be much
 505  
                 // harder for end-users to control when/where that occurs.
 506  
                 //
 507  
                 // Because of this, the SubjectDAO was created as the single point of control, and session state logic
 508  
                 // has been moved to the DefaultSubjectDAO implementation.
 509  
 
 510  
                 // Removed in Shiro 1.2.  SHIRO-157 is still satisfied by the new DefaultSubjectDAO implementation
 511  
                 // introduced in 1.2
 512  
                 // Satisfies SHIRO-157:
 513  
                 // bindPrincipalsToSession(principals, context);
 514  
 
 515  
             } else {
 516  58
                 log.trace("No remembered identity found.  Returning original context.");
 517  
             }
 518  
         }
 519  
 
 520  92
         return context;
 521  
     }
 522  
 
 523  
     protected SessionContext createSessionContext(SubjectContext subjectContext) {
 524  0
         DefaultSessionContext sessionContext = new DefaultSessionContext();
 525  0
         if (!CollectionUtils.isEmpty(subjectContext)) {
 526  0
             sessionContext.putAll(subjectContext);
 527  
         }
 528  0
         Serializable sessionId = subjectContext.getSessionId();
 529  0
         if (sessionId != null) {
 530  0
             sessionContext.setSessionId(sessionId);
 531  
         }
 532  0
         String host = subjectContext.resolveHost();
 533  0
         if (host != null) {
 534  0
             sessionContext.setHost(host);
 535  
         }
 536  0
         return sessionContext;
 537  
     }
 538  
 
 539  
     public void logout(Subject subject) {
 540  
 
 541  18
         if (subject == null) {
 542  0
             throw new IllegalArgumentException("Subject method argument cannot be null.");
 543  
         }
 544  
 
 545  18
         beforeLogout(subject);
 546  
 
 547  18
         PrincipalCollection principals = subject.getPrincipals();
 548  18
         if (principals != null && !principals.isEmpty()) {
 549  16
             if (log.isDebugEnabled()) {
 550  16
                 log.debug("Logging out subject with primary principal {}", principals.getPrimaryPrincipal());
 551  
             }
 552  16
             Authenticator authc = getAuthenticator();
 553  16
             if (authc instanceof LogoutAware) {
 554  16
                 ((LogoutAware) authc).onLogout(principals);
 555  
             }
 556  
         }
 557  
 
 558  
         try {
 559  18
             delete(subject);
 560  0
         } catch (Exception e) {
 561  0
             if (log.isDebugEnabled()) {
 562  0
                 String msg = "Unable to cleanly unbind Subject.  Ignoring (logging out).";
 563  0
                 log.debug(msg, e);
 564  
             }
 565  
         } finally {
 566  0
             try {
 567  18
                 stopSession(subject);
 568  0
             } catch (Exception e) {
 569  0
                 if (log.isDebugEnabled()) {
 570  0
                     String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " +
 571  
                             "Ignoring (logging out).";
 572  0
                     log.debug(msg, e);
 573  
                 }
 574  18
             }
 575  0
         }
 576  18
     }
 577  
 
 578  
     protected void stopSession(Subject subject) {
 579  18
         Session s = subject.getSession(false);
 580  18
         if (s != null) {
 581  18
             s.stop();
 582  
         }
 583  18
     }
 584  
 
 585  
     /**
 586  
      * Unbinds or removes the Subject's state from the application, typically called during {@link #logout}.
 587  
      * <p/>
 588  
      * This has been deprecated in Shiro 1.2 in favor of the {@link #delete(org.apache.shiro.subject.Subject) delete}
 589  
      * method.  The implementation has been updated to invoke that method.
 590  
      *
 591  
      * @param subject the subject to unbind from the application as it will no longer be used.
 592  
      * @deprecated in Shiro 1.2 in favor of {@link #delete(org.apache.shiro.subject.Subject)}
 593  
      */
 594  
     @Deprecated
 595  
     @SuppressWarnings({"UnusedDeclaration"})
 596  
     protected void unbind(Subject subject) {
 597  0
         delete(subject);
 598  0
     }
 599  
 
 600  
     protected PrincipalCollection getRememberedIdentity(SubjectContext subjectContext) {
 601  58
         RememberMeManager rmm = getRememberMeManager();
 602  58
         if (rmm != null) {
 603  
             try {
 604  0
                 return rmm.getRememberedPrincipals(subjectContext);
 605  0
             } catch (Exception e) {
 606  0
                 if (log.isWarnEnabled()) {
 607  0
                     String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
 608  
                             "] threw an exception during getRememberedPrincipals().";
 609  0
                     log.warn(msg, e);
 610  
                 }
 611  
             }
 612  
         }
 613  58
         return null;
 614  
     }
 615  
 }