com.kingsoft.services.auth.Signer Maven / Gradle / Ivy
package com.kingsoft.services.auth;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.kingsoft.services.HttpHeaders;
import com.kingsoft.services.RequestMessage;
import com.kingsoft.services.exception.KWSClientException;
import com.kingsoft.services.util.DateUtils;
import com.kingsoft.services.util.StringUtils;
public class Signer {
private static final Logger log = LoggerFactory.getLogger(Signer.class);
public static final String KWS_SIGNING_ALGORITHM = "KWS-HMAC-SHA256";
public static final String LINE_SEPARATOR = "\n";
public static void sign(RequestMessage> request) {
request.getHeaders().remove(HttpHeaders.AUTHORIZATION);
request.addHeader(HttpHeaders.HOST, request.getEndpoint().getHost());
request.addHeader(HttpHeaders.REQUEST_DATE, DateUtils.getTimeNow());
// request.addHeader(HttpHeaders.CHECK_SUM, calculateContentHash(request));
request.addHeader(HttpHeaders.KOP_VERSION, StringUtils.VERSION);
String tableName = request.getHeaders().get(HttpHeaders.KOP_TABLENAME);
request.getHeaders().remove(HttpHeaders.KOP_RESOURCE);
request.addHeader(HttpHeaders.KOP_RESOURCE, request.getCredentials().getAccessKeyId() + ":" + tableName);
String signedHeaders = getSignedHeadersString(request);
final String canonicalRequest = createCanonicalRequest(request);
final String stringToSign = createStringToSign(request, canonicalRequest);
final byte[] signingKey = deriveSigningKey(request);
final byte[] signature = sign(
stringToSign.getBytes(Charset.forName("UTF-8")), signingKey,
SigningAlgorithm.HmacSHA256);
request.addHeader(
HttpHeaders.AUTHORIZATION,
buildAuthorizationHeader(signedHeaders, signature,
request.getCredentials()));
}
/**
* Creates the authorization header to be included in the request.
*/
private static String buildAuthorizationHeader(String signedHeaders,
byte[] signature, KWSCredentials credentials) {
final String signingCredentials = credentials.getAccessKeyId();
final String credential = "AccessKey=" + signingCredentials;
final String signerHeaders = "SignedHeaders=" + signedHeaders;
final String signatureHeader = "Signature="
+ StringUtils.base64Encode(signature);
final StringBuilder authHeaderBuilder = new StringBuilder();
authHeaderBuilder.append(KWS_SIGNING_ALGORITHM).append(" ")
.append(credential).append(", ").append(signerHeaders).append(", ")
.append(signatureHeader);
return authHeaderBuilder.toString();
}
protected static byte[] sign(byte[] data, byte[] key,
SigningAlgorithm algorithm) throws KWSClientException {
try {
Mac mac = Mac.getInstance(algorithm.toString());
mac.init(new SecretKeySpec(key, algorithm.toString()));
return mac.doFinal(data);
} catch (InvalidKeyException e) {
log.error("The SecretKey is invalid. msg:{}", e.getMessage());
throw new IllegalArgumentException("The SecretKey is invalid.", e);
} catch (Exception e) {
log.error("Unable to calculate a request signature: " + e.getMessage(), e);
throw new IllegalStateException("Unable to calculate a request signature: "
+ e.getMessage(), e);
}
}
/***
* StringToSign = Algorithm + '\n' + RequestDate + '\n'
* Hash(CanonicalRequest))
*
* @param request
* @return
*/
private static String createStringToSign(RequestMessage> request,
String canonicalRequest) {
StringBuilder str = new StringBuilder();
str.append(KWS_SIGNING_ALGORITHM);
str.append(LINE_SEPARATOR);
String date = request.getHeaders().get(HttpHeaders.REQUEST_DATE);
str.append(date);
str.append(LINE_SEPARATOR);
str.append(hash(canonicalRequest));
return str.toString();
}
private static byte[] deriveSigningKey(RequestMessage> request) {
return request.getCredentials().getSecretKey()
.getBytes(Charset.forName("UTF-8"));
}
/***
* CanonicalRequest = HTTPRequestMethod + '\n' + CanonicalURI + '\n' +
* CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders +
* '\n' + Base64Encode(Hash(RequestBody))
*
* @param request
* @return
*/
private static String createCanonicalRequest(RequestMessage> request) {
StringBuilder canonicalRequest = new StringBuilder();
// HTTPRequestMethod
canonicalRequest.append(request.getHttpMethod());
canonicalRequest.append(LINE_SEPARATOR);
// CanonicalURI
canonicalRequest.append("");
canonicalRequest.append(LINE_SEPARATOR);
// CanonicalQueryString
canonicalRequest.append("");
canonicalRequest.append(LINE_SEPARATOR);
// CanonicalHeaders
canonicalRequest.append(getCanonicalizedHeaderString(request));
canonicalRequest.append(LINE_SEPARATOR);
// SignedHeaders
canonicalRequest.append(getSignedHeadersString(request));
canonicalRequest.append(LINE_SEPARATOR);
// Base64(Hash(RequestPayload))
// canonicalRequest.append(calculateContentHash(request));
return canonicalRequest.toString();
}
protected static String calculateContentHash(RequestMessage> request) {
/*
* byte[] data; if (request.getContent() != null) { data = new
* ByteArrayInputStream(request.getContent()). } else { data = new byte[0];
* }
*
* return hash(data);
*/
return "";
}
private static String hash(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] sha = md.digest(data);
return StringUtils.base64Encode(sha);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
private static String hash(String data) {
try {
return hash(data.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
return null;
}
}
protected static String getCanonicalizedHeaderString(RequestMessage> request) {
final List sortedHeaders = new ArrayList(request
.getHeaders().keySet());
Collections.sort(sortedHeaders, String.CASE_INSENSITIVE_ORDER);
final Map requestHeaders = request.getHeaders();
StringBuilder buffer = new StringBuilder();
for (String header : sortedHeaders) {
if (header == HttpHeaders.HOST) {
continue;
}
String key = header.replaceAll("\\s+", " ");
String value = requestHeaders.get(header);
buffer.append(key).append(":");
if (value != null) {
buffer.append(value.replaceAll("\\s+", " "));
}
buffer.append("\n");
}
return buffer.toString();
}
protected static String getSignedHeadersString(RequestMessage> request) {
final List sortedHeaders = new ArrayList(request
.getHeaders().keySet());
Collections.sort(sortedHeaders, String.CASE_INSENSITIVE_ORDER);
StringBuilder buffer = new StringBuilder();
for (String header : sortedHeaders) {
if (header == HttpHeaders.HOST) {
continue;
}
if (buffer.length() > 0)
buffer.append(";");
buffer.append(header);
}
return buffer.toString();
}
public enum SigningAlgorithm {
HmacSHA256;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy