I ended up solving this problem with a simple approach - do the conversion from the email address to the user id before creating the authentication token, and use the user id as the principal in the token.
try{
// Lookup the user by email
User user = userDAO.findByEmail(email);
// If no match we can't authenticate
if(user == null){
throw new AuthenticationException();
}
// Else, build a token with the user id and password
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserId().toString(), password);
// Attempt to login
SecurityUtils.getSubject().login(token);
}catch(AuthenticationException ex){
return false;
}
My UserDAO bean is configured to handle javax.persistence.NoResultException's and return null.
In my shiro.ini file I have changed the jdbcRealm.authenticationQuery
to the following (note I'm using MySQL)
jdbcRealm.authenticationQuery = SELECT password FROM user WHERE user_id = CAST(? AS UNSIGNED)
Finally, to look up details about the user I'm now looking up by the user id, which is now the principal.
currentUser = userDAO.findByUserId(Integer.parseInt((String) SecurityUtils.getSubject().getPrincipal()));