Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.huawei.openstack4j.openstack.identity.signer.AKSK Maven / Gradle / Ivy
package com.huawei.openstack4j.openstack.identity.signer;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SimpleTimeZone;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.huawei.openstack4j.core.transport.HttpRequest;
import com.huawei.openstack4j.core.transport.ObjectMapperSingleton;
import com.huawei.openstack4j.utils.BinaryUtils;
/**
*
* @author QianBiao.NG
* @date 2018-03-13 16:55:38
*/
public class AKSK {
public static class Constants {
public static final String LINE_SEPARATOR = "\n";
public static final String SDK_NAME = "SDK";
public static final String SDK_TERMINATOR = "sdk_request";
public static final String SDK_SIGNING_ALGORITHM = "SDK-HMAC-SHA256";
public static final String X_SDK_DATE = "X-Sdk-Date";
public static final String X_SDK_CONTENT_SHA256 = "x-sdk-content-sha256";
public static final String AUTHORIZATION = "Authorization";
public static final String HOST = "Host";
public static final String CONTENT_TYPE = "Content-Type";
public static final String CONTENT_LENGTH = "Content-Length";
// sorted to be signed headers
public static final List TO_SIGNED_HEADERS = Lists.newArrayList(HOST, X_SDK_DATE);
}
@Getter
@Setter
@Builder
public static class Credential {
String ak;
String sk;
}
// /** SHA256 hash of an empty request body **/
public static final String EMPTY_BODY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
/** format strings for the date/time and date stamps required during signing **/
public static final String ISO8601BasicFormat = "yyyyMMdd'T'HHmmss'Z'";
public static final String DateStringFormat = "yyyyMMdd";
protected static final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(ISO8601BasicFormat);
protected static final SimpleDateFormat dateStampFormat = new SimpleDateFormat(DateStringFormat);
static {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
public static HashMap sign(HttpRequest request, Credential credential) {
// Date now = dateTimeFormat.parse("20180314T080059Z"); // 设置基准时间
Date now = new Date(); // 设置基准时间
HashMap authenticationHeaders = new HashMap<>();
// Step 1: add basic headers required by V4
// Step 1.1: Add Host header
String endpoint = request.getEndpoint();
String requestPath = request.getPath();
URL url = convertToURL(endpoint, requestPath);
String host = buildCanonicalHost(url);
authenticationHeaders.put(Constants.HOST, host);
// Step 1.2: add X-Sdk-Date
dateTimeFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));
dateStampFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));
String dateTimeStamp = dateTimeFormat.format(now);
String datestamp = dateStampFormat.format(now);
authenticationHeaders.put(Constants.X_SDK_DATE, dateTimeStamp);
// Step 2: Create canonical URI--the part of the URI from domain to query
String pathOld = url.getPath();
String path ="";
String[] split = pathOld.split("/");
for(String urlSplit : split){
path += "/" + urlEncode(urlSplit);
}
if(path.length() > 0){
path = path.substring(1, path.length());
}
String canonicalURI = path.endsWith("/") ? path : path + "/";
// Step 3: Create the canonical query string. In this example (a GET request),
// request parameters are in the query string. Query string values must
// be URL-encoded (space=%20). The parameters must be sorted by name.
// For this example, the query string is pre-formatted in the request_parameters variable.
String query = url.getQuery();
Map> parameters = request.getQueryParams();
String canonicalQueryString = buildCanonicalQueryString(query, parameters);
// Step 4: Create the list of signed headers. This lists the headers
// in the canonical_headers list, delimited with ";" and in alpha order.
// Note: The request can include any headers; canonical_headers and
// signed_headers lists those that you want to be included in the
// hash of the request. "Host" and "x-sdk-date" are always required.
// In V4 signer, we only use required header - host & x-sdk-date.
String signedHeaderNames = Joiner.on(";").join(Constants.TO_SIGNED_HEADERS).toLowerCase();
// Step 5: Create the canonical headers and signed headers. Header names
// and value must be trimmed and lower-case, and sorted in ASCII order.
// Note that there is a trailing \n.
String canonicalHeaders = buildCanonicalHeaders(authenticationHeaders);
// Step 6: Create payload hash (hash of the request body content). For GET
// requests, the payload is an empty string ("").
String payloadHash = buildPayloadHash(request);
// Step 7: Combine elements to create canonical request
String canonicalRequest = buildCanonicalRequest(request.getMethod().name(), canonicalURI, canonicalQueryString,
canonicalHeaders, signedHeaderNames, payloadHash);
String canonicalRequestHash = BinaryUtils.toHex(sha256(canonicalRequest));
// ************* TASK 2: CREATE THE STRING TO SIGN*************
// Match the algorithm to the hashing algorithm you use, either SHA-1 or SHA-256 (recommended)
String[] scopeArray = new String[] { datestamp, request.getRegion(), request.getService().getServiceName(),
Constants.SDK_TERMINATOR };
String credentialScope = Joiner.on("/").join(scopeArray);
String stringToSign = getStringToSign(Constants.SDK_SIGNING_ALGORITHM, dateTimeStamp, credentialScope,
canonicalRequestHash);
// ************* TASK 3: CALCULATE THE SIGNATURE *************
// Create the signing key using the function defined above.
String signatureString = signature(request.getService().getServiceName(), datestamp, request.getRegion(),
stringToSign, credential.getSk());
// ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
// The signing information can be either in a query string value or in
// a header named Authorization. This code shows how to use a header.
// Create authorization header and add to request headers
StringBuilder authorization = new StringBuilder(Constants.SDK_SIGNING_ALGORITHM).append(" ");
authorization.append("Credential=").append(credential.getAk()).append("/").append(credentialScope).append(", ");
authorization.append("SignedHeaders=").append(signedHeaderNames).append(", ");
authorization.append("Signature=").append(signatureString);
authenticationHeaders.put(Constants.AUTHORIZATION, authorization.toString());
return authenticationHeaders;
}
/**
* @param request
* @return
*/
public static String buildPayloadHash(HttpRequest request) {
if (!Strings.isNullOrEmpty(request.getJson())) {
return BinaryUtils.toHex(sha256(request.getJson()));
}
try {
if (request.getEntity() != null) {
Object entity = request.getEntity();
String payload = ObjectMapperSingleton.getContext(entity.getClass()).writeValueAsString(entity);
return BinaryUtils.toHex(sha256(payload));
}
} catch (JsonProcessingException e) {
// should not happen
throw new RuntimeException("Could not serialize entity", e);
}
return EMPTY_BODY_SHA256;
}
/**
* @param endpoint
* @param requestPath
* @return
* @throws MalformedURLException
*/
public static URL convertToURL(String endpoint, String requestPath) {
try {
return new URL(endpoint + requestPath);
} catch (MalformedURLException e) {
throw new RuntimeException("Endpoint illegal", e);
}
}
/**
* @param request
* @param datestamp
* @param session
* @param stringToSign
* @return
* @throws UnsupportedEncodingException
*/
public static String signature(String serviceName, String datestamp, String region, String stringToSign,
String secretKey) {
try {
byte[] keySecret = (Constants.SDK_NAME + secretKey).getBytes("UTF-8");
byte[] kDate = hmac(keySecret, datestamp);
byte[] kRegion = hmac(kDate, region);
byte[] kService = hmac(kRegion, serviceName);
byte[] kSigning = hmac(kService, Constants.SDK_TERMINATOR);
byte[] signature = hmac(kSigning, stringToSign);
return BinaryUtils.toHex(signature);
} catch (UnsupportedEncodingException e) {
// should not happen
throw new RuntimeException(e);
}
}
/**
* @param sdkSigningAlgorithm
* @param dateTimeStamp
* @param credentialScope
* @param canonicalRequestHash
* @return
*/
private static String getStringToSign(String... segments) {
return Joiner.on(Constants.LINE_SEPARATOR).join(segments);
}
/**
* @param method
* @param canonicalURI
* @param canonicalQueryString
* @param canonicalHeaders
* @param signedHeaderNames
* @param payloadHash
* @return
*/
private static String buildCanonicalRequest(String... segments) {
return Joiner.on(Constants.LINE_SEPARATOR).join(segments);
}
/**
* Create the canonical headers and signed headers. Header names
* and value must be trimmed and lowercase, and sorted in ASCII order.
* Note that there is a trailing \n.
*
* @param authenticationHeaders
* @return
*/
private static String buildCanonicalHeaders(HashMap authenticationHeaders) {
StringBuilder sb = new StringBuilder();
for (String sortedKey : Constants.TO_SIGNED_HEADERS) {
sb.append(sortedKey.toLowerCase()).append(":").append(authenticationHeaders.get(sortedKey));
sb.append(Constants.LINE_SEPARATOR);
}
return sb.toString();
}
/**
* @param url
* @return
*/
public static String buildCanonicalHost(URL url) {
String host = url.getHost();
int port = url.getPort();
if (port > -1) {
host.concat(":" + Integer.toString(port));
}
return host;
}
public static String buildCanonicalQueryString(String query, Map> parameters) {
SortedMap sorted = new TreeMap();
// get parameters from path query string
if (query != null && !query.isEmpty()) {
String[] splitted = query.split("&");
for (String split : splitted) {
String[] kv = split.split("=");
if (kv.length == 2) {
sorted.put(urlEncode(kv[0]), urlEncode(kv[1]));
}
}
}
if (parameters != null && !parameters.isEmpty()) {
Iterator>> iterator = parameters.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry> pair = iterator.next();
String key = pair.getKey();
List values = pair.getValue();
for (Object value : values) {
String valueString = value.toString();
if("tags".equals(key)||"metadata".equals(key)){
if(valueString.contains("%7B")||valueString.contains("%7D")||valueString.contains("%7b")||valueString.contains("%7d")){
valueString = valueString.replace("%7B","{").replace("%7b","{")
.replace("%7D","}").replace("%7d","}");
}
}
sorted.put(urlEncode(key), urlEncode(valueString));
}
}
}
StringBuilder builder = new StringBuilder();
Iterator> itr = sorted.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry pair = itr.next();
builder.append(pair.getKey());
builder.append("=");
builder.append(pair.getValue());
if (itr.hasNext()) {
builder.append("&");
}
}
return builder.toString();
}
public static String urlEncode(String url) {
try {
return URLEncoder.encode(url, "UTF-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 encoding is not supported.", e);
}
}
/**
* Hashes the string contents (assumed to be UTF-8) using the SHA-256
* algorithm.
*/
public static byte[] sha256(String text) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(text.getBytes("UTF-8"));
return md.digest();
} catch (Exception e) {
throw new RuntimeException("Unable to compute hash while signing request: " + e.getMessage(), e);
}
}
/**
* Hashes the byte array using the SHA-256 algorithm.
*/
public static byte[] sha256(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data);
return md.digest();
} catch (Exception e) {
throw new RuntimeException("Unable to compute hash while signing request: " + e.getMessage(), e);
}
}
protected static byte[] hmac(byte[] key, String data) {
try {
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
hmac.init(secretKeySpec);
return hmac.doFinal(data.getBytes("UTF-8"));
} catch (Exception e) {
throw new RuntimeException("Unable to calculate a request signature: " + e.getMessage(), e);
}
}
protected static byte[] sign(String stringData, byte[] key, String algorithm) {
try {
byte[] data = stringData.getBytes("UTF-8");
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data);
} catch (Exception e) {
throw new RuntimeException("Unable to calculate a request signature: " + e.getMessage(), e);
}
}
public static void main(String[] args) {
System.out.println(BinaryUtils.toHex(sha256("")));
}
}