I've been struggling with authenticationStrategy settings with shiro 1.2.1 in a spring based web application. I have 2 realms. One authenticates against database and one against ldap. both realms are working fine just that i wanted a FirstSuccessfulStrategy but it seems both realms are still being called. here is my security-application-context:
<bean id="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService">
<property name="hashService" ref="hashService" />
</bean>
<bean id="hashService" class="org.apache.shiro.crypto.hash.DefaultHashService">
<property name="hashAlgorithmName" value="SHA-512" />
<property name="hashIterations" value="500000" />
</bean>
<bean id="SaltedSha512JPARealm" class="bla.bla.webapp.security.SaltedSha512JPARealm">
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.PasswordMatcher">
<property name="passwordService" ref="passwordService"/>
</bean>
</property>
</bean>
<bean id="ldapContextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
<property name="url" value="${user.ldap.connection.url}"/>
<property name="authenticationMechanism" value="${user.ldap.connection.auth_mecanism}"/>
</bean>
<bean id="ldapRealm" class="bla.bla.webapp.security.LDAPRealm">
<property name="userDnTemplate" value="${user.ldap.connection.userDnTemplate}"/>
<property name="contextFactory" ref="ldapContextFactory" />
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="roleRepository,roleRightRepository,rightRepository,userRepository">
<property name="realms">
<list>
<ref local="ldapRealm"/>
<ref local="SaltedSha512JPARealm"/>
</list>
</property>
<property name="authenticator.authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
</property>
</bean>
is there anything there that i am not doing well?
FirstSuccessfulStrategy means that your authenticator will try all your realms to authenticate user until the first successful. Your realms was configured in order: ldapRealm, SaltedSha512JPARealm. So if lapRealm will fail authenticator will try second one. To solve this you can try to configure the most successful or the quickest realm to be first, e.g. you can change your realms order to be SaltedSha512JPARealm, ldapRealm:
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="roleRepository,roleRightRepository,rightRepository,userRepository">
<property name="realms">
<list>
<ref local="SaltedSha512JPARealm"/>
<ref local="ldapRealm"/>
</list>
</property>
<property name="authenticator.authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy"/>
</property>
</bean>
But you should understand that for this configuration if SaltedSha512JPARealm will fail, authenticator will try ldapRealm.
Or you can try to use different token classes for this realms. But it will work only if you have different authentication entry points for each of them.
UPD
It seems that ModularRealmAuthenticator is designed so that it will always try to authenticate user by all realms. FirstSuccessfulStrategy can affect only on authentication result. It will return first successful AuthenticationInfo. To achieve your goal you need to override ModularRealmAuthenticator#doMultiRealmAuthentication method. It can look like this:
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
AuthenticationStrategy strategy = getAuthenticationStrategy();
AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
if (log.isTraceEnabled()) {
log.trace("Iterating through {} realms for PAM authentication", realms.size());
}
for (Realm realm : realms) {
aggregate = strategy.beforeAttempt(realm, token, aggregate);
if (realm.supports(token)) {
log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);
AuthenticationInfo info = null;
Throwable t = null;
try {
info = realm.getAuthenticationInfo(token);
} catch (Throwable throwable) {
t = throwable;
if (log.isDebugEnabled()) {
String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";
log.debug(msg, t);
}
}
aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
// dirty dirty hack
if (aggregate != null && !CollectionUtils.isEmpty(aggregate.getPrincipals())) {
return aggregate;
}
// end dirty dirty hack
} else {
log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token);
}
}
aggregate = strategy.afterAllAttempts(token, aggregate);
return aggregate;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With