4

We are using two realms (one for hashed passwords, the other one for generated plaintext keys) - this is working as expected.

With a single realm, we could throw a DisabledAccountException exception in our realm's protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authToken) and explicitly catch such an exception in our application.

Now that we have two realms, all exceptions are Shiro-internally caught; so if one realm fails, the second one can be tried as well. However, this kind of redirect will only throw generic AuthenticationExceptions to our application.

Is there any workaround with multiple realms so that we can have more specific exceptions (to know if an account is locked, the credentials are simply wrong,...)?

BillHaggerty
  • 6,157
  • 10
  • 35
  • 68
xeraa
  • 10,456
  • 3
  • 33
  • 66

1 Answers1

8

You need to specify your own AuthenticationStrategy in your ModularRealmAuthenticator. The ModularRealmAuthenticator uses AtLeastOneSuccessfulStrategy by default and AtLeastOneSuccessfulStrategy ignores the exceptions and keeps trying to login the users using all the realms available.

We had a similar scenario on the tynamo project and to workaround this issue I've implemented my own AuthenticationStrategy, called FirstExceptionStrategy, that works with multiple realms and throws the first exception it gets. This approach works fine as long as there is only one Realm per Token type.

The implementations is rather simple:

/**
 * {@link org.apache.shiro.authc.pam.AuthenticationStrategy} implementation that throws the first exception it gets
 * and ignores all subsequent realms. If there is no exceptions it works as the {@link FirstSuccessfulStrategy}
 *
 * WARN: This approach works fine as long as there is ONLY ONE Realm per Token type.
 *
 */
public class FirstExceptionStrategy extends FirstSuccessfulStrategy {

    @Override
    public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
        if ((t != null) && (t instanceof AuthenticationException)) throw (AuthenticationException) t;
        return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
    }

}

I repeat, this only works if there is ONLY ONE Realm per Token type.

For more info about my particular scenario see here: http://jira.codehaus.org/browse/TYNAMO-154

ascandroli
  • 3,309
  • 1
  • 14
  • 15
  • Unfortunately we're using ``UsernamePasswordToken`` for both realms, so this won't solve our problem... But thanks for the input! – xeraa Nov 19 '12 at 14:26
  • 2
    Without different _Tokens_ it will be really hard for the strategy to know if it should throw an exception or it should keep looking through the realm list. Take a look at _ModularRealmAuthenticator.doMultiRealmAuthentication_. Maybe you can create your own aggregate in _beforeAllAttempts_, save the exceptions in the aggregate in _afterAttempt_ and later throw the exception in _afterAllAttempts_. – ascandroli Nov 22 '12 at 18:18
  • Thanks for the pointer, but I think that's not worth it. We are currently fine with the generic exception and will try your suggestion in case we need additional information. – xeraa Nov 22 '12 at 23:51