// Lookup password for presented username
// NB: DAO-provided password MUST be clear text - not encoded/salted
// (unless this instance's passwordAlreadyEncoded property is 'false')
boolean loadedFromDao = false;
UserDetails user = userCache.getUserFromCache(username);
if (user == null) {
loadedFromDao = true;
try {
user = userDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {
fail(request, response,
new BadCredentialsException(messages.getMessage("DigestProcessingFilter.usernameNotFound",
new Object[]{username}, "Username {0} not found")));
return;
}
if (user == null) {
throw new AuthenticationServiceException(
"AuthenticationDao returned null, which is an interface contract violation");
}
userCache.putUserInCache(user);
}
// Compute the expected response-digest (will be in hex form)
String serverDigestMd5;
// Don't catch IllegalArgumentException (already checked validity)
serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, user.getPassword(),
((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce);
// If digest is incorrect, try refreshing from backend and recomputing
if (!serverDigestMd5.equals(responseDigest) && !loadedFromDao) {
if (logger.isDebugEnabled()) {
logger.debug(
"Digest comparison failure; trying to refresh user from DAO in case password had changed");
}
try {
user = userDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {
// Would very rarely happen, as user existed earlier
fail(request, response,
new BadCredentialsException(messages.getMessage("DigestProcessingFilter.usernameNotFound",
new Object[]{username}, "Username {0} not found")));
}
userCache.putUserInCache(user);
// Don't catch IllegalArgumentException (already checked validity)
serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, user.getPassword(),
((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce);
}
// If digest is still incorrect, definitely reject authentication attempt
if (!serverDigestMd5.equals(responseDigest)) {
if (logger.isDebugEnabled()) {
logger.debug("Expected response: '" + serverDigestMd5 + "' but received: '" + responseDigest
+ "'; is AuthenticationDao returning clear text passwords?");
}
fail(request, response,
new BadCredentialsException(messages.getMessage("DigestProcessingFilter.incorrectResponse",
"Incorrect response")));
return;
}
// To get this far, the digest must have been valid
// Check the nonce has not expired
// We do this last so we can direct the user agent its nonce is stale
// but the request was otherwise appearing to be valid
if (nonceExpiryTime < System.currentTimeMillis()) {
fail(request, response,
new NonceExpiredException(messages.getMessage("DigestProcessingFilter.nonceExpired",
"Nonce has expired/timed out")));
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Authentication success for user: '" + username + "' with response: '" + responseDigest
+ "'");
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user,
user.getPassword());
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
SecurityContextHolder.getContext().setAuthentication(authRequest);
}