// Extract the Authorization header from the incoming HTTP request.
String header = request.getHeader(AUTHORIZATION);
// If the header does not exist or does not start with the correct
// token, give up immediately.
if(header == null || !header.startsWith(HAVALO_AUTHORIZATION_PREFIX)) {
throw new AuthenticationException("Request did not contain " +
"a valid '" + AUTHORIZATION + "' header.");
}
// Extract just the part of the Authorization header that follows
// the Havalo authorization prefix.
header = header.substring(HAVALO_AUTHORIZATION_PREFIX.length());
final String[] tokens = header.split(HAVALO_AUTHORIZATION_SEPARATOR, 2);
if(tokens == null || tokens.length != 2) {
throw new AuthenticationException("Failed to extract correct " +
"number of tokens from '" + AUTHORIZATION + "' header.");
}
// If we get here, then we must have had some valid input
// Authorization header with a real access key and signature.
final String accessKey = tokens[0], signature = tokens[1];
// request.getRequestURI();
// Extract username from incoming signed request header.
// Expected format is ...
// Authorization: Havalo AccessKey:Signature
// ... where the AccessKey is the unique UUID used to identify the user.
// And, the Signature is ...
// Base64( HMAC-SHA256( UTF-8-Encoding-Of( AccessSecret, StringToSign ) ) );
// And, the StringToSign is ....
// HTTP-Verb (GET, PUT, POST, or DELETE) + "\n" +
// RFC822 Date (from 'Date' request header, must exist) + "\n" +
// Content-Type (from 'Content-Type' request header, optional) + "\n" +
// CanonicalizedResource (the part of this request's URL from
// the protocol name up to the query string in the first line
// of the HTTP request)
// Call the user details service to load the user data for the UUID.
final KeyPair userKp = userService_.loadKeyPairById(
UUID.fromString(accessKey));
if(userKp == null) {
throw new AuthenticationException("User service returned " +
"null, which is an interface contract violation.");
}
// Get the string to sign -- will fail gracefully if the incoming
// request does not have the proper headers attached to it.
final String stringToSign = getStringToSign(request);
// Compute the resulting signed signature.
final String computed = HMACSHA256Signer.sign(userKp, stringToSign);
// Does the signature match what was passed to us in the
// Authorization request header?
if(!computed.equals(signature)) {
throw new BadCredentialsException("Signatures did not " +
"match (request=" + signature + ", computed=" + computed +
")");
}
// Success!
request.setAttribute(HAVALO_AUTHENTICATION_ATTRIBUTE, userKp);
} catch (Exception e) {
logger__.debug("Authentication failure; service failed " +
"to authenticate request.", e);
throw new AuthenticationException("Authentication " +
"failed; either the provided signature did not match, " +
"or you do not have permission to access the requested " +
"resource.", e);
}
}