monasca-api/src/main/java/com/hp/csbu/cc/middleware/HPS3Signer.java.txt

237 lines
7.4 KiB
Plaintext

package com.hp.csbu.cc.middleware;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest;
import com.hp.csbu.cc.security.cs.thrift.service.SignatureCredentials;
import static com.hp.csbu.cc.middleware.AuthConstants.SIGNATURE_METHOD;
public class HPS3Signer implements Signer {
private final Set<String> subResources = new HashSet<String>() {
{
add("acl");
add("logging");
add("torrent");
add("location");
add("requestPayment");
}
};
public SigAuthRequest sign(ServletRequest req, String serviceIds,
String endPointIds) {
String accessKeyId = null;
String signature = null;
String dataToSign = null;
if (req.getParameter("AWSAccessKeyId") != null) {
if (hasRequestExpired(req)) {
throw new SignatureBuilderException(
"Either signature is expired or expiration field is missing");
}
req.setAttribute("Date", req.getParameter("Expires"));
accessKeyId = req.getParameter("AWSAccessKeyId");
signature = req.getParameter("Signature");
} else {
Date d = null;
if (((HttpServletRequest) req).getHeader("X-Amz-Date") != null) {
d = parseDate(((HttpServletRequest) req)
.getHeader("X-Amz-Date"));
} else if (((HttpServletRequest) req).getHeader("Date") != null) {
d = parseDate(((HttpServletRequest) req).getHeader("Date"));
} else {
throw new SignatureBuilderException(
"Either date is missing or an invalid date is provided");
}
if (hasClockSkew(d)) {
throw new SignatureBuilderException(
"Date is invalid. Date is skewed by more than 15 mins");
}
String authorizationStr = ((HttpServletRequest) req)
.getHeader("Authorization");
authorizationStr = authorizationStr.substring(
authorizationStr.indexOf(" ")).trim();
int colonDelimeter = authorizationStr.lastIndexOf(":");
accessKeyId = authorizationStr.substring(0, colonDelimeter);
signature = authorizationStr.substring(colonDelimeter + 1);
}
dataToSign = getCanonicalString(req);
return getSignedRequest(dataToSign, accessKeyId, signature,
SIGNATURE_METHOD, serviceIds, endPointIds);
}
protected boolean hasClockSkew(Date d) {
if (d == null) {
// Invalid date
return true;
}
Date currentDate = new Date();
long currentTime = currentDate.getTime();
long epochTime = getUnixEpochTime();
long requestTime = d.getTime();
long delta = TimeUnit.MILLISECONDS.convert(15L, TimeUnit.MINUTES);
if (requestTime < epochTime) {
// Invalid date
return true;
}
if (Math.abs(requestTime - currentTime) > delta) {
// Invalid date
return true;
}
return false;
}
protected String getCanonicalString(ServletRequest req) {
HttpServletRequest request = ((HttpServletRequest) req);
StringBuffer canonicalStr = new StringBuffer();
Map<String, String> amzHeaders = new TreeMap<String, String>();
String contentMd5 = (request.getHeader("Content-MD5") == null) ? ""
: request.getHeader("Content-MD5");
String contentType = (request.getHeader("Content-Type") == null) ? ""
: request.getHeader("Content-Type");
String method = request.getMethod();
canonicalStr.append(method).append("\n").append(contentMd5)
.append("\n").append(contentType).append("\n");
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = ((String) headers.nextElement()).toLowerCase();
if (headerName.startsWith("x-amz-")) {
Enumeration multiHeaderValues = request.getHeaders(headerName);
StringBuffer headerValues = new StringBuffer();
headerValues.append((String) multiHeaderValues.nextElement());
while (multiHeaderValues.hasMoreElements()) {
headerValues.append(",").append(
multiHeaderValues.nextElement());
}
amzHeaders.put(headerName, headerValues.toString());
}
}
if (amzHeaders.containsKey("X-Amz-Date")) {
canonicalStr.append("\n");
} else {
String date = (request.getHeader("Date") != null) ? (String) request
.getHeader("Date") : (String) request.getAttribute("Date");
canonicalStr.append(date).append("\n");
}
for (String key : amzHeaders.keySet()) {
canonicalStr.append(key).append(":").append(amzHeaders.get(key))
.append("\n");
}
String resource = getCanonicalResource(request);
canonicalStr.append(resource);
return canonicalStr.toString();
}
protected String getCanonicalResource(HttpServletRequest request) {
StringBuffer canonicalResource = new StringBuffer();
canonicalResource.append(request.getRequestURI());
String queryString = request.getQueryString();
if (queryString != null) {
canonicalResource.append(getCanonicalSubResource(queryString));
}
return canonicalResource.toString();
}
protected String getCanonicalSubResource(String queryString) {
String[] queryParams;
if (queryString.contains("&")) {
queryParams = queryString.split("&");
} else {
queryParams = new String[1];
queryParams[0] = queryString;
}
for (String param : queryParams) {
String paramName = param;
if (paramName.contains("=")) {
paramName = paramName.substring(0, paramName.indexOf("="));
}
if (subResources.contains(paramName)) {
return "?" + paramName;
}
}
return "";
}
protected long getUnixEpochTime() {
Format formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
Date date;
try {
date = (Date) formatter.parseObject("01 Jan 1970 00:00:00 UTC");
} catch (ParseException e) {
return 0;
}
return date.getTime();
}
protected boolean hasRequestExpired(ServletRequest req) {
if (req.getParameter("Expires") == null) {
return true;
}
long expirationTime = new Long(req.getParameter("Expires"));
return expirationTime < (System.currentTimeMillis()/1000);
}
protected Date parseDate(String data) {
/* Currently date is parsed in RFC 822 format */
SimpleDateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
df.setTimeZone(new SimpleTimeZone(0, "UTC"));
try {
return df.parse(data);
} catch (ParseException e) {
return null;
}
}
protected SigAuthRequest getSignedRequest(String dataToSign,
String accessKeyId, String signature, String signatureMethod,
String serviceIds, String endPointIds) {
try {
SignatureCredentials credentials = null;
Map<String, String> params = new HashMap<String, String>();
String tenantId = null;
String keyId = accessKeyId;
if (accessKeyId.contains(":")) {
String[] strArr = accessKeyId.split(":");
tenantId = strArr[0];
keyId = strArr[1];
}
credentials = new SignatureCredentials(keyId, "accesskey",
signatureMethod, dataToSign, signature);
//If tenantId is null, you get an unscoped token.
if (tenantId != null) {
params.put("tenantId", tenantId);
}
if (serviceIds != null) {
params.put("serviceIds", serviceIds);
}
if (endPointIds != null) {
params.put("endPointTemplateIds", endPointIds);
}
return new SigAuthRequest(credentials, params);
} catch (Exception e) {
throw new SignatureBuilderException(
"Exception building signature with given credentials");
}
}
}