With the help of this post in the shiro mailing list I was able to implement a working solution.
The basic steps are:
1. Implement your own queryForAuthenticationInfo
method in a inherited class of the ActiveDirectoryRealm
2. Specify to use that new class for the query/login operation
public class AarstockADSRealm extends ActiveDirectoryRealm
{
final private Logger _log = LoggerFactory.getLogger(AarstockADSRealm.class);
public AarstockADSRealm()
{
}
@Override
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException
{
//final AuthenticationInfo queryForAuthenticationInfo = super.queryForAuthenticationInfo(token, ldapContextFactory);
final UsernamePasswordToken upToken = (UsernamePasswordToken) token;
LdapContext ctx = null;
try
{
ctx = ldapContextFactory.getSystemLdapContext(); // .getLdapContext(upToken.getUsername(), upToken.getPassword());
final String attribName = "userPrincipalName";
final SearchControls searchCtls = new SearchControls(SearchControls.SUBTREE_SCOPE, 1, 0, new String[]
{
attribName
}, false, false);
final NamingEnumeration<SearchResult> search = ctx.search(searchBase, "sAMAccountName={0}", new Object[]
{
upToken.getPrincipal()
}, searchCtls);
if (search.hasMore())
{
final SearchResult next = search.next();
// upToken.setUsername(next.getAttributes().get(attribName).get().toString());
String loginUser= next.getAttributes().get(attribName).get().toString();
_log.info("Loginuser: "+loginUser);
if (search.hasMore())
{
_log.error("More than one user matching: "+upToken.getPrincipal());
throw new RuntimeException("More than one user matching: "+upToken.getPrincipal());
}
else
{
try
{
LdapContext ctx2 = ldapContextFactory.getLdapContext(loginUser, upToken.getPassword());
}
catch (Exception ex)
{
_log.warn("Error in authentication for user "+loginUser, ex);
// We have to rethrow the exception, to indicate invalid login
throw ex;
}
}
}
else
{
_log.info("No user matching: "+upToken.getPrincipal());
throw new RuntimeException("No user matching: "+upToken.getPrincipal());
}
}
catch (NamingException ne)
{
_log.error("Error in ldap name resolving", ne);
// We have to rethrow the exception, to indicate invalid login
throw ne;
} finally
{
LdapUtils.closeContext(ctx);
}
return buildAuthenticationInfo(upToken.getUsername(), upToken.getPassword());
}
}