/** * Default no-arg constructor that initializes its internal * <code>authenticator</code> instance to a * {@link org.apache.shiro.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator}. */ public AuthenticatingSecurityManager() { super(); this.authenticator = new ModularRealmAuthenticator(); }
/** * Default no-argument constructor which * {@link #setAuthenticationStrategy(AuthenticationStrategy) enables} an * {@link org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy} by default. */ public ModularRealmAuthenticator() { this.authenticationStrategy = new AtLeastOneSuccessfulStrategy(); }
/** * Base implementation that will aggregate the specified <code>singleRealmInfo</code> into the * <code>aggregateInfo</code> and then returns the aggregate. Can be overridden by subclasses for custom behavior. */ public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException { AuthenticationInfo info; if (singleRealmInfo == null) { info = aggregateInfo; } else { if (aggregateInfo == null) { info = singleRealmInfo; } else { info = merge(singleRealmInfo, aggregateInfo); } } return info; }
AuthenticationStrategy strategy = getAuthenticationStrategy(); AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token); aggregate = strategy.beforeAttempt(realm, token, aggregate); aggregate = strategy.afterAttempt(realm, token, info, aggregate, t); aggregate = strategy.afterAllAttempts(token, aggregate);
protected Authenticator authenticator() { ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator(); authenticator.setAuthenticationStrategy(authenticationStrategy()); return authenticator; }
assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken);
/** * Because all realms in this strategy must complete successfully, this implementation ensures that the given * <code>Realm</code> {@link org.apache.shiro.realm.Realm#supports(org.apache.shiro.authc.AuthenticationToken) supports} the given * <code>token</code> argument. If it does not, this method throws an * {@link UnsupportedTokenException UnsupportedTokenException} to end the authentication * process immediately. If the realm does support the token, the <code>info</code> argument is returned immediately. */ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException { if (!realm.supports(token)) { String msg = "Realm [" + realm + "] of type [" + realm.getClass().getName() + "] does not support " + " the submitted AuthenticationToken [" + token + "]. The [" + getClass().getName() + "] implementation requires all configured realm(s) to support and be able to process the submitted " + "AuthenticationToken."; throw new UnsupportedTokenException(msg); } return info; }
/** * Passes on the {@link #getRealms() realms} to the internal delegate <code>Authenticator</code> instance so * that it may use them during authentication attempts. */ protected void afterRealmsSet() { super.afterRealmsSet(); if (this.authenticator instanceof ModularRealmAuthenticator) { ((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms()); } }
@Before public void setUp() { strategy = new FirstSuccessfulStrategy(); }
protected void assertRealmsConfigured() throws IllegalStateException { Collection<Realm> realms = getRealms(); if (CollectionUtils.isEmpty(realms)) { String msg = "Configuration error: No realms have been configured! One or more realms must be " + "present to execute an authentication attempt."; throw new IllegalStateException(msg); } }
@Before public void setUp() { strategy = new AllSuccessfulStrategy(); }
@Test public void testMergeWithValidAggregateInfo() { AuthenticationInfo aggregate = new MergableAuthenticationInfo() { @Override public void merge(AuthenticationInfo info) { } @Override public PrincipalCollection getPrincipals() { return new SimplePrincipalCollection("principals", "realmName"); } @Override public Object getCredentials() { return null; } }; AuthenticationInfo mergeResult = strategy.merge(new SimpleAuthenticationInfo(), aggregate); assertEquals(aggregate, mergeResult); }
/** * Returns the specified {@code aggregate} instance if is non null and valid (that is, has principals and they are * not empty) immediately, or, if it is null or not valid, the {@code info} argument is returned instead. * <p/> * This logic ensures that the first valid info encountered is the one retained and all subsequent ones are ignored, * since this strategy mandates that only the info from the first successfully authenticated realm be used. */ protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) { if (aggregate != null && !isEmpty(aggregate.getPrincipals())) { return aggregate; } return info != null ? info : aggregate; } }
/** * Ensures that the <code>aggregate</code> method argument is not <code>null</code> and * <code>aggregate.{@link org.apache.shiro.authc.AuthenticationInfo#getPrincipals() getPrincipals()}</code> * is not <code>null</code>, and if either is <code>null</code>, throws an AuthenticationException to indicate * that none of the realms authenticated successfully. */ public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { //we know if one or more were able to successfully authenticate if the aggregated account object does not //contain null or empty data: if (aggregate == null || isEmpty(aggregate.getPrincipals())) { throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " + "could not be authenticated by any configured realms. Please ensure that at least one realm can " + "authenticate these tokens."); } return aggregate; } }
@Test(expected = UnsupportedTokenException.class) public void beforeAttemptRealmDoesntSupportToken() { Realm notSupportingRealm = new AuthorizingRealm() { public boolean supports(AuthenticationToken token) { return false; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return null; } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { return null; } }; strategy.beforeAttempt(notSupportingRealm, null, null); }
@Test public void beforeAllAttempts() { AuthenticationInfo info = strategy.beforeAllAttempts(null, null); assertNotNull(info); }
@Test public void beforeAllAttempts() { AuthenticationInfo authenticationInfo = strategy.beforeAllAttempts(null, null); assertNull(authenticationInfo); }
protected AuthenticationStrategy authenticationStrategy() { return new AtLeastOneSuccessfulStrategy(); }
/** * Performs the authentication attempt by interacting with the single configured realm, which is significantly * simpler than performing multi-realm logic. * * @param realm the realm to consult for AuthenticationInfo. * @param token the submitted AuthenticationToken representing the subject's (user's) log-in principals and credentials. * @return the AuthenticationInfo associated with the user account corresponding to the specified {@code token} */ protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { String msg = "Realm [" + realm + "] does not support authentication token [" + token + "]. Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type."; throw new UnsupportedTokenException(msg); } AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); } return info; }
@Test public void testMergeWithInvalidAggregateInfo() { AuthenticationInfo aggregate = new MergableAuthenticationInfo() { @Override public void merge(AuthenticationInfo info) { } @Override public PrincipalCollection getPrincipals() { return new SimplePrincipalCollection(); } @Override public Object getCredentials() { return null; } }; AuthenticationInfo authInfo = new SimpleAuthenticationInfo(); AuthenticationInfo mergeResult = strategy.merge(authInfo, aggregate); assertEquals(authInfo, mergeResult); }