refactor SignatureUtils and related usage (#10291)

This commit is contained in:
cheese8 2022-07-11 09:45:26 +08:00 committed by GitHub
parent 92bf15dee2
commit dea2498718
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 97 deletions

View File

@ -38,12 +38,11 @@ public class AccessKeyAuthenticator implements Authenticator {
@Override
public void sign(Invocation invocation, URL url) {
String currentTime = String.valueOf(System.currentTimeMillis());
String consumer = url.getApplication();
AccessKeyPair accessKeyPair = getAccessKeyPair(invocation, url);
invocation.setAttachment(Constants.REQUEST_SIGNATURE_KEY, getSignature(url, invocation, accessKeyPair.getSecretKey(), currentTime));
invocation.setAttachment(Constants.REQUEST_TIMESTAMP_KEY, currentTime);
invocation.setAttachment(Constants.AK_KEY, accessKeyPair.getAccessKey());
invocation.setAttachment(CommonConstants.CONSUMER, consumer);
invocation.setAttachment(CommonConstants.CONSUMER, url.getApplication());
}
@Override
@ -52,12 +51,11 @@ public class AccessKeyAuthenticator implements Authenticator {
String requestTimestamp = String.valueOf(invocation.getAttachment(Constants.REQUEST_TIMESTAMP_KEY));
String originSignature = String.valueOf(invocation.getAttachment(Constants.REQUEST_SIGNATURE_KEY));
String consumer = String.valueOf(invocation.getAttachment(CommonConstants.CONSUMER));
if (StringUtils.isEmpty(accessKeyId) || StringUtils.isEmpty(consumer)
|| StringUtils.isEmpty(requestTimestamp) || StringUtils.isEmpty(originSignature)) {
throw new RpcAuthenticationException("Failed to authenticate, maybe consumer not enable the auth");
if (StringUtils.isAnyEmpty(accessKeyId, consumer, requestTimestamp, originSignature)) {
throw new RpcAuthenticationException("Failed to authenticate, maybe consumer side did not enable the auth");
}
AccessKeyPair accessKeyPair = null;
AccessKeyPair accessKeyPair;
try {
accessKeyPair = getAccessKeyPair(invocation, url);
} catch (Exception e) {
@ -75,10 +73,10 @@ public class AccessKeyAuthenticator implements Authenticator {
AccessKeyStorage accessKeyStorage = applicationModel.getExtensionLoader(AccessKeyStorage.class)
.getExtension(url.getParameter(Constants.ACCESS_KEY_STORAGE_KEY, Constants.DEFAULT_ACCESS_KEY_STORAGE));
AccessKeyPair accessKeyPair = null;
AccessKeyPair accessKeyPair;
try {
accessKeyPair = accessKeyStorage.getAccessKey(url, invocation);
if (accessKeyPair == null || StringUtils.isEmpty(accessKeyPair.getAccessKey()) || StringUtils.isEmpty(accessKeyPair.getSecretKey())) {
if (accessKeyPair == null || StringUtils.isAnyEmpty(accessKeyPair.getAccessKey(), accessKeyPair.getSecretKey())) {
throw new AccessKeyNotFoundException("AccessKeyId or secretAccessKey not found");
}
} catch (Exception e) {
@ -88,16 +86,11 @@ public class AccessKeyAuthenticator implements Authenticator {
}
String getSignature(URL url, Invocation invocation, String secretKey, String time) {
String requestString = String.format(Constants.SIGNATURE_STRING_FORMAT, url.getColonSeparatedKey(), invocation.getMethodName(), secretKey, time);
boolean parameterEncrypt = url.getParameter(Constants.PARAMETER_SIGNATURE_ENABLE_KEY, false);
String signature;
String requestString = String.format(Constants.SIGNATURE_STRING_FORMAT,
url.getColonSeparatedKey(), invocation.getMethodName(), secretKey, time);
if (parameterEncrypt) {
signature = SignatureUtils.sign(invocation.getArguments(), requestString, secretKey);
} else {
signature = SignatureUtils.sign(requestString, secretKey);
return SignatureUtils.sign(invocation.getArguments(), requestString, secretKey);
}
return signature;
return SignatureUtils.sign(requestString, secretKey);
}
}

View File

@ -23,75 +23,68 @@ import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.SignatureException;
import java.util.Arrays;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class SignatureUtils {
private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
public static String sign(String metadata, String key) throws SecurityException {
try {
return sign(metadata.getBytes(), key);
} catch (Exception e) {
throw new SecurityException("Failed to generate HMAC : " + e.getMessage(), e);
}
public static String sign(String metadata, String key) throws RuntimeException {
return sign(metadata.getBytes(StandardCharsets.UTF_8), key);
}
public static String sign(Object[] parameters, String metadata, String key) {
try {
if (parameters == null) {
return sign(metadata, key);
}
boolean notSerializable = Arrays.stream(parameters).anyMatch(parameter -> !(parameter instanceof Serializable));
if (notSerializable) {
throw new IllegalArgumentException("");
}
Object[] includeMetadata = new Object[parameters.length + 1];
System.arraycopy(parameters, 0, includeMetadata, 0, parameters.length);
includeMetadata[parameters.length] = metadata;
byte[] bytes = toByteArray(includeMetadata);
return sign(bytes, key);
} catch (Exception e) {
throw new SecurityException("Failed to generate HMAC : " + e.getMessage(), e);
public static String sign(Object[] parameters, String metadata, String key) throws RuntimeException {
if (parameters == null) {
return sign(metadata, key);
}
for (int i = 0; i < parameters.length; i++) {
if (!(parameters[i] instanceof Serializable)) {
throw new IllegalArgumentException("The parameter [" + i + "] to be signed was not serializable.");
}
}
Object[] includeMetadata = new Object[parameters.length + 1];
System.arraycopy(parameters, 0, includeMetadata, 0, parameters.length);
includeMetadata[parameters.length] = metadata;
byte[] includeMetadataBytes;
try {
includeMetadataBytes = toByteArray(includeMetadata);
} catch (IOException e) {
throw new RuntimeException("Failed to generate HMAC: " + e.getMessage());
}
return sign(includeMetadataBytes, key);
}
public static String sign(byte[] data, String key) throws SignatureException {
String result;
private static String sign(byte[] data, String key) throws RuntimeException {
Mac mac;
try {
mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
} catch(NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to generate HMAC: no such algorithm exception " + HMAC_SHA256_ALGORITHM);
}
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA256_ALGORITHM);
try {
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(),
HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data);
// base64-encode the hmac
result = Base64.getEncoder().encodeToString(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : "
+ e.getMessage());
} catch(InvalidKeyException e) {
throw new RuntimeException("Failed to generate HMAC: invalid key exception");
}
return result;
byte[] rawHmac;
try{
// compute the hmac on input data bytes
rawHmac = mac.doFinal(data);
} catch (IllegalStateException e) {
throw new RuntimeException("Failed to generate HMAC: " + e.getMessage());
}
// base64-encode the hmac
return Base64.getEncoder().encodeToString(rawHmac);
}
static byte[] toByteArray(Object[] parameters) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
try {
out = new ObjectOutputStream(bos);
private static byte[] toByteArray(Object[] parameters) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)) {
out.writeObject(parameters);
out.flush();
return bos.toByteArray();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
}
}

View File

@ -133,6 +133,5 @@ class AccessKeyAuthenticatorTest {
when(invocation.getArguments()).thenReturn(fakeParams);
String signature1 = helper.getSignature(url, invocation, secretKey, String.valueOf(System.currentTimeMillis()));
assertNotEquals(signature, signature1);
}
}

View File

@ -16,43 +16,23 @@
*/
package org.apache.dubbo.auth.utils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
public class SignatureUtilsTest {
private Object[] objects = new Object[2];
private List<String> list = new ArrayList<>();
private String temp = "temp";
private String key = "TOKEN";
{
objects[0] = list;
objects[1] = temp;
}
@Test
void testObjectToByteArray() {
try {
byte[] bytes = SignatureUtils.toByteArray(objects);
Assertions.assertNotEquals(0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
void testEncryptWithObject() {
Object[] objects = new Object[] {new ArrayList<>(), "temp"};
String encryptWithObject = SignatureUtils.sign(objects, "TestMethod#hello", "TOKEN");
Assertions.assertEquals(encryptWithObject, "t6c7PasKguovqSrVRcTQU4wTZt/ybl0jBCUMgAt/zQw=");
}
@Test
void testEncryptObject() {
String encrypt = SignatureUtils.sign(objects, "TestMethod#hello", key);
String encryptNoParams = SignatureUtils.sign(null, "TestMethod#hello", key);
Assertions.assertNotNull(encrypt);
Assertions.assertNotNull(encryptNoParams);
Assertions.assertNotEquals(encrypt, encryptNoParams);
void testEncryptWithNoParameters() {
String encryptWithNoParams = SignatureUtils.sign(null, "TestMethod#hello", "TOKEN");
Assertions.assertEquals(encryptWithNoParams, "2DGkTcyXg4plU24rY8MZkEJwOMRW3o+wUP3HssRc3EE=");
}
}