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