com.volcengine.auth.impl.SignerV4Impl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of volc-sdk-java Show documentation
Show all versions of volc-sdk-java Show documentation
The VOLC Engine SDK for Java
package com.volcengine.auth.impl;
import com.volcengine.auth.ISignerV4;
import com.volcengine.auth.MetaData;
import com.volcengine.helper.Const;
import com.volcengine.helper.Utils;
import com.volcengine.model.Credentials;
import com.volcengine.model.RequestParam;
import com.volcengine.model.SignRequest;
import com.volcengine.service.SignableRequest;
import com.volcengine.util.NameValueComparator;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class SignerV4Impl implements ISignerV4 {
private static final TimeZone tz = TimeZone.getTimeZone("UTC");
private static final Set H_INCLUDE = new HashSet();
private static final BitSet URLENCODER = new BitSet(256);
private static final String CONST_ENCODE = "0123456789ABCDEF";
static {
H_INCLUDE.add(Const.ContentType);
H_INCLUDE.add(Const.ContentMd5);
H_INCLUDE.add(Const.Host);
int i;
for (i = 97; i <= 122; ++i) {
URLENCODER.set(i);
}
for (i = 65; i <= 90; ++i) {
URLENCODER.set(i);
}
for (i = 48; i <= 57; ++i) {
URLENCODER.set(i);
}
URLENCODER.set('-');
URLENCODER.set('_');
URLENCODER.set('.');
URLENCODER.set('~');
}
@Override
public void sign(SignableRequest request, Credentials credentials) throws Exception {
URIBuilder builder = request.getUriBuilder();
if (StringUtils.isEmpty(builder.getPath())) {
builder.setPath(builder.getPath() + "/");
}
if (request.getFirstHeader(Const.ContentType) == null) {
request.setHeader(Const.ContentType, Const.ContentTypeValue);
}
RequestParam requestParam = RequestParam.builder().isSignUrl(false)
.body(getBodyByEntity(request.getEntity()))
.host(request.getUriBuilder().getHost())
.path(builder.getPath()).method(request.getMethod()).date(new Date())
.queryList(request.getUriBuilder().getQueryParams())
.headers(request.getAllHeaders())
.build();
SignRequest signRequest = getSignRequest(requestParam, credentials);
request.setHeader(Const.Host, signRequest.getHost());
request.setHeader(Const.ContentType, signRequest.getContentType());
request.setHeader(Const.XDate, signRequest.getXDate());
request.setHeader(Const.XContentSha256, signRequest.getXContentSha256());
request.setHeader(Const.Authorization, signRequest.getAuthorization());
if (StringUtils.isNotEmpty(signRequest.getXSecurityToken())) {
request.setHeader(Const.XSecurityToken, signRequest.getXSecurityToken());
}
request.setURI(request.getUriBuilder().build());
}
private byte[] getBodyByEntity(HttpEntity httpEntity) throws IOException {
if (httpEntity == null){
return new byte[0];
}
if( httpEntity.getContentLength()>25*1024){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
httpEntity.writeTo(byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
return EntityUtils.toByteArray(httpEntity);
}
@Override
public String signUrl(SignableRequest request, Credentials credentials) throws Exception {
URIBuilder uriBuilder = request.getUriBuilder();
RequestParam requestParam = RequestParam.builder().isSignUrl(true)
.body(request.getEntity() == null ? new byte[0] : EntityUtils.toByteArray(request.getEntity()))
.host(uriBuilder.getHost())
.path(uriBuilder.getPath()).method(request.getMethod()).date(new Date())
.queryList(request.getUriBuilder().getQueryParams())
.build();
SignRequest signRequest = getSignRequest(requestParam, credentials);
uriBuilder.setParameter(Const.XDate, signRequest.getXDate());
uriBuilder.setParameter(Const.XNotSignBody, signRequest.getXNotSignBody());
uriBuilder.setParameter(Const.XCredential, signRequest.getXCredential());
uriBuilder.setParameter(Const.XAlgorithm, signRequest.getXAlgorithm());
uriBuilder.setParameter(Const.XSignedHeaders, signRequest.getXSignedHeaders());
uriBuilder.setParameter(Const.XSignedQueries, signRequest.getXSignedQueries());
uriBuilder.setParameter(Const.XSignature, signRequest.getXSignature());
if (StringUtils.isNotEmpty(signRequest.getXSecurityToken())) {
uriBuilder.setParameter(Const.XSecurityToken, signRequest.getXSecurityToken());
}
return uriBuilder.build().toURL().getQuery();
}
@Override
public SignRequest getSignRequest(RequestParam requestParam, Credentials credentials) throws Exception {
if (requestParam == null || credentials == null) {
throw new Exception("requestParam and credentials is null");
}
if (requestParam.getIsSignUrl() == null || requestParam.getDate() == null || requestParam.getQueryList() == null) {
throw new Exception("requestParam's isSignUrl or date or queryList is null");
}
String formatDate = getAppointFormatDate(requestParam.getDate());
MetaData meta = getMetaDate(credentials, toDate(formatDate));
Map requestSignMap = new HashMap<>();
String bodyHash;
SignRequest signRequest = SignRequest.builder().xDate(formatDate).xSecurityToken(credentials.getSessionToken()).build();
if (StringUtils.isNotEmpty(credentials.getSessionToken())) {
requestSignMap.put(Const.XSecurityToken, credentials.getSessionToken());
}
if (requestParam.getIsSignUrl()) {
requestParam.getQueryList().forEach(nv -> requestSignMap.put(nv.getName(), nv.getValue()));
requestSignMap.put(Const.XDate, formatDate);
requestSignMap.put(Const.XNotSignBody, "");
requestSignMap.put(Const.XCredential, credentials.getAccessKeyID() + "/" + meta.getCredentialScope());
requestSignMap.put(Const.XAlgorithm, meta.getAlgorithm());
requestSignMap.put(Const.XSignedHeaders, meta.getSignedHeaders());
requestSignMap.put(Const.XSignedQueries, "");
List keys = new ArrayList<>(requestSignMap.keySet());
Collections.sort(keys);
requestSignMap.put(Const.XSignedQueries, StringUtils.join(keys, ";"));
signRequest.setXNotSignBody("");
signRequest.setXCredential(credentials.getAccessKeyID() + "/" + meta.getCredentialScope());
signRequest.setXAlgorithm(meta.getAlgorithm());
signRequest.setXSignedHeaders(meta.getSignedHeaders());
signRequest.setXSignedQueries(StringUtils.join(keys, ";"));
bodyHash = Utils.hashSHA256(new byte[0]);
} else {
for (Header header : requestParam.getHeaders()) {
if (header.getName().equalsIgnoreCase(Const.ContentType)) {
signRequest.setContentType(header.getValue());
}
requestSignMap.put(header.getName(), header.getValue());
}
requestSignMap.put(Const.XDate, formatDate);
requestSignMap.put(Const.Host, requestParam.getHost());
bodyHash = Utils.hashSHA256(requestParam.getBody() == null ? new byte[0] : requestParam.getBody());
requestSignMap.put(Const.XContentSha256, bodyHash);
signRequest.setHost(requestParam.getHost());
signRequest.setXContentSha256(bodyHash);
}
String signature = getSignatureStr(requestParam, meta, credentials.getSecretAccessKey(),
formatDate, requestSignMap, bodyHash);
if (requestParam.getIsSignUrl()) {
signRequest.setXSignature(signature);
} else {
signRequest.setAuthorization(buildAuthHeaderV4(signature, meta, credentials));
}
return signRequest;
}
private String getSignatureStr(RequestParam requestParam, MetaData meta, String secreteAccessKey,
String formatDate, Map requestSignMap, String bodyHash) throws Exception {
//step1
String hashedCanonReq = hashedCanonicalRequestV4(requestParam, meta, requestSignMap, bodyHash);
// step 2
String stringToSign = StringUtils.join(new String[]{meta.getAlgorithm(), formatDate, meta.getCredentialScope(), hashedCanonReq}, "\n");
// step 3
byte[] signingKey = genSigningSecretKeyV4(secreteAccessKey, meta.getDate(), meta.getRegion(), meta.getService());
return signatureV4(signingKey, stringToSign);
}
private MetaData getMetaDate(Credentials credentials, String date) {
MetaData meta = new MetaData();
meta.setDate(date);
meta.setService(credentials.getService());
meta.setRegion(credentials.getRegion());
meta.setAlgorithm("HMAC-SHA256");
meta.setSignedHeaders("");
meta.setCredentialScope(StringUtils.join(new String[]{meta.getDate(), meta.getRegion(), meta.getService(), "request"}, "/"));
return meta;
}
private String hashedCanonicalRequestV4(RequestParam requestParam, MetaData meta,
Map requestSignMap, String bodyHash) throws Exception {
List queryList = new ArrayList<>();
String canonicalRequest;
if (requestParam.getIsSignUrl()) {
for (String key : requestSignMap.keySet()) {
queryList.add(new BasicNameValuePair(key, requestSignMap.get(key)));
}
canonicalRequest = StringUtils.join(new String[]{requestParam.getMethod(), this.normUri(requestParam.getPath()),
this.normQuery(queryList), "\n", meta.getSignedHeaders(), bodyHash}, "\n");
} else {
String canonicalHeaders = getCanonicalHeaders(requestParam, meta, requestSignMap);
canonicalRequest = StringUtils.join(new String[]{requestParam.getMethod(), normUri(requestParam.getPath()),
normQuery(requestParam.getQueryList()), canonicalHeaders, meta.getSignedHeaders(), bodyHash}, "\n");
}
return Utils.hashSHA256(canonicalRequest.getBytes());
}
private String getCanonicalHeaders(RequestParam requestParam, MetaData meta, Map requestSignMap) {
Map signMap = new HashMap<>();
List signedHeaders = sortHeaders(requestSignMap, signMap);
if (!requestParam.getIsSignUrl()) {
meta.setSignedHeaders(StringUtils.join(signedHeaders, ";"));
}
if (StringUtils.isEmpty(requestParam.getPath())) {
requestParam.setPath("/");
}
StringBuilder signedHeadersToSignStr = new StringBuilder();
for (String h : signedHeaders) {
String value = signMap.get(h).trim();
if (h.equals("host")) {
if (value.contains(":")) {
String[] split = value.split(":");
String port = split[1];
if (port.equals("80") || port.equals("443")) {
value = split[0];
}
}
}
signedHeadersToSignStr.append(h).append(":").append(value).append("\n");
}
return signedHeadersToSignStr.toString();
}
private List sortHeaders(Map requestSignMap, Map signMap) {
List signedHeaders = new ArrayList<>();
for (Map.Entry entry : requestSignMap.entrySet()) {
signMap.put(entry.getKey().toLowerCase(), entry.getValue());
if (H_INCLUDE.contains(entry.getKey()) || entry.getKey().startsWith("X-")) {
signedHeaders.add(entry.getKey().toLowerCase());
}
}
Collections.sort(signedHeaders);
return signedHeaders;
}
private String signatureV4(byte[] signingKey, String stringToSign) throws Exception {
return Hex.encodeHexString(Utils.hmacSHA256(signingKey, stringToSign));
}
private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
byte[] kDate = Utils.hmacSHA256((secretKey).getBytes(), date);
byte[] kRegion = Utils.hmacSHA256(kDate, region);
byte[] kService = Utils.hmacSHA256(kRegion, service);
return Utils.hmacSHA256(kService, "request");
}
private String buildAuthHeaderV4(String signature, MetaData meta, Credentials credentials) {
String credential = credentials.getAccessKeyID() + "/" + meta.getCredentialScope();
return meta.getAlgorithm() +
" Credential=" + credential +
", SignedHeaders=" + meta.getSignedHeaders() +
", Signature=" + signature;
}
private String getCurrentFormatDate() {
DateFormat df = new SimpleDateFormat(Const.TIME_FORMAT_V4);
df.setTimeZone(tz);
return df.format(new Date());
}
private String getAppointFormatDate(Date date) {
DateFormat df = new SimpleDateFormat(Const.TIME_FORMAT_V4);
df.setTimeZone(tz);
return df.format(date);
}
private String toDate(String timestamp) {
return timestamp.substring(0, 8);
}
private String normUri(String path) {
String[] parts = path.split("/", -1);
for (int i = 0; i < parts.length; i++) {
parts[i] = signStringEncoder(parts[i]);
}
return StringUtils.join(parts, "/");
}
/**
* 与golang的标准对齐
*
* @param params query kv pair
* @return query
*/
private String normQuery(List params) {
params.sort(NameValueComparator.INSTANCE);
return signQueryEncoder(params);
}
/**
* 与golang的标准对齐,
*
* @param params kv pair
* @return query string
*/
private String signQueryEncoder(List params) {
StringBuilder result = new StringBuilder();
for (NameValuePair pair : params) {
String encodedName = signStringEncoder(pair.getName());
String encodedValue = signStringEncoder(pair.getValue());
if (result.length() > 0) {
result.append("&");
}
result.append(encodedName).append("=");
if (encodedValue != null) {
result.append(encodedValue);
}
}
return result.toString();
}
/**
* 与golang的标准对齐,URLENCODER中的字符不转换,空格转换为%20(仅签名使用)
*
* @param source 原文
* @return 转换后的编码字符串
*/
private String signStringEncoder(String source) {
if (source == null) {
return null;
}
StringBuilder buf = new StringBuilder(source.length());
ByteBuffer bb = Consts.UTF_8.encode(source);
while (bb.hasRemaining()) {
int b = bb.get() & 255;
if (URLENCODER.get(b)) {
buf.append((char) b);
} else if (b == 32) {
buf.append("%20");
} else {
buf.append("%");
char hex1 = CONST_ENCODE.charAt(b >> 4);
char hex2 = CONST_ENCODE.charAt(b & 15);
buf.append(hex1);
buf.append(hex2);
}
}
return buf.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy