HttpServletResponse response = (HttpServletResponse) servletResponse;
final String accessId = getAtMostOneParameter(request,
this.accessIdParameter);
if (accessId == null || accessId.length() == 0) {
throw new QueryException(QueryError.MissingClientTokenId);
}
final String signature = getExactlyOneParameter(request,
this.signatureParameter);
final String signatureVersion = getExactlyOneParameter(request,
this.signatureVersionParameter);
// Note that signature version 1 has known vulnerabilities when used across plain
// HTTP. This interface should only be offered over SSL.
// see http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1928
//
// if another version comes along, this library will need to be updated
if (!(SIGNATURE_VERSION_2.equals(signatureVersion) ||
SIGNATURE_VERSION_1.equals(signatureVersion))) {
throw new QueryException(QueryError.InvalidParameterValue,
"Only signature versions 1 and 2 are supported");
}
String signatureMethod = getAtMostOneParameter(request,
this.signatureMethodParameter);
if (signatureMethod != null) {
if (!(signatureMethod.equals(HMACSHA256) ||
signatureMethod.equals(HMACSHA1))) {
throw new QueryException(QueryError.InvalidParameterValue,
"Only "+ HMACSHA256 +" or " +HMACSHA1 +
" are supported signature methods");
}
} else {
signatureMethod = HMACSHA1;
}
final String timestamp = getAtMostOneParameter(request,
this.timestampParameter);
final String expires = getAtMostOneParameter(request,
this.expiresParameter);
final boolean hasTimestamp = timestamp != null;
final boolean hasExpires = expires != null;
if (hasTimestamp == hasExpires) {
throw new QueryException(QueryError.InvalidArgument,
"Request must have timestamp or expiration, but not both");
}
final QueryUser user;
try {
user = userDetailsService.loadUserByUsername(accessId);
} catch (UsernameNotFoundException e) {
throw new QueryException(QueryError.InvalidClientTokenId, e);
} catch (DataAccessException e) {
throw new QueryException(QueryError.InternalError,
"Failed to retrieve user token for provided accessID", e);
}
final String secret = user.getSecret();
final String stringToSign;
if (SIGNATURE_VERSION_2.equals(signatureVersion)) {
stringToSign = getStringToSign_v2(request);
} else {
stringToSign = getStringToSign_v1(request);
}
final String checkSig = createSignature(stringToSign,
secret, signatureMethod);
// Note that this comparison will succeed if both inputs are null.
// (But checkSig can't be null in this implementation)
if (!QueryUtils.safeStringEquals(signature, checkSig)) {
logger.warn("Signature check failed on request for accessID: "+accessId);
throw new QueryException(QueryError.SignatureDoesNotMatch,
"Signature check failed!");
}
// check for expiration of request-- replay attack prevention
final DateTime expireTime;
try {
if (hasTimestamp) {
// boto doesn't include the 'Z' in its timestamp
// we force parsing to assume UTC
final DateTime stamp = new DateTime(timestamp, DateTimeZone.UTC);
expireTime = stamp.plusSeconds(this.expirationSeconds);
} else {
expireTime = new DateTime(expires, DateTimeZone.UTC);
}
} catch (IllegalArgumentException e) {
throw new QueryException(QueryError.InvalidParameterValue, "Failed to parse "+
(hasTimestamp ? "timestamp" : "expiration") +
". Must be in ISO8601 format.", e);
}
if (expireTime.isBeforeNow()) {
throw new QueryException(QueryError.RequestExpired, "Request is expired");
}
final QueryAuthenticationToken auth = new QueryAuthenticationToken(user, true);
// okay we have an authenticated request. set token on the SecurityContext