Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
|
7a26e3940e | |
|
3ba4dc8e91 | |
|
098c9c5a46 | |
|
44020825d6 | |
|
889d67b5b5 | |
|
c0e45f3726 | |
|
4206675483 | |
|
6de7979789 | |
|
e3c9eb6025 | |
|
4bb8ca31d7 |
89
pom.xml
89
pom.xml
|
@ -12,12 +12,12 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<inceptionYear>2018</inceptionYear>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client-mse-extension</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<version>1.0.6</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<developers>
|
||||
|
@ -30,6 +30,15 @@
|
|||
<role>Developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>robynron</id>
|
||||
<name>Rong Liu</name>
|
||||
<email>liurong.liu@alibaba-inc.com</email>
|
||||
<url>https://github.com/robynron</url>
|
||||
<roles>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<licenses>
|
||||
<license>
|
||||
|
@ -42,31 +51,32 @@
|
|||
<name>Aliyun NACOS extension for MSE</name>
|
||||
<description>Aliyun NACOS extension for MSE</description>
|
||||
<url>http://nacos.io</url>
|
||||
|
||||
|
||||
<scm>
|
||||
<url>git@github.com:nacos-group/nacos-client-mse-extension.git</url>
|
||||
<connection>scm:git@github.com:nacos-group/nacos-client-mse-extension.git</connection>
|
||||
<developerConnection>scm:git@github.com:nacos-group/nacos-client-mse-extension.git</developerConnection>
|
||||
</scm>
|
||||
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<nacos.version>2.2.4</nacos.version>
|
||||
<nacos.version>2.4.0</nacos.version>
|
||||
<guava.version>30.1-jre</guava.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
<version>4.5.17</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-kms</artifactId>
|
||||
<version>2.16.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun.kms</groupId>
|
||||
<artifactId>kms-transfer-client</artifactId>
|
||||
|
@ -78,20 +88,45 @@
|
|||
</exclusions>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>credentials-java</artifactId>
|
||||
<version>0.3.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>alibabacloud-secretsmanager-client</artifactId>
|
||||
<version>1.3.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>kms20160120</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-api</artifactId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<groupId>commons-codec</groupId>
|
||||
<version>1.15</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- for test-->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
@ -99,15 +134,23 @@
|
|||
<version>RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-inline</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -119,8 +162,8 @@
|
|||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
|
@ -134,8 +177,8 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
|
@ -151,8 +194,8 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
|
|
|
@ -1,43 +1,22 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.config.filter.AbstractConfigFilter;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigRequest;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigResponse;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.aliyun.dkms.gcs.openapi.models.Config;
|
||||
import com.aliyun.kms.KmsTransferAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.auth.AlibabaCloudCredentialsProvider;
|
||||
import com.aliyuncs.auth.InstanceProfileCredentialsProvider;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.http.FormatType;
|
||||
import com.aliyuncs.http.HttpClientConfig;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.aliyuncs.http.ProtocolType;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.EncryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.SetDeletionProtectionRequest;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.aliyuncs.profile.IClientProfile;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CONTENT;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.DATA_ID;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.GROUP;
|
||||
|
||||
/**
|
||||
* the IConfigFilter of Aliyun.
|
||||
|
@ -47,254 +26,28 @@ import java.util.Set;
|
|||
public class AliyunConfigFilter extends AbstractConfigFilter {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AliyunConfigFilter.class);
|
||||
|
||||
private static final String GROUP = "group";
|
||||
|
||||
private static final String DATA_ID = "dataId";
|
||||
|
||||
private static final String CONTENT = "content";
|
||||
|
||||
private static final String REGION_ID = "regionId";
|
||||
|
||||
private static final String KMS_REGION_ID = "kms_region_id";
|
||||
|
||||
private static final String KEY_ID = "keyId";
|
||||
|
||||
private static final String ENCRYPTED_DATA_KEY = "encryptedDataKey";
|
||||
|
||||
private static final String CIPHER_PREFIX = "cipher-";
|
||||
|
||||
private static AliyunConst.KmsVersion kmsVersion;
|
||||
|
||||
public static final String CIPHER_KMS_AES_128_PREFIX = "cipher-kms-aes-128-";
|
||||
|
||||
public static final String CIPHER_KMS_AES_256_PREFIX = "cipher-kms-aes-256-";
|
||||
|
||||
public static final String KMS_KEY_SPEC_AES_128 = "AES_128";
|
||||
|
||||
public static final String KMS_KEY_SPEC_AES_256 = "AES_256";
|
||||
|
||||
private IAcsClient kmsClient;
|
||||
|
||||
private String keyId;
|
||||
|
||||
private final Set<String> addedKeys = new HashSet<String>();
|
||||
|
||||
private AsyncProcessor asyncProcessor;
|
||||
|
||||
private Exception localInitException;
|
||||
private KmsEncryptor kmsEncryptor;
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
LOGGER.info("init ConfigFilter: {}, for more information, please check: {}",
|
||||
this.getFilterName(), AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
// get kms version, default using kms v1
|
||||
String kv = properties.getProperty(AliyunConst.KMS_VERSION_KEY,
|
||||
System.getProperty(AliyunConst.KMS_VERSION_KEY, System.getenv(AliyunConst.KMS_VERSION_KEY)));
|
||||
if (StringUtils.isBlank(kv)) {
|
||||
LOGGER.warn("kms version is not set, using kms v1 version.");
|
||||
kmsVersion = AliyunConst.KmsVersion.Kmsv1;
|
||||
} else {
|
||||
kmsVersion = AliyunConst.KmsVersion.fromValue(kv);
|
||||
if (kmsVersion == AliyunConst.KmsVersion.UNKNOWN_VERSION) {
|
||||
LOGGER.warn("kms version is not supported, using kms v1 version.");
|
||||
kmsVersion = AliyunConst.KmsVersion.Kmsv1;
|
||||
} else {
|
||||
LOGGER.info("using kms version {}.", kmsVersion.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//keyId corresponding to the id/alias of KMS's secret key, using mseServiceKeyId by default
|
||||
keyId = properties.getProperty(KEY_ID, System.getProperty(KEY_ID, System.getenv(KEY_ID)));
|
||||
if (StringUtils.isBlank(keyId)) {
|
||||
if (kmsVersion == AliyunConst.KmsVersion.Kmsv1) {
|
||||
keyId = AliyunConst.KMS_DEFAULT_KEY_ID_VALUE;
|
||||
LOGGER.info("using default keyId {}.", keyId);
|
||||
} else {
|
||||
String errorMsg = "keyId is not set up yet, unable to encrypt the configuration.";
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
LOGGER.error(AliyunConst.formatHelpMessage(errorMsg), localInitException);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("using keyId {}.", keyId);
|
||||
}
|
||||
|
||||
try {
|
||||
if (kmsVersion == AliyunConst.KmsVersion.Kmsv1) {
|
||||
kmsClient = createKmsV1Client(properties);
|
||||
} else if (kmsVersion == AliyunConst.KmsVersion.Kmsv3) {
|
||||
kmsClient = createKmsV3Client(properties);
|
||||
}
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error(AliyunConst.formatHelpMessage("kms init failed."), e);
|
||||
localInitException = e;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(AliyunConst.formatHelpMessage("create kms client failed."), e);
|
||||
localInitException = e;
|
||||
}
|
||||
try {
|
||||
asyncProcessor = new AsyncProcessor();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("init async processor failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init kms v1 client, accessing the KMS service through a shared gateway.
|
||||
*
|
||||
* @date 2023/9/19
|
||||
* @description
|
||||
* @param properties
|
||||
* @return com.aliyuncs.IAcsClient
|
||||
* @throws
|
||||
*/
|
||||
private IAcsClient createKmsV1Client(Properties properties) {
|
||||
String regionId = properties.getProperty(REGION_ID, System.getProperty(REGION_ID, System.getenv(REGION_ID)));
|
||||
String kmsRegionId = properties.getProperty(KMS_REGION_ID, System.getProperty(KMS_REGION_ID, System.getenv(KMS_REGION_ID)));
|
||||
if (StringUtils.isBlank(regionId)) {
|
||||
regionId = kmsRegionId;
|
||||
}
|
||||
LOGGER.info("using regionId {}.", regionId);
|
||||
if (StringUtils.isBlank(kmsRegionId)) {
|
||||
kmsRegionId = regionId;
|
||||
}
|
||||
LOGGER.info("using kms regionId {}.", kmsRegionId);
|
||||
|
||||
if (StringUtils.isBlank(kmsRegionId) && StringUtils.isBlank(regionId)) {
|
||||
String errorMsg = "region is not set up yet";
|
||||
LOGGER.error(AliyunConst.formatHelpMessage(errorMsg));
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
String ramRoleName= properties.getProperty(PropertyKeyConst.RAM_ROLE_NAME,
|
||||
System.getProperty(PropertyKeyConst.RAM_ROLE_NAME, System.getenv(PropertyKeyConst.RAM_ROLE_NAME)));
|
||||
LOGGER.info("using ramRoleName {}.", ramRoleName);
|
||||
|
||||
String accessKey = properties.getProperty(PropertyKeyConst.ACCESS_KEY,
|
||||
System.getProperty(PropertyKeyConst.ACCESS_KEY, System.getenv(PropertyKeyConst.ACCESS_KEY)));
|
||||
LOGGER.info("using accessKey {}.", accessKey);
|
||||
|
||||
String secretKey = properties.getProperty(PropertyKeyConst.SECRET_KEY,
|
||||
System.getProperty(PropertyKeyConst.SECRET_KEY, System.getenv(PropertyKeyConst.SECRET_KEY)));
|
||||
|
||||
String kmsEndpoint = properties.getProperty(AliyunConst.KMS_ENDPOINT,
|
||||
System.getProperty(AliyunConst.KMS_ENDPOINT, System.getenv(AliyunConst.KMS_ENDPOINT)));
|
||||
if (!StringUtils.isBlank(kmsEndpoint)) {
|
||||
DefaultProfile.addEndpoint(regionId, "kms", kmsEndpoint);
|
||||
}
|
||||
LOGGER.info("using kmsEndpoint {}.", kmsEndpoint);
|
||||
|
||||
IClientProfile profile = null;
|
||||
IAcsClient kmsClient = null;
|
||||
if (!StringUtils.isBlank(ramRoleName)) {
|
||||
profile = DefaultProfile.getProfile(regionId);
|
||||
AlibabaCloudCredentialsProvider alibabaCloudCredentialsProvider = new InstanceProfileCredentialsProvider(
|
||||
ramRoleName);
|
||||
kmsClient = new KmsTransferAcsClient(profile, alibabaCloudCredentialsProvider);
|
||||
LOGGER.info("successfully create kms client by using RAM role.");
|
||||
} else {
|
||||
profile = DefaultProfile.getProfile(regionId, accessKey, secretKey);
|
||||
kmsClient = new KmsTransferAcsClient(profile);
|
||||
LOGGER.info("successfully create kms client by using ak/sk.");
|
||||
}
|
||||
return kmsClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* init kms v3 client, accessing the KMS service through the KMS instance gateway.
|
||||
*
|
||||
* @date 2023/9/19
|
||||
* @description
|
||||
* @param properties
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
private IAcsClient createKmsV3Client(Properties properties) throws ClientException {
|
||||
Config config = new Config();
|
||||
config.setProtocol("https");
|
||||
IClientProfile profile = null;
|
||||
|
||||
|
||||
String kmsClientKeyContent = properties.getProperty(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY)));
|
||||
if (!StringUtils.isBlank(kmsClientKeyContent)) {
|
||||
LOGGER.info("using {}: {}.", AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, kmsClientKeyContent);
|
||||
config.setClientKeyContent(kmsClientKeyContent);
|
||||
} else {
|
||||
String errorMsg = null;
|
||||
LOGGER.info("{} is empty, will read from file.", AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY);
|
||||
String kmsClientKeyFilePath = properties.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY)));
|
||||
if (!StringUtils.isBlank(kmsClientKeyFilePath)) {
|
||||
String s = readFileToString(kmsClientKeyFilePath);
|
||||
if (!StringUtils.isBlank(s)) {
|
||||
LOGGER.info("using kmsClientKeyFilePath: {}.", kmsClientKeyFilePath);
|
||||
config.setClientKeyFile(kmsClientKeyFilePath);
|
||||
} else {
|
||||
errorMsg = "both config from kmsClientKeyContent and kmsClientKeyFilePath is empty";
|
||||
}
|
||||
} else {
|
||||
errorMsg = "kmsClientKeyFilePath is empty";
|
||||
}
|
||||
if (!StringUtils.isBlank(errorMsg)) {
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
}
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY)));
|
||||
String kmsClientKeyFilePath = properties.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY)));
|
||||
|
||||
if(!StringUtils.isBlank(kmsClientKeyContent)||!StringUtils.isBlank(kmsClientKeyFilePath)){
|
||||
LOGGER.info("kmsClientKeyContent or kmsClientKeyFilePath is set up, using ClientKey to connect KMS.");
|
||||
this.kmsEncryptor = new ClientKeyKmsEncryptor(properties);
|
||||
}else{
|
||||
LOGGER.info("kmsClientKeyContent and kmsClientKeyFilePath are not set up, using Ram to connect KMS.");
|
||||
this.kmsEncryptor = new RamKmsEncryptor(properties);
|
||||
}
|
||||
|
||||
String kmsEndpoint = properties.getProperty(AliyunConst.KMS_ENDPOINT,
|
||||
System.getProperty(AliyunConst.KMS_ENDPOINT, System.getenv(AliyunConst.KMS_ENDPOINT)));
|
||||
if (StringUtils.isBlank(kmsEndpoint)) {
|
||||
String errorMsg = String.format("%s is empty", AliyunConst.KMS_ENDPOINT);
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
} else {
|
||||
LOGGER.info("using kmsEndpoint: {}.", kmsEndpoint);
|
||||
config.setEndpoint(kmsEndpoint);
|
||||
}
|
||||
|
||||
String kmsPassword = properties.getProperty(AliyunConst.KMS_PASSWORD_KEY,
|
||||
System.getProperty(AliyunConst.KMS_PASSWORD_KEY, System.getenv(AliyunConst.KMS_PASSWORD_KEY)));
|
||||
if (StringUtils.isBlank(kmsPassword)) {
|
||||
String errorMsg = String.format("%s is empty", AliyunConst.KMS_PASSWORD_KEY);
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
} else {
|
||||
LOGGER.info("using kmsPassword prefix: {}.", kmsPassword.substring(kmsPassword.length() / 8));
|
||||
config.setPassword(kmsPassword);
|
||||
}
|
||||
|
||||
String kmsCaFileContent = properties.getProperty(AliyunConst.KMS_CA_FILE_CONTENT,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_CONTENT, System.getenv(AliyunConst.KMS_CA_FILE_CONTENT)));
|
||||
if (!StringUtils.isBlank(kmsCaFileContent)) {
|
||||
LOGGER.info("using {}: {}.", AliyunConst.KMS_CA_FILE_CONTENT, kmsCaFileContent);
|
||||
config.setCa(kmsCaFileContent);
|
||||
} else {
|
||||
String errorMsg = null;
|
||||
LOGGER.info("{} is empty, will read from file.", AliyunConst.KMS_CA_FILE_CONTENT);
|
||||
String kmsCaFilePath = properties.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY, System.getenv(AliyunConst.KMS_CA_FILE_PATH_KEY)));
|
||||
if (!StringUtils.isBlank(kmsCaFilePath)) {
|
||||
config.setCaFilePath(kmsCaFilePath);
|
||||
} else {
|
||||
errorMsg = "kmsCaFilePath is empty";
|
||||
config.setCaFilePath(null);
|
||||
}
|
||||
if (!StringUtils.isBlank(errorMsg)) {
|
||||
LOGGER.warn(AliyunConst.formatHelpMessage(errorMsg));
|
||||
profile = DefaultProfile.getProfile(config.getRegionId(), "ak", "sk", "sts");
|
||||
HttpClientConfig httpClientConfig = HttpClientConfig.getDefault();
|
||||
httpClientConfig.setIgnoreSSLCerts(true);
|
||||
profile.setHttpClientConfig(httpClientConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
return new KmsTransferAcsClient(config);
|
||||
}
|
||||
return new KmsTransferAcsClient(profile, config);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void doFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain filterChain)
|
||||
|
@ -307,7 +60,7 @@ public class AliyunConfigFilter extends AbstractConfigFilter {
|
|||
group = (String) request.getParameter(GROUP);
|
||||
if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
if (!StringUtils.isBlank((String)request.getParameter(CONTENT))) {
|
||||
request.putParameter(CONTENT, encrypt(keyId, request));
|
||||
request.putParameter(CONTENT, kmsEncryptor.encrypt(request));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +71,7 @@ public class AliyunConfigFilter extends AbstractConfigFilter {
|
|||
group = (String) response.getParameter(GROUP);
|
||||
if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
if (!StringUtils.isBlank((String)response.getParameter(CONTENT))) {
|
||||
response.putParameter(CONTENT, decrypt(response));
|
||||
response.putParameter(CONTENT, kmsEncryptor.decrypt(response));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,197 +79,10 @@ public class AliyunConfigFilter extends AbstractConfigFilter {
|
|||
String message = String.format("KMS message:[%s], error message:[%s], dataId: %s, groupId: %s", e.getMessage(), e.getErrMsg(), dataId, group);
|
||||
throw new NacosException(NacosException.HTTP_CLIENT_ERROR_CODE, AliyunConst.formatHelpMessage(message), e);
|
||||
} catch (Exception e) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (StackTraceElement ste : e.getStackTrace()) {
|
||||
stringBuilder.append(ste.toString()).append("\n");
|
||||
}
|
||||
NacosException ee = new NacosException(NacosException.INVALID_PARAM, AliyunConst.formatHelpMessage(stringBuilder.toString()), e);
|
||||
throw ee;
|
||||
throw new NacosException(NacosException.INVALID_PARAM, AliyunConst.formatHelpMessage(e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String decrypt(IConfigResponse response) throws Exception {
|
||||
String dataId = (String) response.getParameter(DATA_ID);
|
||||
String content = (String) response.getParameter(CONTENT);
|
||||
String result;
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
String encryptedDataKey = (String) response.getParameter(ENCRYPTED_DATA_KEY);
|
||||
if (!StringUtils.isBlank(encryptedDataKey)) {
|
||||
String dataKey = decrypt(encryptedDataKey);
|
||||
if (StringUtils.isBlank(dataKey)) {
|
||||
throw new RuntimeException("failed to decrypt encryptedDataKey with empty value");
|
||||
}
|
||||
result = AesUtils.decrypt((String) response.getParameter(CONTENT), dataKey, "UTF-8");
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new RuntimeException("failed to decrypt content with empty value");
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("encrypted failed encryptedDataKey is empty");
|
||||
}
|
||||
} else {
|
||||
result = decrypt(content);
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new RuntimeException("failed to decrypt content with empty value");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String decrypt(String content) throws Exception {
|
||||
if (kmsClient == null) {
|
||||
if (localInitException != null) {
|
||||
throw localInitException;
|
||||
} else {
|
||||
throw new RuntimeException("kms client isn't initialized. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
}
|
||||
final DecryptRequest decReq = new DecryptRequest();
|
||||
decReq.setSysProtocol(ProtocolType.HTTPS);
|
||||
decReq.setSysMethod(MethodType.POST);
|
||||
decReq.setAcceptFormat(FormatType.JSON);
|
||||
decReq.setCiphertextBlob(content);
|
||||
return kmsClient.getAcsResponse(decReq).getPlaintext();
|
||||
}
|
||||
|
||||
private String encrypt(String keyId, IConfigRequest configRequest) throws Exception {
|
||||
if (kmsClient == null) {
|
||||
if (localInitException != null) {
|
||||
throw localInitException;
|
||||
} else {
|
||||
throw new RuntimeException("kms client isn't initialized. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(keyId)) {
|
||||
throw new RuntimeException("keyId is not set up yet, unable to encrypt the configuration. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
String result;
|
||||
protectKeyId(keyId);
|
||||
String dataId = (String) configRequest.getParameter(DATA_ID);
|
||||
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
String keySpec = null;
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX)) {
|
||||
keySpec = KMS_KEY_SPEC_AES_128;
|
||||
} else {
|
||||
keySpec = KMS_KEY_SPEC_AES_256;
|
||||
}
|
||||
GenerateDataKeyResponse generateDataKeyResponse = generateDataKey(keyId, keySpec);
|
||||
String dataKey = generateDataKeyResponse.getPlaintext();
|
||||
if (StringUtils.isBlank(dataKey.trim())) {
|
||||
throw new RuntimeException("get generateDataKey failed with empty content. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
configRequest.putParameter(ENCRYPTED_DATA_KEY, generateDataKeyResponse.getCiphertextBlob());
|
||||
result = AesUtils.encrypt((String) configRequest.getParameter(CONTENT), dataKey, "UTF-8");
|
||||
} else {
|
||||
result = encrypt(keyId, (String) configRequest.getParameter(CONTENT));
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(result)) {
|
||||
throw new RuntimeException("encrypt failed with empty result.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String encrypt(String keyId, String plainText) throws Exception {
|
||||
final EncryptRequest encReq = new EncryptRequest();
|
||||
encReq.setProtocol(ProtocolType.HTTPS);
|
||||
encReq.setAcceptFormat(FormatType.JSON);
|
||||
encReq.setMethod(MethodType.POST);
|
||||
encReq.setKeyId(keyId);
|
||||
encReq.setPlaintext(plainText);
|
||||
return kmsClient.getAcsResponse(encReq).getCiphertextBlob();
|
||||
}
|
||||
|
||||
public GenerateDataKeyResponse generateDataKey(String keyId, String keySpec) throws ClientException {
|
||||
GenerateDataKeyRequest generateDataKeyRequest = new GenerateDataKeyRequest();
|
||||
|
||||
generateDataKeyRequest.setAcceptFormat(FormatType.JSON);
|
||||
|
||||
generateDataKeyRequest.setKeyId(keyId);
|
||||
generateDataKeyRequest.setKeySpec(keySpec);
|
||||
return kmsClient.getAcsResponse(generateDataKeyRequest);
|
||||
}
|
||||
|
||||
private void protectKeyId(String keyId) {
|
||||
if (!addedKeys.contains(keyId)) {
|
||||
synchronized (addedKeys) {
|
||||
addedKeys.add(keyId);
|
||||
asyncProcessor.addTack(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (kmsClient == null) {
|
||||
LOGGER.error("kms client hasn't initiated.");
|
||||
return;
|
||||
}
|
||||
DescribeKeyRequest describeKeyRequest = new DescribeKeyRequest();
|
||||
describeKeyRequest.setKeyId(keyId);
|
||||
try {
|
||||
DescribeKeyResponse describeKeyResponse = kmsClient.getAcsResponse(describeKeyRequest);
|
||||
if (describeKeyResponse.getKeyMetadata()!= null) {
|
||||
String arn = describeKeyResponse.getKeyMetadata().getArn();
|
||||
LOGGER.info("set deletion protection for keyId[{}], arn[{}]", keyId, arn);
|
||||
|
||||
SetDeletionProtectionRequest setDeletionProtectionRequest = new SetDeletionProtectionRequest();
|
||||
setDeletionProtectionRequest.setProtectedResourceArn(arn);
|
||||
setDeletionProtectionRequest.setEnableDeletionProtection(true);
|
||||
setDeletionProtectionRequest.setDeletionProtectionDescription("key is used by nacos-client");
|
||||
try {
|
||||
kmsClient.getAcsResponse(setDeletionProtectionRequest);
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("set deletion protect failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.warn("keyId meta is null, cannot set key protection");
|
||||
}
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("describe key failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.error("execute async task failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readFileToString(String filePath) {
|
||||
File file = getFileByPath(filePath);
|
||||
if (file == null || !file.exists()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
byte[] fileContent = Files.readAllBytes(path);
|
||||
return new String(fileContent, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static File getFileByPath(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
String path = AliyunConfigFilter.class.getClassLoader().getResource("").getPath();
|
||||
if (!(file = new File(path + filePath)).exists()) {
|
||||
path = Paths.get(filePath).toAbsolutePath().toString();
|
||||
if (!(file = new File(path)).exists()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
|
@ -526,4 +92,8 @@ public class AliyunConfigFilter extends AbstractConfigFilter {
|
|||
public String getFilterName() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
this.kmsEncryptor.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,73 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* the Const Values of Aliyun.
|
||||
*
|
||||
* @author luyanbo(RobberPhex)
|
||||
*/
|
||||
public class AliyunConst {
|
||||
|
||||
public static final String GROUP = "group";
|
||||
|
||||
public static final String DATA_ID = "dataId";
|
||||
|
||||
public static final String CONTENT = "content";
|
||||
|
||||
public static final String ENCRYPTED_DATA_KEY = "encryptedDataKey";
|
||||
|
||||
public static final String CIPHER_PREFIX = "cipher-";
|
||||
|
||||
public static final String CIPHER_KMS_AES_128_PREFIX = "cipher-kms-aes-128-";
|
||||
|
||||
public static final String CIPHER_KMS_AES_256_PREFIX = "cipher-kms-aes-256-";
|
||||
|
||||
public static final String KMS_KEY_SPEC_AES_128 = "AES_128";
|
||||
|
||||
public static final String KMS_KEY_SPEC_AES_256 = "AES_256";
|
||||
|
||||
public static final String KMS_ACCESS_KEY = "kmsAccessKey";
|
||||
|
||||
public static final String KMS_SECRET_KEY = "kmsSecretKey";
|
||||
|
||||
public static final String KMS_RAM_ROLE_NAME = "kmsRamRoleName";
|
||||
|
||||
public static final String KMS_ROLE_ARN = "kmsRoleArn";
|
||||
|
||||
public static final String KMS_POLICY = "kmsPolicy";
|
||||
|
||||
public static final String KMS_ROLE_SESSION_EXPIRATION_SECONDS = "kmsRoleSessionExpiration";
|
||||
|
||||
public static final String KMS_OIDC_PROVIDER_ARN = "kmsOidcProviderArn";
|
||||
|
||||
public static final String KMS_ROLE_SESSION_NAME = "kmsRoleSessionName";
|
||||
|
||||
public static final String KMS_OIDC_TOKEN_FILE_PATH = "kmsOidcTokenFilePath";
|
||||
|
||||
public static final String KMS_SECURITY_TOKEN = "kmsSecurityToken";
|
||||
|
||||
public static final String KMS_EXTENSION_ACCESS_KEY = "kmsExtensionAccessKey";
|
||||
|
||||
public static final String KMS_EXTENSION_SECRET_KEY = "kmsExtensionSecretKey";
|
||||
|
||||
public static final String KMS_CREDENTIALS_URI = "kmsCredentialsUri";
|
||||
|
||||
public static final String ENCODE_UTF8 = StandardCharsets.UTF_8.displayName();
|
||||
|
||||
public static final String ENCODE_UTF16 = StandardCharsets.UTF_16.displayName();
|
||||
|
||||
public static final String KMS_ENDPOINT = "kmsEndpoint";
|
||||
|
||||
public static final String KMS_VERSION_KEY = "kmsVersion";
|
||||
|
||||
public static final String KMS_DEFAULT_KEY_ID_VALUE = "alias/acs/mse";
|
||||
|
||||
public static final String REGION_ID = "regionId";
|
||||
|
||||
public static final String KMS_REGION_ID = "kms_region_id";
|
||||
|
||||
public static final String KEY_ID = "keyId";
|
||||
|
||||
public static final String KMS_CLIENT_KEY_FILE_PATH_KEY = "kmsClientKeyFilePath";
|
||||
|
||||
|
@ -21,8 +78,30 @@ public class AliyunConst {
|
|||
public static final String KMS_CA_FILE_PATH_KEY = "kmsCaFilePath";
|
||||
|
||||
public static final String KMS_CA_FILE_CONTENT = "kmsCaFileContent";
|
||||
|
||||
public static final String OPEN_SSL_KEY = "openSSL";
|
||||
|
||||
public static final String MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL = "https://help.aliyun.com/zh/mse/user-guide/create-and-use-encrypted-configurations?spm=a2c4g.11186623.0.0.55587becdOW3jf";
|
||||
|
||||
public static final String NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_SWITCH = "nacos.config.encryption.kms.local.cache.switch";
|
||||
|
||||
public static final boolean DEFAULT_KMS_LOCAL_CACHE_SWITCH = true;
|
||||
|
||||
public static final String NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_SIZE = "nacos.config.encryption.kms.local.cache.maxSize";
|
||||
|
||||
public static final int DEFAULT_KMS_LOCAL_CACHE_MAX_SIZE = 1000;
|
||||
|
||||
public static final String NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_AFTER_ACCESS_DURATION = "nacos.config.encryption.kms.local.cache.afterAccessDuration";
|
||||
|
||||
public static final int DEFAULT_KMS_LOCAL_CACHE_AFTER_ACCESS_DURATION_SECONDS = 60 * 60;
|
||||
|
||||
public static final String NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_AFTER_WRITE_DURATION = "nacos.config.encryption.kms.local.cache.afterWriteDuration";
|
||||
|
||||
public static final int DEFAULT_KMS_LOCAL_CACHE_AFTER_WRITE_DURATION_SECONDS = 60 * 60 * 24;
|
||||
|
||||
public static final String NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_TEST_MODE = "nacos.config.encryption.kms.local.cache.testMode";
|
||||
|
||||
public static final String STRING_VALUE_BLANK_ERROR_MSG_FORMAT = "[config: %s] %s. %s is null or empty.";
|
||||
|
||||
public static String formatHelpMessage(String errorMessage) {
|
||||
return String.format("%s, for more information, please check: %s",
|
||||
|
|
|
@ -7,10 +7,15 @@ import java.util.concurrent.ArrayBlockingQueue;
|
|||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author rong
|
||||
*/
|
||||
public class AsyncProcessor {
|
||||
|
||||
private static final int QUEUE_INITIAL_CAPACITY = 8;
|
||||
|
||||
|
||||
private static final int DEFAULT_RETRY_INTERVAL_MILLISECONDS_WHEN_EXCEPTION = 10 * 1000;
|
||||
|
||||
private static final String DEFAULT_PROCESSOR_NAME = "asyncProcessor";
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncProcessor.class);
|
||||
|
@ -20,7 +25,7 @@ public class AsyncProcessor {
|
|||
private final AtomicBoolean closed;
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
public AsyncProcessor() {
|
||||
this(QUEUE_INITIAL_CAPACITY, DEFAULT_PROCESSOR_NAME);
|
||||
}
|
||||
|
@ -29,7 +34,7 @@ public class AsyncProcessor {
|
|||
this.queue = new ArrayBlockingQueue<Runnable>(queueSize);
|
||||
this.closed = new AtomicBoolean(false);
|
||||
this.name = name;
|
||||
(new InnerWorker(name)).start();
|
||||
(new InnerWorker(name, this)).start();
|
||||
}
|
||||
|
||||
public void addTack(Runnable task) {
|
||||
|
@ -50,20 +55,33 @@ public class AsyncProcessor {
|
|||
}
|
||||
|
||||
private class InnerWorker extends Thread {
|
||||
InnerWorker(String name) {
|
||||
AsyncProcessor outterAsyncProcessor;
|
||||
|
||||
InnerWorker(String name, AsyncProcessor outterAsyncProcessor) {
|
||||
super(name);
|
||||
this.outterAsyncProcessor = outterAsyncProcessor;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed.get()) {
|
||||
Runnable task = null;
|
||||
try {
|
||||
Runnable task = queue.take();
|
||||
task = queue.take();
|
||||
long begin = System.currentTimeMillis();
|
||||
task.run();
|
||||
long duration = System.currentTimeMillis();
|
||||
LOGGER.info("runner[{}] executed task {} cost {} ms", getName(), task, duration - begin);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error(e.toString(), e);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(String.format("task running failed with retry milli interval %d. exception msg: %s.",
|
||||
DEFAULT_RETRY_INTERVAL_MILLISECONDS_WHEN_EXCEPTION, e.toString()), e);
|
||||
try {
|
||||
Thread.sleep(DEFAULT_RETRY_INTERVAL_MILLISECONDS_WHEN_EXCEPTION);
|
||||
} catch (InterruptedException ex) {
|
||||
LOGGER.error(e.toString(), e);
|
||||
}
|
||||
if (this.outterAsyncProcessor != null && task != null) {
|
||||
this.outterAsyncProcessor.addTack(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.aliyun.dkms.gcs.openapi.models.Config;
|
||||
import com.aliyun.kms.KmsTransferAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.http.FormatType;
|
||||
import com.aliyuncs.http.HttpClientConfig;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.aliyuncs.http.ProtocolType;
|
||||
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.EncryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.SetDeletionProtectionRequest;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.aliyuncs.profile.IClientProfile;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.KEY_ID;
|
||||
|
||||
public class ClientKeyKmsEncryptor extends KmsEncryptor{
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClientKeyKmsEncryptor.class);
|
||||
|
||||
private IAcsClient kmsClient;
|
||||
|
||||
private String keyId;
|
||||
|
||||
private Exception localInitException;
|
||||
|
||||
private final Set<String> addedKeys = new HashSet<String>();
|
||||
|
||||
private AsyncProcessor asyncProcessor;
|
||||
|
||||
public ClientKeyKmsEncryptor(Properties properties) {
|
||||
super(properties);
|
||||
keyId = properties.getProperty(KEY_ID, System.getProperty(KEY_ID, System.getenv(KEY_ID)));
|
||||
if (StringUtils.isBlank(keyId)) {
|
||||
String errorMsg = "keyId is not set up yet, unable to encrypt the configuration.";
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
LOGGER.error(AliyunConst.formatHelpMessage(errorMsg));
|
||||
} else {
|
||||
LOGGER.info("using keyId {}.", keyId);
|
||||
}
|
||||
try{
|
||||
kmsClient = createKmsV3Client(properties);
|
||||
}catch (ClientException e){
|
||||
localInitException = e;
|
||||
}
|
||||
|
||||
if(localInitException == null){
|
||||
try {
|
||||
asyncProcessor = new AsyncProcessor();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("init async processor failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String encrypt(String plainText) throws Exception {
|
||||
AtomicReference<String> resultContent = new AtomicReference<>();
|
||||
final EncryptRequest encReq = new EncryptRequest();
|
||||
encReq.setProtocol(ProtocolType.HTTPS);
|
||||
encReq.setAcceptFormat(FormatType.XML);
|
||||
encReq.setMethod(MethodType.POST);
|
||||
encReq.setKeyId(keyId);
|
||||
encReq.setPlaintext(plainText);
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set( kmsClient.getAcsResponse(encReq).getCiphertextBlob());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (StringUtils.isBlank(resultContent.get())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
return resultContent.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decrypt(String content) throws Exception {
|
||||
AtomicReference<String> resultContent = new AtomicReference<>();
|
||||
final DecryptRequest decReq = new DecryptRequest();
|
||||
decReq.setSysProtocol(ProtocolType.HTTPS);
|
||||
decReq.setSysMethod(MethodType.POST);
|
||||
decReq.setAcceptFormat(FormatType.XML);
|
||||
decReq.setCiphertextBlob(content);
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set(kmsClient.getAcsResponse(decReq).getPlaintext());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (StringUtils.isBlank(resultContent.get())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
return resultContent.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private IAcsClient createKmsV3Client(Properties properties) throws ClientException{
|
||||
Config config = new Config();
|
||||
config.setProtocol("https");
|
||||
IClientProfile profile = null;
|
||||
|
||||
String kmsClientKeyContent = properties.getProperty(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY)));
|
||||
if (!StringUtils.isBlank(kmsClientKeyContent)) {
|
||||
LOGGER.info("using {}: {}.", AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, kmsClientKeyContent);
|
||||
config.setClientKeyContent(kmsClientKeyContent);
|
||||
} else {
|
||||
String errorMsg = null;
|
||||
LOGGER.info("{} is empty, will read from file.", AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY);
|
||||
String kmsClientKeyFilePath = properties.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY, System.getenv(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY)));
|
||||
if (!StringUtils.isBlank(kmsClientKeyFilePath)) {
|
||||
String s = readFileToString(kmsClientKeyFilePath);
|
||||
if (!StringUtils.isBlank(s)) {
|
||||
LOGGER.info("using kmsClientKeyFilePath: {}.", kmsClientKeyFilePath);
|
||||
config.setClientKeyFile(kmsClientKeyFilePath);
|
||||
} else {
|
||||
errorMsg = "both config from kmsClientKeyContent and kmsClientKeyFilePath is empty";
|
||||
}
|
||||
} else {
|
||||
errorMsg = "kmsClientKeyFilePath and kmsClientKeyContent are both empty";
|
||||
}
|
||||
if (!StringUtils.isBlank(errorMsg)) {
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String kmsEndpoint = properties.getProperty(AliyunConst.KMS_ENDPOINT,
|
||||
System.getProperty(AliyunConst.KMS_ENDPOINT, System.getenv(AliyunConst.KMS_ENDPOINT)));
|
||||
if (StringUtils.isBlank(kmsEndpoint)) {
|
||||
String errorMsg = String.format("%s is empty", AliyunConst.KMS_ENDPOINT);
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
} else {
|
||||
LOGGER.info("using kmsEndpoint: {}.", kmsEndpoint);
|
||||
config.setEndpoint(kmsEndpoint);
|
||||
}
|
||||
|
||||
String kmsPassword = properties.getProperty(AliyunConst.KMS_PASSWORD_KEY,
|
||||
System.getProperty(AliyunConst.KMS_PASSWORD_KEY, System.getenv(AliyunConst.KMS_PASSWORD_KEY)));
|
||||
if (StringUtils.isBlank(kmsPassword)) {
|
||||
String errorMsg = String.format("%s is empty", AliyunConst.KMS_PASSWORD_KEY);
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
} else {
|
||||
LOGGER.info("using kmsPassword prefix: {}.", kmsPassword.substring(kmsPassword.length() / 8));
|
||||
config.setPassword(kmsPassword);
|
||||
}
|
||||
|
||||
String kmsCaFileContent = properties.getProperty(AliyunConst.KMS_CA_FILE_CONTENT,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_CONTENT, System.getenv(AliyunConst.KMS_CA_FILE_CONTENT)));
|
||||
if (!StringUtils.isBlank(kmsCaFileContent)) {
|
||||
LOGGER.info("using {}: {}.", AliyunConst.KMS_CA_FILE_CONTENT, kmsCaFileContent);
|
||||
config.setCa(kmsCaFileContent);
|
||||
} else {
|
||||
String errorMsg = null;
|
||||
LOGGER.info("{} is empty, will read from file.", AliyunConst.KMS_CA_FILE_CONTENT);
|
||||
String kmsCaFilePath = properties.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY, System.getenv(AliyunConst.KMS_CA_FILE_PATH_KEY)));
|
||||
if (!StringUtils.isBlank(kmsCaFilePath)) {
|
||||
config.setCaFilePath(kmsCaFilePath);
|
||||
} else {
|
||||
errorMsg = "kmsCaFilePath is empty";
|
||||
config.setCaFilePath(null);
|
||||
}
|
||||
if (!StringUtils.isBlank(errorMsg)) {
|
||||
LOGGER.warn(AliyunConst.formatHelpMessage(errorMsg));
|
||||
profile = DefaultProfile.getProfile(config.getRegionId(), "ak", "sk", "sts");
|
||||
HttpClientConfig httpClientConfig = HttpClientConfig.getDefault();
|
||||
httpClientConfig.setIgnoreSSLCerts(true);
|
||||
profile.setHttpClientConfig(httpClientConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
return new KmsTransferAcsClient(config);
|
||||
}
|
||||
return new KmsTransferAcsClient(profile, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataKey generateDataKey(String keySpec) throws Exception {
|
||||
GenerateDataKeyRequest generateDataKeyRequest = new GenerateDataKeyRequest();
|
||||
generateDataKeyRequest.setAcceptFormat(FormatType.XML);
|
||||
generateDataKeyRequest.setKeyId(keyId);
|
||||
generateDataKeyRequest.setKeySpec(keySpec);
|
||||
AtomicReference<GenerateDataKeyResponse> resultContent = new AtomicReference<>();
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set(kmsClient.getAcsResponse(generateDataKeyRequest));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (resultContent.get() == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
DataKey dataKey = new DataKey();
|
||||
dataKey.setEncryptedDataKey(resultContent.get().getCiphertextBlob());
|
||||
dataKey.setPlainDataKey(resultContent.get().getPlaintext());
|
||||
return dataKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void protectKeyId() {
|
||||
if (!addedKeys.contains(keyId)) {
|
||||
synchronized (addedKeys) {
|
||||
if (addedKeys.contains(keyId)) {
|
||||
return;
|
||||
}
|
||||
addedKeys.add(keyId);
|
||||
asyncProcessor.addTack(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (kmsClient == null) {
|
||||
LOGGER.error("kms client hasn't initiated.");
|
||||
return;
|
||||
}
|
||||
DescribeKeyRequest describeKeyRequest = new DescribeKeyRequest();
|
||||
describeKeyRequest.setKeyId(keyId);
|
||||
try {
|
||||
DescribeKeyResponse describeKeyResponse = kmsClient.getAcsResponse(describeKeyRequest);
|
||||
if (describeKeyResponse.getKeyMetadata()!= null) {
|
||||
if (!"Enabled".equals(describeKeyResponse.getKeyMetadata().getKeyState())) {
|
||||
throw new RuntimeException("Key not available");
|
||||
}
|
||||
String arn = describeKeyResponse.getKeyMetadata().getArn();
|
||||
LOGGER.info("set deletion protection for keyId[{}], arn[{}]", keyId, arn);
|
||||
|
||||
SetDeletionProtectionRequest setDeletionProtectionRequest = new SetDeletionProtectionRequest();
|
||||
setDeletionProtectionRequest.setProtectedResourceArn(arn);
|
||||
setDeletionProtectionRequest.setEnableDeletionProtection(true);
|
||||
setDeletionProtectionRequest.setDeletionProtectionDescription("key is used by mse");
|
||||
try {
|
||||
kmsClient.getAcsResponse(setDeletionProtectionRequest);
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("set deletion protect failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.warn("keyId meta is null, cannot set key protection");
|
||||
}
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("describe key failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.error("execute async task failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void checkIfKmsClientIsReady() throws Exception {
|
||||
if (kmsClient == null) {
|
||||
if (localInitException != null) {
|
||||
throw localInitException;
|
||||
} else {
|
||||
throw new RuntimeException("kms client isn't initialized. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkKeyId() throws Exception {
|
||||
throwExceptionIfStringBlankWithErrorKey(keyId, "", "keyId is not set.", KEY_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
asyncProcessor.shutdown();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
public class GroupKeyUtils {
|
||||
public static String getGroupKey2(String dataId, String group) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
urlEncode(dataId, sb);
|
||||
sb.append('+');
|
||||
urlEncode(group, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void urlEncode(String str, StringBuilder sb) {
|
||||
for (int idx = 0; idx < str.length(); ++idx) {
|
||||
char c = str.charAt(idx);
|
||||
if ('+' == c) {
|
||||
sb.append("%2B");
|
||||
} else if ('%' == c) {
|
||||
sb.append("%25");
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.config.filter.IConfigRequest;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigResponse;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_128_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_256_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CONTENT;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.DATA_ID;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.ENCODE_UTF8;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.ENCRYPTED_DATA_KEY;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.GROUP;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.STRING_VALUE_BLANK_ERROR_MSG_FORMAT;
|
||||
|
||||
public abstract class KmsEncryptor implements Closeable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AliyunConfigFilter.class);
|
||||
|
||||
private KmsLocalCache kmsLocalCache;
|
||||
|
||||
public static final int defaultRetryTimes = 3;
|
||||
|
||||
public static final int defaultRetryIntervalMilliseconds = 2 * 100;
|
||||
|
||||
public static final int defaultTimeoutMilliseconds = 3 * 1000;
|
||||
|
||||
public boolean isUseLocalCache;
|
||||
|
||||
public KmsEncryptor(Properties properties){
|
||||
this.isUseLocalCache = KmsUtils.parsePropertyValue(properties, AliyunConst.NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_SWITCH,
|
||||
AliyunConst.DEFAULT_KMS_LOCAL_CACHE_SWITCH);
|
||||
if (this.isUseLocalCache()) {
|
||||
LOGGER.info("using kms encryption local cache.");
|
||||
this.kmsLocalCache = new KmsLocalCache(properties);
|
||||
}
|
||||
}
|
||||
|
||||
public String encrypt(IConfigRequest configRequest) throws Exception {
|
||||
checkIfKmsClientIsReady();
|
||||
checkKeyId();
|
||||
protectKeyId();
|
||||
|
||||
String dataId = (String) configRequest.getParameter(DATA_ID);
|
||||
String group = (String) configRequest.getParameter(GROUP);
|
||||
String plainContent = (String) configRequest.getParameter(CONTENT);
|
||||
String plainDataKey = null;
|
||||
String encryptedDataKey = null;
|
||||
String result = null; //encryptedContent
|
||||
String blankResultErrorMsg = "encrypt from kms failed.";
|
||||
// Exception requestKmsException = null;
|
||||
|
||||
//prefer to use kms service
|
||||
try {
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
String keySpec = KmsUtils.getKeySpecByDataIdPrefix(dataId);
|
||||
DataKey dataKey = generateDataKey(keySpec);
|
||||
plainDataKey = dataKey.getPlainDataKey();
|
||||
throwExceptionIfStringBlankWithErrorKey(plainDataKey, GroupKeyUtils.getGroupKey2(dataId, group),
|
||||
"generateDataKeyResponse.getPlaintext()", "plainDataKey");
|
||||
encryptedDataKey = dataKey.getEncryptedDataKey();
|
||||
throwExceptionIfStringBlankWithErrorKey(encryptedDataKey, GroupKeyUtils.getGroupKey2(dataId, group),
|
||||
"generateDataKeyResponse.getCiphertextBlob()", "encryptedDataKey");
|
||||
configRequest.putParameter(ENCRYPTED_DATA_KEY, encryptedDataKey);
|
||||
result = AesUtils.encrypt(plainContent, plainDataKey, ENCODE_UTF8);
|
||||
} else if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
result = encrypt(plainContent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("encrypt config:[{}] failed by using kms service: {}.",
|
||||
GroupKeyUtils.getGroupKey2(dataId, group), e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
throwExceptionIfStringBlankWithErrorKey(result, GroupKeyUtils.getGroupKey2(dataId, group), "encrypt failed", blankResultErrorMsg);
|
||||
|
||||
//update local cache
|
||||
this.updateLocalCacheItem(group, dataId, encryptedDataKey, result, plainDataKey, plainContent);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public abstract String encrypt(String plainText) throws Exception;
|
||||
|
||||
public String decrypt(IConfigResponse configResponse) throws Exception {
|
||||
checkIfKmsClientIsReady();
|
||||
|
||||
String dataId = (String) configResponse.getParameter(DATA_ID);
|
||||
String group = (String) configResponse.getParameter(GROUP);
|
||||
String encryptedContent = (String) configResponse.getParameter(CONTENT);
|
||||
String encryptedDataKey = (String) configResponse.getParameter(ENCRYPTED_DATA_KEY);
|
||||
String plainDataKey = null;
|
||||
String result = null;
|
||||
Exception requestKmsException = null;
|
||||
String blankResultErrorMsg = "decrypt from kms failed.";
|
||||
boolean isUsedCache = true;
|
||||
|
||||
try {
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
throwExceptionIfStringBlankWithErrorKey(encryptedDataKey, GroupKeyUtils.getGroupKey2(dataId, group),
|
||||
"decrypt failed", "response.getParameter(ENCRYPTED_DATA_KEY)");
|
||||
plainDataKey = decrypt(encryptedDataKey);
|
||||
result = AesUtils.decrypt(encryptedContent, plainDataKey, ENCODE_UTF8);
|
||||
} else if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
result = decrypt(encryptedContent);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
//use local cache protection
|
||||
LOGGER.error("decrypt config:[{}] failed by using kms service: {}.",
|
||||
GroupKeyUtils.getGroupKey2(dataId, group), e.getMessage(), e);
|
||||
requestKmsException = e;
|
||||
}
|
||||
|
||||
if (requestKmsException != null || StringUtils.isBlank(result)) {
|
||||
LOGGER.warn("decrypt config [{}] failed with exception or empty result by using kms service. try to use local cache.", GroupKeyUtils.getGroupKey2(dataId, group));
|
||||
result = getDecryptedContentByUsingLocalCache(group, dataId, encryptedDataKey, encryptedContent);
|
||||
if (requestKmsException != null && StringUtils.isBlank(result)) {
|
||||
throw requestKmsException;
|
||||
} else if (StringUtils.isBlank(result)) {
|
||||
blankResultErrorMsg += "and no kms decryption local cache.";
|
||||
}
|
||||
} else {
|
||||
isUsedCache = false;
|
||||
}
|
||||
throwExceptionIfStringBlankWithErrorKey(result, GroupKeyUtils.getGroupKey2(dataId, group), "decrypt failed", blankResultErrorMsg);
|
||||
if (!isUsedCache) {
|
||||
this.updateLocalCacheItem(group, dataId, encryptedDataKey, encryptedContent, plainDataKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract String decrypt(String encryptedContent) throws Exception;
|
||||
|
||||
public abstract void protectKeyId();
|
||||
|
||||
public abstract DataKey generateDataKey(String keySpec) throws Exception;
|
||||
|
||||
public abstract void checkIfKmsClientIsReady() throws Exception;
|
||||
|
||||
public abstract void checkKeyId() throws Exception;
|
||||
|
||||
public void updateLocalCacheItem(String group, String dataId, String encryptedDataKey, String encryptedContent, String plainDataKey, String plainContent) {
|
||||
if (!this.isLocalCacheAvailable()) {
|
||||
return;
|
||||
}
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
getKmsLocalCache().put(GroupKeyUtils.getGroupKey2(dataId, group), new KmsLocalCache.LocalCacheItem(encryptedDataKey, encryptedContent, plainDataKey));
|
||||
} else if(dataId.startsWith(CIPHER_PREFIX)) {
|
||||
getKmsLocalCache().put(GroupKeyUtils.getGroupKey2(dataId, group), new KmsLocalCache.LocalCacheItem(encryptedContent, plainContent));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUseLocalCache() {
|
||||
return this.isUseLocalCache;
|
||||
}
|
||||
|
||||
public KmsLocalCache getKmsLocalCache() {
|
||||
return this.kmsLocalCache;
|
||||
}
|
||||
|
||||
public boolean isLocalCacheAvailable() {
|
||||
return this.isUseLocalCache() && this.getKmsLocalCache()!= null;
|
||||
}
|
||||
|
||||
|
||||
public String getDecryptedContentByUsingLocalCache(String group, String dataId, String encryptedDataKey, String encryptedContent)
|
||||
throws Exception {
|
||||
KmsLocalCache.LocalCacheItem localCacheItem = getLocalCacheItem(group, dataId, encryptedDataKey, encryptedContent);
|
||||
if (localCacheItem != null) {
|
||||
if (!StringUtils.isBlank(localCacheItem.getPlainDataKey())) {
|
||||
return AesUtils.decrypt(encryptedContent, localCacheItem.getPlainDataKey(), ENCODE_UTF8);
|
||||
} else if (!StringUtils.isBlank(localCacheItem.getPlainContent())) {
|
||||
return localCacheItem.getPlainContent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public KmsLocalCache.LocalCacheItem getLocalCacheItem(String group, String dataId, String encryptDataKey, String encryptedContent) {
|
||||
//check if open local cache
|
||||
if (!this.isLocalCacheAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//check if cache is ready
|
||||
KmsLocalCache.LocalCacheItem localCacheItem = this.getKmsLocalCache().get(GroupKeyUtils.getGroupKey2(dataId, group));
|
||||
if (localCacheItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//check if cache is valid
|
||||
if (!checkIfKmsCacheItemValidByDecrypt(localCacheItem, dataId, encryptDataKey, encryptedContent)) {
|
||||
return null;
|
||||
}
|
||||
return localCacheItem;
|
||||
}
|
||||
|
||||
public KmsLocalCache.LocalCacheItem getLocalCacheItem(String group, String dataId, String plainText) {
|
||||
//check if open local cache
|
||||
if (!this.isLocalCacheAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//check if cache is ready
|
||||
KmsLocalCache.LocalCacheItem localCacheItem = this.getKmsLocalCache().get(GroupKeyUtils.getGroupKey2(dataId, group));
|
||||
if (localCacheItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//check if cache is valid
|
||||
if (checkIfKmsCacheItemValidByEncrypt(localCacheItem, dataId, plainText)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return localCacheItem;
|
||||
}
|
||||
|
||||
public void locallyRunWithRetryTimesAndTimeout(Supplier<Boolean> runnable, int retryTimes, long timeout)
|
||||
throws Exception {
|
||||
int locallyRetryTimes = 0;
|
||||
Exception localException = null;
|
||||
long beginTime = System.currentTimeMillis();
|
||||
while (locallyRetryTimes++ < retryTimes && System.currentTimeMillis() < beginTime + timeout) {
|
||||
try {
|
||||
if (runnable.get()) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
localException = e;
|
||||
}
|
||||
Thread.sleep(defaultRetryIntervalMilliseconds);
|
||||
}
|
||||
if (localException != null) {
|
||||
throw localException;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkIfKmsCacheItemValidByEncrypt(KmsLocalCache.LocalCacheItem localCacheItem, String dataId, String plainContent) {
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
return !StringUtils.isBlank(localCacheItem.getEncryptedDataKey())
|
||||
&& !StringUtils.isBlank(localCacheItem.getPlainDataKey());
|
||||
} else if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
return !StringUtils.isBlank(localCacheItem.getEncryptedContent())
|
||||
&& !StringUtils.isBlank(localCacheItem.getPlainContent())
|
||||
&& localCacheItem.getPlainContent().equals(plainContent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkIfKmsCacheItemValidByDecrypt(KmsLocalCache.LocalCacheItem localCacheItem, String dataId, String encryptedDataKey, String encryptedContent) {
|
||||
String encryptedContentMd5 = MD5Utils.md5Hex(encryptedContent, ENCODE_UTF8);
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX) || dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)) {
|
||||
return !StringUtils.isBlank(localCacheItem.getEncryptedDataKey())
|
||||
&& !StringUtils.isBlank(localCacheItem.getEncryptedContentMD5())
|
||||
&& !StringUtils.isBlank(localCacheItem.getPlainDataKey())
|
||||
&& StringUtils.equals(localCacheItem.getEncryptedDataKey(), encryptedDataKey)
|
||||
&& StringUtils.equals(localCacheItem.getEncryptedContentMD5(), encryptedContentMd5);
|
||||
} else if (dataId.startsWith(CIPHER_PREFIX)) {
|
||||
return !StringUtils.isBlank(localCacheItem.getEncryptedContentMD5())
|
||||
&& !StringUtils.isBlank(localCacheItem.getPlainContent())
|
||||
&& StringUtils.equals(localCacheItem.getEncryptedContentMD5(), encryptedContentMd5);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String readFileToString(String filePath) {
|
||||
File file = getFileByPath(filePath);
|
||||
if (file == null || !file.exists()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
byte[] fileContent = Files.readAllBytes(path);
|
||||
return new String(fileContent, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getFileByPath(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
String path = AliyunConfigFilter.class.getClassLoader().getResource("").getPath();
|
||||
if (!(file = new File(path + filePath)).exists()) {
|
||||
path = Paths.get(filePath).toAbsolutePath().toString();
|
||||
if (!(file = new File(path)).exists()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public void throwExceptionIfStringBlankWithErrorKey(String s, String groupKey, String errorMsg, String errorKey) throws Exception {
|
||||
if (StringUtils.isBlank(s)) {
|
||||
throw new RuntimeException(String.format(STRING_VALUE_BLANK_ERROR_MSG_FORMAT, groupKey, errorMsg, errorKey)
|
||||
+ "For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DataKey {
|
||||
|
||||
private String plainDataKey;
|
||||
|
||||
private String encryptedDataKey;
|
||||
|
||||
public String getPlainDataKey() {
|
||||
return plainDataKey;
|
||||
}
|
||||
|
||||
public void setPlainDataKey(String plainDataKey) {
|
||||
this.plainDataKey = plainDataKey;
|
||||
}
|
||||
|
||||
public String getEncryptedDataKey() {
|
||||
return encryptedDataKey;
|
||||
}
|
||||
|
||||
public void setEncryptedDataKey(String encryptedDataKey) {
|
||||
this.encryptedDataKey = encryptedDataKey;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.DEFAULT_KMS_LOCAL_CACHE_MAX_SIZE;
|
||||
|
||||
/**
|
||||
* @author rong
|
||||
*/
|
||||
public class KmsLocalCache {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KmsLocalCache.class);
|
||||
|
||||
private final Cache<String, LocalCacheItem> encryptedContentCache;
|
||||
|
||||
KmsLocalCache(Properties properties) {
|
||||
int cacheSize = KmsUtils.parsePropertyValue(properties,
|
||||
AliyunConst.NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_SIZE, DEFAULT_KMS_LOCAL_CACHE_MAX_SIZE);
|
||||
int afterAccessDurationSeconds = KmsUtils.parsePropertyValue(properties,
|
||||
AliyunConst.NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_AFTER_ACCESS_DURATION, AliyunConst.DEFAULT_KMS_LOCAL_CACHE_AFTER_ACCESS_DURATION_SECONDS);
|
||||
int afterWriteDurationSeconds = KmsUtils.parsePropertyValue(properties,
|
||||
AliyunConst.NACOS_CONFIG_ENCRYPTION_KMS_LOCAL_CACHE_AFTER_WRITE_DURATION, AliyunConst.DEFAULT_KMS_LOCAL_CACHE_AFTER_WRITE_DURATION_SECONDS);
|
||||
encryptedContentCache = CacheBuilder.newBuilder().maximumSize(cacheSize)
|
||||
.expireAfterAccess(afterAccessDurationSeconds, TimeUnit.SECONDS)
|
||||
.expireAfterWrite(afterWriteDurationSeconds, TimeUnit.SECONDS).build();
|
||||
}
|
||||
|
||||
public LocalCacheItem get(String key) {
|
||||
if (StringUtils.isBlank(key)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return encryptedContentCache.getIfPresent(key);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("get encrypted content from local cache failed, key: {}", key, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void put(String key, LocalCacheItem localCacheItem) {
|
||||
if (StringUtils.isBlank(key) || localCacheItem == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
encryptedContentCache.put(key, localCacheItem);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("put encrypted content to local cache failed, key: {}", key, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
if (StringUtils.isBlank(key)) {
|
||||
return;
|
||||
}
|
||||
this.encryptedContentCache.invalidate(key);
|
||||
}
|
||||
|
||||
public static class LocalCacheItem {
|
||||
private final String encryptedDataKey;
|
||||
|
||||
private final String encryptedContent;
|
||||
|
||||
private final String encryptedContentMD5;
|
||||
|
||||
private final String plainDataKey;
|
||||
|
||||
private final String plainContent;
|
||||
|
||||
public LocalCacheItem(String encryptedDataKey, String encryptedContent, String plainDataKey) {
|
||||
this.encryptedDataKey = encryptedDataKey;
|
||||
this.plainDataKey = plainDataKey;
|
||||
this.encryptedContent = null;
|
||||
this.encryptedContentMD5 = MD5Utils.md5Hex(encryptedContent, AliyunConst.ENCODE_UTF8);
|
||||
this.plainContent = null;
|
||||
}
|
||||
|
||||
public LocalCacheItem(String encryptedContent, String plainContent) {
|
||||
this.encryptedDataKey = null;
|
||||
this.plainDataKey = null;
|
||||
this.encryptedContent = null;
|
||||
this.encryptedContentMD5 = MD5Utils.md5Hex(encryptedContent, AliyunConst.ENCODE_UTF8);
|
||||
this.plainContent = plainContent;
|
||||
}
|
||||
|
||||
public String getEncryptedDataKey() {
|
||||
return encryptedDataKey;
|
||||
}
|
||||
|
||||
public String getEncryptedContent() {
|
||||
return encryptedContent;
|
||||
}
|
||||
|
||||
public String getPlainDataKey() {
|
||||
return plainDataKey;
|
||||
}
|
||||
|
||||
public String getPlainContent() {
|
||||
return plainContent;
|
||||
}
|
||||
|
||||
public String getEncryptedContentMD5() {
|
||||
return encryptedContentMD5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocalCacheItem{" + "encryptedDataKey='" + encryptedDataKey + '\'' + ", encryptedContent='"
|
||||
+ encryptedContent + '\'' + ", encryptedContentMD5='" + encryptedContentMD5 + '\''
|
||||
+ ", plainDataKey='" + plainDataKey + '\'' + ", plainContent='" + plainContent + '\'' + '}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_128_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_256_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.KMS_KEY_SPEC_AES_128;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.KMS_KEY_SPEC_AES_256;
|
||||
|
||||
/**
|
||||
* @author rong
|
||||
*/
|
||||
public class KmsUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KmsUtils.class);
|
||||
|
||||
/**
|
||||
* KMS限流返回错误码
|
||||
*/
|
||||
public final static String REJECTED_THROTTLING = "Rejected.Throttling";
|
||||
|
||||
/**
|
||||
* KMS服务不可用返回错误码
|
||||
*/
|
||||
public final static String SERVICE_UNAVAILABLE_TEMPORARY = "ServiceUnavailableTemporary";
|
||||
|
||||
/**
|
||||
* KMS服务内部错误返回错误码
|
||||
*/
|
||||
public final static String INTERNAL_FAILURE = "InternalFailure";
|
||||
|
||||
/**
|
||||
* KMS服务Socket连接超时错误码
|
||||
*/
|
||||
public final static String SDK_READ_TIMEOUT = "SDK.ReadTimeout";
|
||||
|
||||
/**
|
||||
* KMS服务无法连接错误码
|
||||
*/
|
||||
public final static String SDK_SERVER_UNREACHABLE = "SDK.ServerUnreachable";
|
||||
|
||||
/**
|
||||
* 根据Client异常判断是否进行规避重试
|
||||
*
|
||||
* @param e 指定Client异常
|
||||
* @return
|
||||
*/
|
||||
public static boolean judgeNeedBackoff(ClientException e) {
|
||||
return REJECTED_THROTTLING.equals(e.getErrCode()) || SERVICE_UNAVAILABLE_TEMPORARY.equals(e.getErrCode())
|
||||
|| INTERNAL_FAILURE.equals(e.getErrCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Client异常判断是否进行容灾重试
|
||||
*
|
||||
* @param e 指定Client异常
|
||||
* @return
|
||||
*/
|
||||
public static boolean judgeNeedRecoveryException(ClientException e) {
|
||||
return SDK_READ_TIMEOUT.equals(e.getErrCode()) || SDK_SERVER_UNREACHABLE.equals(e.getErrCode())
|
||||
|| judgeNeedBackoff(e);
|
||||
}
|
||||
|
||||
public static int parsePropertyValue(Properties properties, String propertyName, int defaultValueInt) {
|
||||
String propertyValueString = properties.getProperty(propertyName, System.getProperty(propertyName, System.getenv(propertyName)));
|
||||
int resultValue = defaultValueInt;
|
||||
if (!StringUtils.isBlank(propertyValueString)) {
|
||||
try {
|
||||
resultValue = Integer.parseInt(propertyValueString);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("parse {} failed: {}\n. use default value {}.", propertyName, e.getMessage(),
|
||||
defaultValueInt);
|
||||
}
|
||||
}
|
||||
return resultValue;
|
||||
}
|
||||
|
||||
public static boolean parsePropertyValue(Properties properties, String propertyName, boolean defaultValueInt) {
|
||||
String propertyValueString = properties.getProperty(propertyName, System.getProperty(propertyName, System.getenv(propertyName)));
|
||||
boolean resultValue = defaultValueInt;
|
||||
if (!StringUtils.isBlank(propertyValueString)) {
|
||||
try {
|
||||
resultValue = Boolean.parseBoolean(propertyValueString);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("parse {} failed: {}\n. use default value {}.", propertyName, e.getMessage(),
|
||||
defaultValueInt);
|
||||
}
|
||||
}
|
||||
return resultValue;
|
||||
}
|
||||
|
||||
public static String getKeySpecByDataIdPrefix(String dataId) {
|
||||
if (dataId.startsWith(CIPHER_KMS_AES_128_PREFIX)) {
|
||||
return KMS_KEY_SPEC_AES_128;
|
||||
} else if (dataId.startsWith(CIPHER_KMS_AES_256_PREFIX)){
|
||||
return KMS_KEY_SPEC_AES_256;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* MD5 util.
|
||||
*
|
||||
* @author nacos
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class MD5Utils {
|
||||
|
||||
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
|
||||
'e', 'f'};
|
||||
|
||||
private static final ThreadLocal<MessageDigest> MESSAGE_DIGEST_LOCAL = new ThreadLocal<MessageDigest>() {
|
||||
@Override
|
||||
protected MessageDigest initialValue() {
|
||||
try {
|
||||
return MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate MD5 hex string.
|
||||
*
|
||||
* @param bytes byte arrays
|
||||
* @return MD5 hex string of input
|
||||
* @throws NoSuchAlgorithmException if can't load md5 digest spi.
|
||||
*/
|
||||
public static String md5Hex(byte[] bytes) throws NoSuchAlgorithmException {
|
||||
try {
|
||||
MessageDigest messageDigest = MESSAGE_DIGEST_LOCAL.get();
|
||||
if (messageDigest != null) {
|
||||
return encodeHexString(messageDigest.digest(bytes));
|
||||
}
|
||||
throw new NoSuchAlgorithmException("MessageDigest get MD5 instance error");
|
||||
} finally {
|
||||
MESSAGE_DIGEST_LOCAL.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate MD5 hex string with encode charset.
|
||||
*
|
||||
* @param value value
|
||||
* @param encode encode charset of input
|
||||
* @return MD5 hex string of input
|
||||
*/
|
||||
public static String md5Hex(String value, String encode) {
|
||||
try {
|
||||
return md5Hex(value.getBytes(encode));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a byte array into a visible string.
|
||||
*/
|
||||
public static String encodeHexString(byte[] bytes) {
|
||||
int l = bytes.length;
|
||||
|
||||
char[] out = new char[l << 1];
|
||||
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = DIGITS_LOWER[(0xF0 & bytes[i]) >>> 4];
|
||||
out[j++] = DIGITS_LOWER[0x0F & bytes[i]];
|
||||
}
|
||||
|
||||
return new String(out);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.provider.AccessKeyCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.CredentialsUriKmsCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.EcsRamRoleKmsCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.KmsCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.OidcRoleArnKmsCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.RamRoleArnKmsCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.provider.StsTokenKmsCredentialsProvider;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.kms20160120.Client;
|
||||
import com.aliyun.kms20160120.models.DecryptRequest;
|
||||
import com.aliyun.kms20160120.models.DescribeKeyRequest;
|
||||
import com.aliyun.kms20160120.models.DescribeKeyResponse;
|
||||
import com.aliyun.kms20160120.models.EncryptRequest;
|
||||
import com.aliyun.kms20160120.models.GenerateDataKeyRequest;
|
||||
import com.aliyun.kms20160120.models.GenerateDataKeyResponseBody;
|
||||
import com.aliyun.kms20160120.models.SetDeletionProtectionRequest;
|
||||
import com.aliyun.teaopenapi.models.Config;
|
||||
import com.aliyun.teautil.models.RuntimeOptions;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.KEY_ID;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.KMS_REGION_ID;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.REGION_ID;
|
||||
|
||||
public class RamKmsEncryptor extends KmsEncryptor{
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RamKmsEncryptor.class);
|
||||
|
||||
private Client kmsClient;
|
||||
|
||||
private String keyId;
|
||||
|
||||
private RuntimeOptions runtimeOptions;
|
||||
|
||||
private Exception localInitException;
|
||||
|
||||
private final Set<String> addedKeys = new HashSet<String>();
|
||||
|
||||
private AsyncProcessor asyncProcessor;
|
||||
|
||||
private final Set<KmsCredentialsProvider> credentialsProviders;
|
||||
|
||||
public RamKmsEncryptor(Properties properties){
|
||||
super(properties);
|
||||
credentialsProviders = new HashSet<>();
|
||||
credentialsProviders.add(new AccessKeyCredentialsProvider());
|
||||
credentialsProviders.add(new StsTokenKmsCredentialsProvider());
|
||||
credentialsProviders.add(new RamRoleArnKmsCredentialsProvider());
|
||||
credentialsProviders.add(new EcsRamRoleKmsCredentialsProvider());
|
||||
credentialsProviders.add(new OidcRoleArnKmsCredentialsProvider());
|
||||
credentialsProviders.add(new CredentialsUriKmsCredentialsProvider());
|
||||
|
||||
try{
|
||||
kmsClient = createClient(properties);
|
||||
}catch (Exception e){
|
||||
localInitException = e;
|
||||
}
|
||||
|
||||
if(localInitException == null){
|
||||
try {
|
||||
asyncProcessor = new AsyncProcessor();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("init async processor failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Client createClient(Properties properties) throws Exception {
|
||||
String regionId = properties.getProperty(REGION_ID, System.getProperty(REGION_ID, System.getenv(REGION_ID)));
|
||||
String kmsRegionId = properties.getProperty(KMS_REGION_ID, System.getProperty(KMS_REGION_ID, System.getenv(KMS_REGION_ID)));
|
||||
if (StringUtils.isBlank(regionId)) {
|
||||
regionId = kmsRegionId;
|
||||
}
|
||||
LOGGER.info("using regionId {}.", regionId);
|
||||
if (StringUtils.isBlank(kmsRegionId)) {
|
||||
kmsRegionId = regionId;
|
||||
}
|
||||
LOGGER.info("using kms regionId {}.", kmsRegionId);
|
||||
|
||||
String kmsEndpoint = properties.getProperty(AliyunConst.KMS_ENDPOINT,
|
||||
System.getProperty(AliyunConst.KMS_ENDPOINT, System.getenv(AliyunConst.KMS_ENDPOINT)));
|
||||
LOGGER.info("using kmsEndpoint {}.", kmsEndpoint);
|
||||
|
||||
Config config = new Config();
|
||||
runtimeOptions = new RuntimeOptions();
|
||||
|
||||
boolean ifAuth = false;
|
||||
com.aliyun.credentials.models.Config credentialConfig = new com.aliyun.credentials.models.Config();
|
||||
for (KmsCredentialsProvider each : credentialsProviders) {
|
||||
if (each.matchProvider(properties)) {
|
||||
LOGGER.info("Match Kms credentials provider: {}", each.getClass().getName());
|
||||
credentialConfig = each.generateCredentialsConfig(properties);
|
||||
ifAuth = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ifAuth){
|
||||
String msg = "Ram Auth Information are not set up yet";
|
||||
LOGGER.error(msg);
|
||||
localInitException = new RuntimeException(msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
com.aliyun.credentials.Client credentialClient = new com.aliyun.credentials.Client(credentialConfig);
|
||||
config.setCredential(credentialClient);
|
||||
|
||||
|
||||
config.setRegionId(kmsRegionId);
|
||||
if(!StringUtils.isBlank(kmsEndpoint)){
|
||||
config.setEndpoint(kmsEndpoint);
|
||||
keyId = properties.getProperty(KEY_ID, System.getProperty(KEY_ID, System.getenv(KEY_ID)));
|
||||
if(StringUtils.isBlank(keyId)){
|
||||
String msg = "keyId is not set up yet, unable to encrypt the configuration.";
|
||||
LOGGER.error(msg);
|
||||
}else{
|
||||
LOGGER.info("using keyId {}.", keyId);
|
||||
}
|
||||
}else{
|
||||
LOGGER.info("kmsEndpoint is not set up yet, KMS V1.0 mode");
|
||||
if (StringUtils.isBlank(kmsRegionId) && StringUtils.isBlank(regionId)) {
|
||||
String errorMsg = "KMS V1.0 mode, region is not set up yet";
|
||||
LOGGER.error(AliyunConst.formatHelpMessage(errorMsg));
|
||||
localInitException = new RuntimeException(errorMsg);
|
||||
return null;
|
||||
}
|
||||
keyId = AliyunConst.KMS_DEFAULT_KEY_ID_VALUE;
|
||||
return new Client(config);
|
||||
}
|
||||
|
||||
String kmsCaFileContent = properties.getProperty(AliyunConst.KMS_CA_FILE_CONTENT,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_CONTENT, System.getenv(AliyunConst.KMS_CA_FILE_CONTENT)));
|
||||
if(StringUtils.isBlank(kmsCaFileContent)){
|
||||
String kmsCaFilePath = properties.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY,
|
||||
System.getProperty(AliyunConst.KMS_CA_FILE_PATH_KEY,
|
||||
System.getenv(AliyunConst.KMS_CA_FILE_PATH_KEY)));
|
||||
if(!StringUtils.isBlank(kmsCaFilePath)){
|
||||
try{
|
||||
kmsCaFileContent = readFileToString(kmsCaFilePath);
|
||||
}catch (Exception e){
|
||||
LOGGER.error("read kms ca file failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.isBlank(kmsCaFileContent)) {
|
||||
LOGGER.info("using {}: {}.", AliyunConst.KMS_CA_FILE_CONTENT, kmsCaFileContent);
|
||||
config.setCa(kmsCaFileContent);
|
||||
} else {
|
||||
runtimeOptions.ignoreSSL=true;
|
||||
}
|
||||
|
||||
String openSSL = properties.getProperty(AliyunConst.OPEN_SSL_KEY,
|
||||
System.getProperty(AliyunConst.OPEN_SSL_KEY, System.getenv(AliyunConst.OPEN_SSL_KEY)));
|
||||
if(!StringUtils.isBlank(openSSL)){
|
||||
if(openSSL.equalsIgnoreCase("false")){
|
||||
LOGGER.info("openSSL is set to false.");
|
||||
runtimeOptions.ignoreSSL = true;
|
||||
} else if (openSSL.equalsIgnoreCase("true")){
|
||||
LOGGER.info("ignoreSSL is set to true.");
|
||||
runtimeOptions.ignoreSSL = false;
|
||||
}
|
||||
}
|
||||
return new Client(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String plainText) throws Exception {
|
||||
AtomicReference<String> resultContent = new AtomicReference<>();
|
||||
final EncryptRequest encReq = new EncryptRequest();
|
||||
encReq.setKeyId(keyId);
|
||||
encReq.setPlaintext(plainText);
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set( kmsClient.encryptWithOptions(encReq, runtimeOptions).getBody().getCiphertextBlob());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (StringUtils.isBlank(resultContent.get())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
return resultContent.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decrypt(String encryptedContent) throws Exception {
|
||||
AtomicReference<String> resultContent = new AtomicReference<>();
|
||||
final DecryptRequest decReq = new DecryptRequest();
|
||||
decReq.setCiphertextBlob(encryptedContent);
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set(kmsClient.decryptWithOptions(decReq, runtimeOptions).getBody().getPlaintext());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (StringUtils.isBlank(resultContent.get())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
return resultContent.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkIfKmsClientIsReady() throws Exception {
|
||||
if (kmsClient == null) {
|
||||
if (localInitException != null) {
|
||||
throw localInitException;
|
||||
} else {
|
||||
throw new RuntimeException("kms client isn't initialized. " +
|
||||
"For more information, please check: " + AliyunConst.MSE_ENCRYPTED_CONFIG_USAGE_DOCUMENT_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void protectKeyId() {
|
||||
if (!addedKeys.contains(keyId)) {
|
||||
synchronized (addedKeys) {
|
||||
if (addedKeys.contains(keyId)) {
|
||||
return;
|
||||
}
|
||||
addedKeys.add(keyId);
|
||||
asyncProcessor.addTack(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (kmsClient == null) {
|
||||
LOGGER.error("kms client hasn't initiated.");
|
||||
return;
|
||||
}
|
||||
DescribeKeyRequest describeKeyRequest = new DescribeKeyRequest();
|
||||
describeKeyRequest.setKeyId(keyId);
|
||||
try {
|
||||
DescribeKeyResponse describeKeyResponse = kmsClient.describeKeyWithOptions(describeKeyRequest, runtimeOptions);
|
||||
if (describeKeyResponse.getBody().getKeyMetadata()!= null) {
|
||||
if (!"Enabled".equals(describeKeyResponse.getBody().getKeyMetadata().getKeyState())) {
|
||||
throw new RuntimeException("Key not available");
|
||||
}
|
||||
String arn = describeKeyResponse.getBody().getKeyMetadata().getArn();
|
||||
LOGGER.info("set deletion protection for keyId[{}], arn[{}]", keyId, arn);
|
||||
|
||||
SetDeletionProtectionRequest setDeletionProtectionRequest = new SetDeletionProtectionRequest();
|
||||
setDeletionProtectionRequest.setProtectedResourceArn(arn);
|
||||
setDeletionProtectionRequest.setEnableDeletionProtection(true);
|
||||
setDeletionProtectionRequest.setDeletionProtectionDescription("key is used by mse");
|
||||
try {
|
||||
kmsClient.setDeletionProtectionWithOptions(setDeletionProtectionRequest, runtimeOptions);
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("set deletion protect failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.warn("keyId meta is null, cannot set key protection");
|
||||
}
|
||||
} catch (ClientException e) {
|
||||
LOGGER.error("describe key failed, keyId: {}.", keyId);
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
addedKeys.remove(keyId);
|
||||
LOGGER.error("execute async task failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataKey generateDataKey(String keySpec) throws Exception {
|
||||
GenerateDataKeyRequest generateDataKeyRequest = new GenerateDataKeyRequest();
|
||||
generateDataKeyRequest.setKeyId(keyId);
|
||||
generateDataKeyRequest.setKeySpec(keySpec);
|
||||
AtomicReference<GenerateDataKeyResponseBody> resultContent = new AtomicReference<>();
|
||||
locallyRunWithRetryTimesAndTimeout(() -> {
|
||||
try {
|
||||
resultContent.set(kmsClient.generateDataKeyWithOptions(generateDataKeyRequest,runtimeOptions).getBody());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (resultContent.get() == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, defaultRetryTimes, defaultTimeoutMilliseconds);
|
||||
DataKey dataKey = new DataKey();
|
||||
dataKey.setEncryptedDataKey(resultContent.get().getCiphertextBlob());
|
||||
dataKey.setPlainDataKey(resultContent.get().getPlaintext());
|
||||
return dataKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkKeyId() throws Exception {
|
||||
throwExceptionIfStringBlankWithErrorKey(keyId, "", "keyId is not set.", KEY_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
asyncProcessor.shutdown();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.aliyun.auth.injector.ConfigExtensionResourceInjector;
|
||||
import com.alibaba.nacos.client.aliyun.auth.injector.NamingExtensionResourceInjector;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.AutoRotateCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.CredentialsUriCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.ExtensionCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.OidcRoleArnCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.RamRoleArnCredentialsProvider;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.StsTokenCredentialsProvider;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.AbstractResourceInjector;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import com.alibaba.nacos.plugin.auth.constant.SignType;
|
||||
import com.alibaba.nacos.plugin.auth.spi.client.AbstractClientAuthService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Nacos ClientAuthServiceImpl for aliyun extension auth way.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class AliyunExtensionClientAuthServiceImpl extends AbstractClientAuthService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AliyunExtensionClientAuthServiceImpl.class);
|
||||
|
||||
private final Set<ExtensionCredentialsProvider> credentialsProviders;
|
||||
|
||||
private final Map<String, AbstractResourceInjector> resourceInjectors;
|
||||
|
||||
private ExtensionCredentialsProvider matchedProvider;
|
||||
|
||||
public AliyunExtensionClientAuthServiceImpl() {
|
||||
this.credentialsProviders = new HashSet<>();
|
||||
this.credentialsProviders.add(new CredentialsUriCredentialsProvider());
|
||||
this.credentialsProviders.add(new StsTokenCredentialsProvider());
|
||||
this.credentialsProviders.add(new OidcRoleArnCredentialsProvider());
|
||||
this.credentialsProviders.add(new RamRoleArnCredentialsProvider());
|
||||
this.credentialsProviders.add(new AutoRotateCredentialsProvider());
|
||||
this.resourceInjectors = new HashMap<>();
|
||||
this.resourceInjectors.put(SignType.NAMING, new NamingExtensionResourceInjector());
|
||||
this.resourceInjectors.put(SignType.CONFIG, new ConfigExtensionResourceInjector());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean login(Properties properties) {
|
||||
for (ExtensionCredentialsProvider each : credentialsProviders) {
|
||||
if (each.matchProvider(properties)) {
|
||||
if (null == matchedProvider) {
|
||||
LOGGER.info("Match credentials provider: {}", each.getClass().getName());
|
||||
}
|
||||
matchedProvider = each;
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (null == matchedProvider) {
|
||||
return false;
|
||||
}
|
||||
matchedProvider.init(properties);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Init for Credential Provider {} failed.", matchedProvider.getClass().getName(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginIdentityContext getLoginIdentityContext(RequestResource resource) {
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
if (null == matchedProvider) {
|
||||
return result;
|
||||
}
|
||||
ExtensionRamContext ramContext = matchedProvider.getCredentialsForNacosClient();
|
||||
if (!ramContext.validate() || notFountInjector(resource.getType())) {
|
||||
return result;
|
||||
}
|
||||
resourceInjectors.get(resource.getType()).doInject(resource, ramContext, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean notFountInjector(String type) {
|
||||
if (!resourceInjectors.containsKey(type)) {
|
||||
LOGGER.warn("Injector for type {} not found, will use default ram identity context.", type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
if (null != matchedProvider) {
|
||||
matchedProvider.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth;
|
||||
|
||||
/**
|
||||
* Constants for aliyun extension auth.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ExtensionAuthConstants {
|
||||
|
||||
/**
|
||||
* Original signature region id key, added by nacos-client 2.4.0.
|
||||
*/
|
||||
public static final String SIGNATURE_REGION_ID_KEY = "signatureRegionId";
|
||||
|
||||
public static final String SECURITY_TOKEN_HEADER = "Spas-SecurityToken";
|
||||
|
||||
public static final String V4_SIGNATURE_UTIL_CLASS = "com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil";
|
||||
|
||||
/**
|
||||
* Nacos properties keys
|
||||
*/
|
||||
private static final String PREFIX = "alibabaCloud";
|
||||
|
||||
public static final String SECRET_NAME_KEY = PREFIX + "SecretName";
|
||||
|
||||
public static final String CREDENTIALS_URI_KEY = PREFIX + "CredentialsUri";
|
||||
|
||||
public static final String OIDC_TOKEN_FILE_PATH_KEY = PREFIX + "OidcTokenFile";
|
||||
|
||||
public static final String OIDC_PROVIDER_ARN_KEY = PREFIX + "OidcProviderArn";
|
||||
|
||||
public static final String ROLE_SESSION_EXPIRATION_KEY = PREFIX + "RoleSessionExpiration";
|
||||
|
||||
public static final String POLICY_KEY = PREFIX + "Policy";
|
||||
|
||||
public static final String ROLE_SESSION_NAME_KEY = PREFIX + "RoleSessionName";
|
||||
|
||||
public static final String ROLE_ARN_KEY = PREFIX + "RoleArn";
|
||||
|
||||
public static final String SECURITY_TOKEN_KEY = PREFIX + "SecurityToken";
|
||||
|
||||
public static final String ACCESS_KEY_SECRET_KEY = PREFIX + "AccessKeySecret";
|
||||
|
||||
public static final String ACCESS_KEY_ID_KEY = PREFIX + "AccessKeyId";
|
||||
|
||||
/**
|
||||
* Env properties keys.
|
||||
*/
|
||||
private static final String ENV_PREFIX = "ALIBABA_CLOUD_";
|
||||
|
||||
public static final String ENV_ACCESS_KEY_ID_KEY = ENV_PREFIX + "ACCESS_KEY_ID";
|
||||
|
||||
public static final String ENV_ACCESS_KEY_SECRET_KEY = ENV_PREFIX + "ACCESS_KEY_SECRET";
|
||||
|
||||
public static final String ENV_SECURITY_TOKEN_KEY = ENV_PREFIX + "SECURITY_TOKEN";
|
||||
|
||||
public static final String ENV_SIGNATURE_REGION_ID_KEY = ENV_PREFIX + "SIGNATURE_REGION_ID";
|
||||
|
||||
public static final String ENV_ROLE_ARN_KEY = ENV_PREFIX + "ROLE_ARN";
|
||||
|
||||
public static final String ENV_ROLE_SESSION_NAME_KEY = ENV_PREFIX + "ROLE_SESSION_NAME";
|
||||
|
||||
public static final String ENV_POLICY_KEY = ENV_PREFIX + "POLICY";
|
||||
|
||||
public static final String ENV_ROLE_SESSION_EXPIRATION_KEY = ENV_PREFIX + "ROLE_SESSION_EXPIRATION";
|
||||
|
||||
public static final String ENV_OIDC_PROVIDER_ARN_KEY = ENV_PREFIX + "OIDC_PROVIDER_ARN";
|
||||
|
||||
public static final String ENV_OIDC_TOKEN_FILE_KEY = ENV_PREFIX + "OIDC_TOKEN_FILE";
|
||||
|
||||
public static final String ENV_CREDENTIALS_URI_KEY = ENV_PREFIX + "CREDENTIALS_URI";
|
||||
|
||||
public static final String ENV_SECRET_NAME_KEY = ENV_PREFIX + "SECRET_NAME";
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth;
|
||||
|
||||
/**
|
||||
* Aliyun Extension Auth Property Key.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public enum ExtensionAuthPropertyKey {
|
||||
|
||||
ACCESS_KEY_ID(ExtensionAuthConstants.ACCESS_KEY_ID_KEY, ExtensionAuthConstants.ENV_ACCESS_KEY_ID_KEY),
|
||||
|
||||
ACCESS_KEY_SECRET(ExtensionAuthConstants.ACCESS_KEY_SECRET_KEY, ExtensionAuthConstants.ENV_ACCESS_KEY_SECRET_KEY),
|
||||
|
||||
SECURITY_TOKEN(ExtensionAuthConstants.SECURITY_TOKEN_KEY, ExtensionAuthConstants.ENV_SECURITY_TOKEN_KEY),
|
||||
|
||||
SIGNATURE_REGION_ID(ExtensionAuthConstants.SIGNATURE_REGION_ID_KEY,
|
||||
ExtensionAuthConstants.ENV_SIGNATURE_REGION_ID_KEY),
|
||||
|
||||
ROLE_ARN(ExtensionAuthConstants.ROLE_ARN_KEY, ExtensionAuthConstants.ENV_ROLE_ARN_KEY),
|
||||
|
||||
ROLE_SESSION_NAME(ExtensionAuthConstants.ROLE_SESSION_NAME_KEY, ExtensionAuthConstants.ENV_ROLE_SESSION_NAME_KEY),
|
||||
|
||||
POLICY(ExtensionAuthConstants.POLICY_KEY, ExtensionAuthConstants.ENV_POLICY_KEY),
|
||||
|
||||
ROLE_SESSION_EXPIRATION(ExtensionAuthConstants.ROLE_SESSION_EXPIRATION_KEY,
|
||||
ExtensionAuthConstants.ENV_ROLE_SESSION_EXPIRATION_KEY),
|
||||
|
||||
OIDC_PROVIDER_ARN(ExtensionAuthConstants.OIDC_PROVIDER_ARN_KEY, ExtensionAuthConstants.ENV_OIDC_PROVIDER_ARN_KEY),
|
||||
|
||||
OIDC_TOKEN_FILE_PATH(ExtensionAuthConstants.OIDC_TOKEN_FILE_PATH_KEY,
|
||||
ExtensionAuthConstants.ENV_OIDC_TOKEN_FILE_KEY),
|
||||
|
||||
CREDENTIALS_URI(ExtensionAuthConstants.CREDENTIALS_URI_KEY, ExtensionAuthConstants.ENV_CREDENTIALS_URI_KEY),
|
||||
|
||||
SECRET_NAME(ExtensionAuthConstants.SECRET_NAME_KEY, ExtensionAuthConstants.ENV_SECRET_NAME_KEY);
|
||||
|
||||
private final String key;
|
||||
|
||||
private final String envKey;
|
||||
|
||||
ExtensionAuthPropertyKey(String key, String envKey) {
|
||||
this.key = key;
|
||||
this.envKey = envKey;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getEnvKey() {
|
||||
return envKey;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Extension ram context.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ExtensionRamContext extends RamContext {
|
||||
|
||||
private String securityToken;
|
||||
|
||||
/**
|
||||
* For adapter nacos-client 2.4.0 v4 signature.
|
||||
*/
|
||||
private String extensionSignatureRegionId;
|
||||
|
||||
private boolean ephemeralAccessKeyId = true;
|
||||
|
||||
public String getSecurityToken() {
|
||||
return securityToken;
|
||||
}
|
||||
|
||||
public void setSecurityToken(String securityToken) {
|
||||
this.securityToken = securityToken;
|
||||
}
|
||||
|
||||
public String getExtensionSignatureRegionId() {
|
||||
return extensionSignatureRegionId;
|
||||
}
|
||||
|
||||
public void setExtensionSignatureRegionId(String extensionSignatureRegionId) {
|
||||
this.extensionSignatureRegionId = extensionSignatureRegionId;
|
||||
}
|
||||
|
||||
public boolean isEphemeralAccessKeyId() {
|
||||
return ephemeralAccessKeyId;
|
||||
}
|
||||
|
||||
public void setEphemeralAccessKeyId(boolean ephemeralAccessKeyId) {
|
||||
this.ephemeralAccessKeyId = ephemeralAccessKeyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
if (ephemeralAccessKeyId && StringUtils.isEmpty(securityToken)) {
|
||||
return false;
|
||||
}
|
||||
return StringUtils.isNotBlank(super.getAccessKey()) && StringUtils.isNotBlank(super.getSecretKey());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthConstants;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.RamConstants;
|
||||
import com.alibaba.nacos.client.auth.ram.RamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.injector.AbstractResourceInjector;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.CalculateV4SigningKeyUtil;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Abstract resource injector for extension.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public abstract class AbstractExtensionResourceInjector extends AbstractResourceInjector {
|
||||
|
||||
private boolean supportV4signature;
|
||||
|
||||
protected AbstractExtensionResourceInjector() {
|
||||
try {
|
||||
Class.forName(ExtensionAuthConstants.V4_SIGNATURE_UTIL_CLASS);
|
||||
supportV4signature = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
supportV4signature = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doInject(RequestResource resource, RamContext context, LoginIdentityContext result) {
|
||||
ExtensionRamContext ramContext = (ExtensionRamContext) context;
|
||||
result.setParameter(getAccessKeyHeaderKey(), ramContext.getAccessKey());
|
||||
if (ramContext.isEphemeralAccessKeyId()) {
|
||||
result.setParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER, ramContext.getSecurityToken());
|
||||
}
|
||||
String secretKey = trySignatureWithV4(ramContext, result);
|
||||
Map<String, String> signatures = calculateSignature(resource, secretKey, ramContext);
|
||||
result.setParameters(signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to sign with v4 signature.
|
||||
*
|
||||
* @param context ram context with extension
|
||||
* @param result login identity context
|
||||
* @return actual secret key, if not support v4 signature or not config signature region, return secret key directly,otherwise return v4 signature.
|
||||
*/
|
||||
protected String trySignatureWithV4(ExtensionRamContext context, LoginIdentityContext result) {
|
||||
if (!supportV4signature || StringUtils.isEmpty(context.getExtensionSignatureRegionId())) {
|
||||
return context.getSecretKey();
|
||||
}
|
||||
result.setParameter(RamConstants.SIGNATURE_VERSION, RamConstants.V4);
|
||||
return CalculateV4SigningKeyUtil.finalSigningKeyStringWithDefaultInfo(context.getSecretKey(),
|
||||
context.getExtensionSignatureRegionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access key header key according to child module.
|
||||
*
|
||||
* @return access key header key.
|
||||
*/
|
||||
protected abstract String getAccessKeyHeaderKey();
|
||||
|
||||
/**
|
||||
* Calculate signature according to child module.
|
||||
*
|
||||
* @param resource request resource
|
||||
* @param actualSecretKey actual secret key, if support v4 and config signature region, it's v4 key, otherwise it's original key.
|
||||
* @param ramContext extension ram context
|
||||
* @return signature item maps.
|
||||
*/
|
||||
protected abstract Map<String, String> calculateSignature(RequestResource resource, String actualSecretKey,
|
||||
ExtensionRamContext ramContext);
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SpasAdapter;
|
||||
import com.alibaba.nacos.client.utils.LogUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Ram resource injector with aliyun extension for nacos config module.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class ConfigExtensionResourceInjector extends AbstractExtensionResourceInjector {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.logger(ConfigExtensionResourceInjector.class);
|
||||
|
||||
private static final String ACCESS_KEY_HEADER = "Spas-AccessKey";
|
||||
|
||||
private static final String DEFAULT_RESOURCE = "";
|
||||
|
||||
@Override
|
||||
protected String getAccessKeyHeaderKey() {
|
||||
return ACCESS_KEY_HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, String> calculateSignature(RequestResource resource, String actualSecretKey,
|
||||
ExtensionRamContext ramContext) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
try {
|
||||
String resourceString = getResource(resource.getNamespace(), resource.getGroup());
|
||||
Map<String, String> signHeaders = SpasAdapter.getSignHeaders(resourceString, actualSecretKey);
|
||||
result.putAll(signHeaders);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Calculate auth signature for config failed.", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getResource(String tenant, String group) {
|
||||
if (StringUtils.isNotBlank(tenant) && StringUtils.isNotBlank(group)) {
|
||||
return tenant + "+" + group;
|
||||
}
|
||||
if (StringUtils.isNotBlank(group)) {
|
||||
return group;
|
||||
}
|
||||
if (StringUtils.isNotBlank(tenant)) {
|
||||
return tenant;
|
||||
}
|
||||
return DEFAULT_RESOURCE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.naming.utils.NamingUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SignUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
|
||||
|
||||
/**
|
||||
* Ram resource injector with aliyun extension for nacos naming module.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class NamingExtensionResourceInjector extends AbstractExtensionResourceInjector {
|
||||
|
||||
private static final String SIGNATURE_FILED = "signature";
|
||||
|
||||
private static final String DATA_FILED = "data";
|
||||
|
||||
private static final String AK_FILED = "ak";
|
||||
|
||||
@Override
|
||||
protected String getAccessKeyHeaderKey() {
|
||||
return AK_FILED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, String> calculateSignature(RequestResource resource, String actualSecretKey,
|
||||
ExtensionRamContext ramContext) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
try {
|
||||
String signData = getSignData(getGroupedServiceName(resource));
|
||||
String signature = SignUtil.sign(signData, actualSecretKey);
|
||||
result.put(SIGNATURE_FILED, signature);
|
||||
result.put(DATA_FILED, signData);
|
||||
} catch (Exception e) {
|
||||
NAMING_LOGGER.warn("Calculate auth signature for naming failed.", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getGroupedServiceName(RequestResource resource) {
|
||||
if (resource.getResource().contains(Constants.SERVICE_INFO_SPLITER) || StringUtils
|
||||
.isBlank(resource.getGroup())) {
|
||||
return resource.getResource();
|
||||
}
|
||||
return NamingUtils.getGroupedNameOptional(resource.getResource(), resource.getGroup());
|
||||
}
|
||||
|
||||
private String getSignData(String serviceName) {
|
||||
return StringUtils.isNotEmpty(serviceName) ? System.currentTimeMillis() + Constants.SERVICE_INFO_SPLITER
|
||||
+ serviceName : String.valueOf(System.currentTimeMillis());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.aliyun.credentials.Client;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
import com.aliyun.credentials.models.CredentialModel;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Abstract credentials provider by aliyun credentials client.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public abstract class AbstractCredentialClientProvider implements ExtensionCredentialsProvider {
|
||||
|
||||
private Client credentialsClient;
|
||||
|
||||
private String signatureRegionId;
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
synchronized (this) {
|
||||
if (null == credentialsClient) {
|
||||
Config credentialsConfig = generateCredentialsConfig(properties);
|
||||
credentialsClient = new Client(credentialsConfig);
|
||||
}
|
||||
}
|
||||
signatureRegionId = getSignatureRegionId(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate credentials config by properties.
|
||||
*
|
||||
* @param properties nacos client properties which same as parameters {@link #matchProvider(Properties)}
|
||||
* @return credentials config
|
||||
*/
|
||||
protected abstract Config generateCredentialsConfig(Properties properties);
|
||||
|
||||
@Override
|
||||
public ExtensionRamContext getCredentialsForNacosClient() {
|
||||
ExtensionRamContext ramContext = new ExtensionRamContext();
|
||||
if (null != credentialsClient) {
|
||||
CredentialModel credentialModel = credentialsClient.getCredential();
|
||||
ramContext.setAccessKey(credentialModel.getAccessKeyId());
|
||||
ramContext.setSecretKey(credentialModel.getAccessKeySecret());
|
||||
ramContext.setSecurityToken(credentialModel.getSecurityToken());
|
||||
}
|
||||
ramContext.setExtensionSignatureRegionId(signatureRegionId);
|
||||
return ramContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
if (null != credentialsClient) {
|
||||
doCloseCredentialsClient();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aliyun Credentials Client don't include close or shutdown method, but it might be with session or Thread Pool.
|
||||
*
|
||||
* <p>
|
||||
* For invalid leak of connection and thread pool, template use reflect to close inner resource.
|
||||
* If new version provide close method, will use it.
|
||||
* </p>
|
||||
*/
|
||||
private void doCloseCredentialsClient() {
|
||||
try {
|
||||
Field field = credentialsClient.getClass().getDeclaredField("credentialsProvider");
|
||||
field.setAccessible(true);
|
||||
Object innerProvider = field.get(credentialsClient);
|
||||
if (innerProvider instanceof AutoCloseable) {
|
||||
((AutoCloseable) innerProvider).close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
protected Config injectCommonBasicConfig(Properties properties, Config config) {
|
||||
config.setAccessKeyId(getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_ID));
|
||||
config.setAccessKeySecret(getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_SECRET));
|
||||
String securityToken = getNacosProperties(properties, ExtensionAuthPropertyKey.SECURITY_TOKEN);
|
||||
if (!StringUtils.isEmpty(securityToken)) {
|
||||
config.setSecurityToken(securityToken);
|
||||
}
|
||||
String policy = getNacosProperties(properties, ExtensionAuthPropertyKey.POLICY);
|
||||
if (!StringUtils.isEmpty(policy)) {
|
||||
config.setPolicy(policy);
|
||||
}
|
||||
String roleSessionExpiration = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_EXPIRATION);
|
||||
if (!StringUtils.isEmpty(roleSessionExpiration)) {
|
||||
config.setRoleSessionExpiration(Integer.parseInt(roleSessionExpiration));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.common.utils.JacksonUtils;
|
||||
import com.aliyuncs.kms.secretsmanager.client.SecretCacheClient;
|
||||
import com.aliyuncs.kms.secretsmanager.client.SecretCacheClientBuilder;
|
||||
import com.aliyuncs.kms.secretsmanager.client.exception.CacheSecretException;
|
||||
import com.aliyuncs.kms.secretsmanager.client.model.SecretInfo;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun credentials provider for auto rotate access key by KMS.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class AutoRotateCredentialsProvider implements ExtensionCredentialsProvider {
|
||||
|
||||
private SecretCacheClient client;
|
||||
|
||||
private String secretName;
|
||||
|
||||
private String signatureRegionId;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
return !StringUtils.isEmpty(getNacosProperties(properties, ExtensionAuthPropertyKey.SECRET_NAME));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
secretName = getNacosProperties(properties, ExtensionAuthPropertyKey.SECRET_NAME);
|
||||
signatureRegionId = getSignatureRegionId(properties);
|
||||
buildSecretClient();
|
||||
}
|
||||
|
||||
private synchronized void buildSecretClient() {
|
||||
try {
|
||||
if (null == client) {
|
||||
client = SecretCacheClientBuilder.newClient();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new NacosRuntimeException(23000, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionRamContext getCredentialsForNacosClient() {
|
||||
ExtensionRamContext result = new ExtensionRamContext();
|
||||
result.setEphemeralAccessKeyId(false);
|
||||
if (null == client) {
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
SecretInfo secretInfo = client.getSecretInfo(secretName);
|
||||
JsonNode jsonNode = JacksonUtils.toObj(secretInfo.getSecretValue());
|
||||
result.setAccessKey(jsonNode.get("AccessKeyId").asText());
|
||||
result.setSecretKey(jsonNode.get("AccessKeySecret").asText());
|
||||
result.setExtensionSignatureRegionId(signatureRegionId);
|
||||
} catch (CacheSecretException e) {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun credentials provider for custom credential uri type.
|
||||
*
|
||||
* <p>
|
||||
* This credentials provider is supported to get credential from custom credential uri.
|
||||
* The custom uri should be in the following format: <a href="http://local_or_remote_uri/">http://local_or_remote_uri/</a>
|
||||
* And the custom uri should response with code {@code 200} and with body json format:
|
||||
* <code>
|
||||
* {
|
||||
* "Code": "Success",
|
||||
* "AccessKeySecret": "AccessKeySecret",
|
||||
* "AccessKeyId": "AccessKeyId",
|
||||
* "Expiration": "2021-09-26T03:46:38Z",
|
||||
* "SecurityToken": "SecurityToken"
|
||||
* }
|
||||
* </code>
|
||||
* </p>
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class CredentialsUriCredentialsProvider extends AbstractCredentialClientProvider {
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
String credentialsURI = getNacosProperties(properties, ExtensionAuthPropertyKey.CREDENTIALS_URI);
|
||||
return !StringUtils.isEmpty(credentialsURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config generateCredentialsConfig(Properties properties) {
|
||||
Config config = new Config();
|
||||
config.setType("credentials_uri");
|
||||
config.setCredentialsUri(getNacosProperties(properties, ExtensionAuthPropertyKey.CREDENTIALS_URI));
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.common.lifecycle.Closeable;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun CredentialsProvider for nacos extension plugin.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public interface ExtensionCredentialsProvider extends Closeable {
|
||||
|
||||
/**
|
||||
* The properties are generated by {@link com.alibaba.nacos.client.env.NacosClientProperties}, which loaded from init Properties, JVM and Env.
|
||||
*
|
||||
* @param properties nacos client properties
|
||||
* @return {@code true} if match and will use this Credentials Provider, {@code false} otherwise.
|
||||
*/
|
||||
boolean matchProvider(Properties properties);
|
||||
|
||||
/**
|
||||
* Initialize the provider.
|
||||
*
|
||||
* @param properties nacos client properties which same as parameters {@link #matchProvider(Properties)}
|
||||
*/
|
||||
void init(Properties properties);
|
||||
|
||||
/**
|
||||
* Get Aliyun Credentials and transform to Nacos Credentials.
|
||||
*
|
||||
* @return Nacos Credentials as {@link ExtensionRamContext}
|
||||
*/
|
||||
ExtensionRamContext getCredentialsForNacosClient();
|
||||
|
||||
default String getNacosProperties(Properties properties, ExtensionAuthPropertyKey key) {
|
||||
String result = properties.getProperty(key.getKey());
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
result = properties.getProperty(key.getEnvKey());
|
||||
}
|
||||
// For Adapt 2.1.X, in 2.1.X version, NacosClientProperties not finished all replaced, so properties don't include env.
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
result = System.getenv(key.getEnvKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
default String getSignatureRegionId(Properties properties) {
|
||||
return getNacosProperties(properties, ExtensionAuthPropertyKey.SIGNATURE_REGION_ID);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun CredentialsProvider for OIDC role arn type which most of Kubernetes situation.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class OidcRoleArnCredentialsProvider extends AbstractCredentialClientProvider {
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
String arnRole = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN);
|
||||
String roleSessionName = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME);
|
||||
String oidcProviderArn = getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN);
|
||||
return !StringUtils.isEmpty(arnRole) && !StringUtils.isEmpty(roleSessionName) && !StringUtils.isEmpty(
|
||||
oidcProviderArn);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config generateCredentialsConfig(Properties properties) {
|
||||
Config config = new Config();
|
||||
config.setType("oidc_role_arn");
|
||||
config.setRoleArn(getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN));
|
||||
config.setRoleSessionName(getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME));
|
||||
config.setOidcProviderArn(getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN));
|
||||
config.setOidcTokenFilePath(getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_TOKEN_FILE_PATH));
|
||||
return injectCommonBasicConfig(properties, config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun CredentialsProvider for ram role arn type which most of assume role situation.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class RamRoleArnCredentialsProvider extends AbstractCredentialClientProvider {
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
String arnRole = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN);
|
||||
String roleSessionName = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME);
|
||||
String oidcProviderArn = getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN);
|
||||
return !StringUtils.isEmpty(arnRole) && !StringUtils.isEmpty(roleSessionName) && StringUtils.isEmpty(
|
||||
oidcProviderArn);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config generateCredentialsConfig(Properties properties) {
|
||||
Config config = new Config();
|
||||
config.setType("ram_role_arn");
|
||||
config.setRoleArn(getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN));
|
||||
config.setRoleSessionName(getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME));
|
||||
return injectCommonBasicConfig(properties, config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Aliyun CredentialsProvider for Sts token type which for some untrusted environment template used.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class StsTokenCredentialsProvider implements ExtensionCredentialsProvider {
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String securityToken;
|
||||
|
||||
private String signatureRegionId;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
String accessKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_ID);
|
||||
String secretKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_SECRET);
|
||||
String securityToken = getNacosProperties(properties, ExtensionAuthPropertyKey.SECURITY_TOKEN);
|
||||
return StringUtils.isNotBlank(accessKey) && StringUtils.isNotBlank(secretKey) && StringUtils.isNotBlank(
|
||||
securityToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
accessKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_ID);
|
||||
secretKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_SECRET);
|
||||
securityToken = getNacosProperties(properties, ExtensionAuthPropertyKey.SECURITY_TOKEN);
|
||||
signatureRegionId = getSignatureRegionId(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionRamContext getCredentialsForNacosClient() {
|
||||
ExtensionRamContext extensionRamContext = new ExtensionRamContext();
|
||||
extensionRamContext.setAccessKey(accessKey);
|
||||
extensionRamContext.setSecretKey(secretKey);
|
||||
extensionRamContext.setSecurityToken(securityToken);
|
||||
extensionRamContext.setExtensionSignatureRegionId(signatureRegionId);
|
||||
return extensionRamContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class AccessKeyCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
accessKey = properties.getProperty(AliyunConst.KMS_ACCESS_KEY,
|
||||
System.getProperty(AliyunConst.KMS_ACCESS_KEY, System.getenv(AliyunConst.KMS_ACCESS_KEY)));
|
||||
if(StringUtils.isBlank(accessKey)){
|
||||
accessKey = properties.getProperty(PropertyKeyConst.ACCESS_KEY,
|
||||
System.getProperty(PropertyKeyConst.ACCESS_KEY, System.getenv(PropertyKeyConst.ACCESS_KEY)));
|
||||
}
|
||||
secretKey = properties.getProperty(AliyunConst.KMS_SECRET_KEY,
|
||||
System.getProperty(AliyunConst.KMS_SECRET_KEY, System.getenv(AliyunConst.KMS_SECRET_KEY)));
|
||||
if(StringUtils.isBlank(secretKey)){
|
||||
secretKey = properties.getProperty(PropertyKeyConst.SECRET_KEY,
|
||||
System.getProperty(PropertyKeyConst.SECRET_KEY, System.getenv(PropertyKeyConst.SECRET_KEY)));
|
||||
}
|
||||
return !StringUtils.isBlank(accessKey) && !StringUtils.isBlank(secretKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config credentialConfig = new Config();
|
||||
credentialConfig.setType("access_key");
|
||||
credentialConfig.setAccessKeyId(accessKey);
|
||||
credentialConfig.setAccessKeySecret(secretKey);
|
||||
return credentialConfig;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class CredentialsUriKmsCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
String credentialsUri;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
credentialsUri = properties.getProperty(AliyunConst.KMS_CREDENTIALS_URI,
|
||||
System.getProperty(AliyunConst.KMS_CREDENTIALS_URI,System.getenv(AliyunConst.KMS_CREDENTIALS_URI)));
|
||||
if(StringUtils.isBlank(credentialsUri)){
|
||||
credentialsUri = getNacosProperties(properties, ExtensionAuthPropertyKey.CREDENTIALS_URI);
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(credentialsUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config config = new Config();
|
||||
config.setType("credentials_uri");
|
||||
config.setCredentialsUri(credentialsUri);
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class EcsRamRoleKmsCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
private String ramRoleName;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
ramRoleName = properties.getProperty(AliyunConst.KMS_RAM_ROLE_NAME,
|
||||
System.getProperty(AliyunConst.KMS_RAM_ROLE_NAME, System.getenv(AliyunConst.KMS_RAM_ROLE_NAME)));
|
||||
if(StringUtils.isBlank(ramRoleName)){
|
||||
ramRoleName= properties.getProperty(PropertyKeyConst.RAM_ROLE_NAME,
|
||||
System.getProperty(PropertyKeyConst.RAM_ROLE_NAME, System.getenv(PropertyKeyConst.RAM_ROLE_NAME)));
|
||||
}
|
||||
return !StringUtils.isBlank(ramRoleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config credentialConfig = new Config();
|
||||
credentialConfig.setType("ecs_ram_role");
|
||||
credentialConfig.setRoleName(ramRoleName);
|
||||
return credentialConfig;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public interface KmsCredentialsProvider {
|
||||
|
||||
boolean matchProvider(Properties properties);
|
||||
|
||||
Config generateCredentialsConfig(Properties properties);
|
||||
|
||||
default String getNacosProperties(Properties properties, ExtensionAuthPropertyKey key) {
|
||||
String result = properties.getProperty(key.getKey());
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
result = properties.getProperty(key.getEnvKey());
|
||||
}
|
||||
// For Adapt 2.1.X, in 2.1.X version, NacosClientProperties not finished all replaced, so properties don't include env.
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
result = System.getenv(key.getEnvKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class OidcRoleArnKmsCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
private String roleArn;
|
||||
|
||||
private String roleSessionName;
|
||||
|
||||
private String oidcProviderArn;
|
||||
|
||||
private String oidcTokenFilePath;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
roleArn = properties.getProperty(AliyunConst.KMS_ROLE_ARN,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_ARN, System.getenv(AliyunConst.KMS_ROLE_ARN)));
|
||||
if(StringUtils.isBlank(roleArn)){
|
||||
roleArn = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN);
|
||||
}
|
||||
|
||||
roleSessionName = properties.getProperty(AliyunConst.KMS_ROLE_SESSION_NAME,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_SESSION_NAME, System.getenv(AliyunConst.KMS_ROLE_SESSION_NAME)));
|
||||
if(StringUtils.isBlank(roleSessionName)){
|
||||
roleSessionName = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME);
|
||||
}
|
||||
|
||||
oidcProviderArn = properties.getProperty(AliyunConst.KMS_OIDC_PROVIDER_ARN,
|
||||
System.getProperty(AliyunConst.KMS_OIDC_PROVIDER_ARN, System.getenv(AliyunConst.KMS_OIDC_PROVIDER_ARN)));
|
||||
if(StringUtils.isBlank(oidcProviderArn)){
|
||||
oidcProviderArn = getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN);
|
||||
}
|
||||
|
||||
oidcTokenFilePath = properties.getProperty(AliyunConst.KMS_OIDC_TOKEN_FILE_PATH,
|
||||
System.getProperty(AliyunConst.KMS_OIDC_TOKEN_FILE_PATH, System.getenv(AliyunConst.KMS_OIDC_TOKEN_FILE_PATH)));
|
||||
if(StringUtils.isBlank(oidcTokenFilePath)){
|
||||
oidcTokenFilePath = getNacosProperties(properties, ExtensionAuthPropertyKey.OIDC_TOKEN_FILE_PATH);
|
||||
}
|
||||
return StringUtils.isNotBlank(roleArn) && StringUtils.isNotBlank(roleSessionName)
|
||||
&& StringUtils.isNotBlank(oidcProviderArn) && StringUtils.isNotBlank(oidcTokenFilePath);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config credentialsConfig = new Config();
|
||||
credentialsConfig.setType("oidc_role_arn");
|
||||
credentialsConfig.setRoleArn(roleArn);
|
||||
credentialsConfig.setRoleSessionName(roleSessionName);
|
||||
credentialsConfig.setOidcProviderArn(oidcProviderArn);
|
||||
credentialsConfig.setOidcTokenFilePath(oidcTokenFilePath);
|
||||
String policy = properties.getProperty(AliyunConst.KMS_POLICY,
|
||||
System.getProperty(AliyunConst.KMS_POLICY, System.getenv(AliyunConst.KMS_POLICY)));
|
||||
if(StringUtils.isBlank(policy)){
|
||||
policy = getNacosProperties(properties, ExtensionAuthPropertyKey.POLICY);
|
||||
}
|
||||
if(StringUtils.isNotBlank(policy)){
|
||||
credentialsConfig.setPolicy(policy);
|
||||
}
|
||||
String roleSessionExpiration = properties.getProperty(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS, System.getenv(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS)));
|
||||
if(StringUtils.isBlank(roleSessionExpiration)){
|
||||
roleSessionExpiration = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_EXPIRATION);
|
||||
}
|
||||
if(StringUtils.isNotBlank(roleSessionExpiration)){
|
||||
credentialsConfig.setRoleSessionExpiration(Integer.parseInt(roleSessionExpiration));
|
||||
}
|
||||
return credentialsConfig;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class RamRoleArnKmsCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String roleArn;
|
||||
|
||||
private String roleSessionName;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
accessKey = properties.getProperty(AliyunConst.KMS_EXTENSION_ACCESS_KEY,
|
||||
System.getProperty(AliyunConst.KMS_EXTENSION_ACCESS_KEY, System.getenv(AliyunConst.KMS_EXTENSION_ACCESS_KEY)));
|
||||
if(StringUtils.isBlank(accessKey)){
|
||||
accessKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_ID);
|
||||
}
|
||||
|
||||
secretKey = properties.getProperty(AliyunConst.KMS_EXTENSION_SECRET_KEY,
|
||||
System.getProperty(AliyunConst.KMS_EXTENSION_SECRET_KEY, System.getenv(AliyunConst.KMS_EXTENSION_SECRET_KEY)));
|
||||
if(StringUtils.isBlank(secretKey)){
|
||||
secretKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_SECRET);
|
||||
}
|
||||
|
||||
roleArn = properties.getProperty(AliyunConst.KMS_ROLE_ARN,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_ARN, System.getenv(AliyunConst.KMS_ROLE_ARN)));
|
||||
if(StringUtils.isBlank(roleArn)){
|
||||
roleArn = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_ARN);
|
||||
}
|
||||
|
||||
roleSessionName = properties.getProperty(AliyunConst.KMS_ROLE_SESSION_NAME,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_SESSION_NAME, System.getenv(AliyunConst.KMS_ROLE_SESSION_NAME)));
|
||||
if(StringUtils.isBlank(roleSessionName)){
|
||||
roleSessionName = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_NAME);
|
||||
}
|
||||
|
||||
return StringUtils.isNotBlank(accessKey) && StringUtils.isNotBlank(secretKey) && StringUtils.isNotBlank(roleArn)
|
||||
&& StringUtils.isNotBlank(roleSessionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config config = new Config();
|
||||
config.setType("ram_role_arn");
|
||||
config.setAccessKeyId(accessKey);
|
||||
config.setAccessKeySecret(secretKey);
|
||||
config.setRoleArn(roleArn);
|
||||
config.setRoleSessionName(roleSessionName);
|
||||
String policy = properties.getProperty(AliyunConst.KMS_POLICY,
|
||||
System.getProperty(AliyunConst.KMS_POLICY, System.getenv(AliyunConst.KMS_POLICY)));
|
||||
if(StringUtils.isBlank(policy)){
|
||||
policy = getNacosProperties(properties, ExtensionAuthPropertyKey.POLICY);
|
||||
}
|
||||
if(StringUtils.isNotBlank(policy)){
|
||||
config.setPolicy(policy);
|
||||
}
|
||||
String roleSessionExpiration = properties.getProperty(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS,
|
||||
System.getProperty(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS, System.getenv(AliyunConst.KMS_ROLE_SESSION_EXPIRATION_SECONDS)));
|
||||
if(StringUtils.isBlank(roleSessionExpiration)){
|
||||
roleSessionExpiration = getNacosProperties(properties, ExtensionAuthPropertyKey.ROLE_SESSION_EXPIRATION);
|
||||
}
|
||||
if(StringUtils.isNotBlank(roleSessionExpiration)){
|
||||
config.setRoleSessionExpiration(Integer.parseInt(roleSessionExpiration));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.alibaba.nacos.client.aliyun.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class StsTokenKmsCredentialsProvider implements KmsCredentialsProvider{
|
||||
|
||||
private String stsAccessKey;
|
||||
|
||||
private String stsSecretKey;
|
||||
|
||||
private String securityToken;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
stsAccessKey = properties.getProperty(AliyunConst.KMS_EXTENSION_ACCESS_KEY,
|
||||
System.getProperty(AliyunConst.KMS_EXTENSION_ACCESS_KEY, System.getenv(AliyunConst.KMS_EXTENSION_ACCESS_KEY)));
|
||||
if(StringUtils.isBlank(stsAccessKey)){
|
||||
stsAccessKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_ID);
|
||||
}
|
||||
stsSecretKey = properties.getProperty(AliyunConst.KMS_EXTENSION_SECRET_KEY,
|
||||
System.getProperty(AliyunConst.KMS_EXTENSION_SECRET_KEY, System.getenv(AliyunConst.KMS_EXTENSION_SECRET_KEY)));
|
||||
if(StringUtils.isBlank(stsSecretKey)){
|
||||
stsSecretKey = getNacosProperties(properties, ExtensionAuthPropertyKey.ACCESS_KEY_SECRET);
|
||||
}
|
||||
|
||||
securityToken = properties.getProperty(AliyunConst.KMS_SECURITY_TOKEN,
|
||||
System.getProperty(AliyunConst.KMS_SECURITY_TOKEN, System.getenv(AliyunConst.KMS_SECURITY_TOKEN)));
|
||||
if(StringUtils.isBlank(securityToken)){
|
||||
securityToken = getNacosProperties(properties, ExtensionAuthPropertyKey.SECURITY_TOKEN);
|
||||
}
|
||||
return StringUtils.isNotBlank(stsAccessKey) && StringUtils.isNotBlank(stsSecretKey) && StringUtils.isNotBlank(securityToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config generateCredentialsConfig(Properties properties) {
|
||||
Config credentialConfig = new Config();
|
||||
credentialConfig.setType("sts");
|
||||
credentialConfig.setAccessKeyId(stsAccessKey);
|
||||
credentialConfig.setAccessKeySecret(stsSecretKey);
|
||||
credentialConfig.setSecurityToken(securityToken);
|
||||
return credentialConfig;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.alibaba.nacos.client.aliyun.sample;
|
||||
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.aliyun.AliyunConst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class KmsV3Sample {
|
||||
public static Properties properties;
|
||||
|
||||
public static final List<String> dataIdListPost = new ArrayList<String>(){{
|
||||
add("common-config");
|
||||
add("cipher-kms-aes-256-crypt");
|
||||
}};
|
||||
|
||||
public static final String content = "crypt";
|
||||
|
||||
public static final String group = "default";
|
||||
public static void main(String[] args) throws NacosException {
|
||||
properties = new Properties();
|
||||
properties.put(PropertyKeyConst.SERVER_ADDR, "serverAddr");
|
||||
properties.put(PropertyKeyConst.NAMESPACE, "ns");
|
||||
properties.put(PropertyKeyConst.ACCESS_KEY, "ak");
|
||||
properties.put(PropertyKeyConst.SECRET_KEY, "value of sk");
|
||||
|
||||
properties.put(AliyunConst.REGION_ID, "value of regionId");
|
||||
properties.put(AliyunConst.KMS_REGION_ID, "value of kms_region_id");
|
||||
properties.put(AliyunConst.KMS_ENDPOINT, "value of kmsEndpoint");
|
||||
properties.put(AliyunConst.KEY_ID, "value of keyId");
|
||||
properties.put(AliyunConst.KMS_PASSWORD_KEY, "value of kmsPasswordKey");
|
||||
|
||||
//only need set one between AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY and AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY
|
||||
properties.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "value of kmsClientKey");
|
||||
// properties.put(AliyunConst.KMS_CLIENT_KEY_FILE_PATH_KEY, "path to kmsClientKeyFile");
|
||||
|
||||
//only need set one between AliyunConst.KMS_CA_FILE_CONTENT and AliyunConst.KMS_CA_FILE_PATH_KEY
|
||||
properties.put(AliyunConst.KMS_CA_FILE_CONTENT, "value of kmsCaFile");
|
||||
// properties.put(AliyunConst.KMS_CA_FILE_PATH_KEY, "path to kmsCaFile");
|
||||
|
||||
properties.put(AliyunConst.KMS_VERSION_KEY, AliyunConst.KmsVersion.Kmsv3.getValue());
|
||||
ConfigService configService = NacosFactory.createConfigService(properties);
|
||||
|
||||
//publish and get config
|
||||
System.out.println("------config loop------");
|
||||
for (String dataId : dataIdListPost) {
|
||||
boolean b = configService.publishConfig(dataId, group, content);
|
||||
if (!b) {
|
||||
System.out.println("publish config: dataId=" + dataId + ",publishConfig failed");
|
||||
continue;
|
||||
} else {
|
||||
System.out.println("publish config: dataId=" + dataId + ",publishConfig success");
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String content = configService.getConfig(dataId, group, 5000);
|
||||
System.out.println("get config: dataId=" + dataId + ",content=" + content);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright 1999-2024 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.client.aliyun.auth.AliyunExtensionClientAuthServiceImpl
|
|
@ -1,97 +1,102 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigRequest;
|
||||
import com.alibaba.nacos.api.config.filter.IConfigResponse;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.utils.StringUtils;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigRequest;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedConstruction;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
public class AliyunConfigFilterTest {
|
||||
private static final String ENCRYPTED_DATA_KEY = "encryptedDataKey";
|
||||
public static Properties properties;
|
||||
public static final List<String> dataIdList = new ArrayList<String>(){{
|
||||
add("cipher-crypt");
|
||||
add("cipher-kms-aes-256-crypt");
|
||||
add("cipher-kms-aes-128-crypt");
|
||||
}};
|
||||
|
||||
public static final String content = "crypt";
|
||||
|
||||
public static final String group = "default";
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mockConstruction;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AliyunConfigFilterTest {
|
||||
|
||||
MockedConstruction<RamKmsEncryptor> ramKmsEncryptorMockedConstruction;
|
||||
|
||||
@Mock
|
||||
IConfigFilterChain chain;
|
||||
|
||||
@BeforeEach
|
||||
public void preset() {
|
||||
try {
|
||||
properties = new Properties();
|
||||
properties.load(this.getClass().getResourceAsStream("/aliyun-kms.properties"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
void setUp() {
|
||||
ramKmsEncryptorMockedConstruction = mockConstruction(RamKmsEncryptor.class,(mock,contexnt)->{
|
||||
when(mock.encrypt(any(IConfigRequest.class))).thenReturn("encryptedContext");
|
||||
when(mock.decrypt(any(IConfigResponse.class))).thenReturn("plainText");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
ramKmsEncryptorMockedConstruction.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliyunConfigFilterWithKmsV1() {
|
||||
properties.setProperty(AliyunConst.KMS_VERSION_KEY, AliyunConst.KmsVersion.Kmsv1.getValue());
|
||||
//ignore kmsEndpoint
|
||||
properties.setProperty("kmsEndpoint", "");
|
||||
properties.setProperty("regionId", "cn-beijing");
|
||||
properties.setProperty("kms_region_id", "cn-beijing");
|
||||
properties.setProperty("accessKey", "LTAxxxx1E6");
|
||||
properties.setProperty("secretKey", "kr6JxxxsD6");
|
||||
properties.setProperty("keyId", "alias/acs/mse");
|
||||
executeConfigFilter();
|
||||
void init() throws NoSuchFieldException, IllegalAccessException {
|
||||
Properties properties_1 = new Properties();
|
||||
properties_1.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "test");
|
||||
AliyunConfigFilter aliyunConfigFilter_1 = new AliyunConfigFilter();
|
||||
aliyunConfigFilter_1.init(properties_1);
|
||||
Field field = aliyunConfigFilter_1.getClass().getDeclaredField("kmsEncryptor");
|
||||
field.setAccessible(true);
|
||||
KmsEncryptor kmsEncryptor = (KmsEncryptor) field.get(aliyunConfigFilter_1);
|
||||
assertTrue(kmsEncryptor instanceof ClientKeyKmsEncryptor);
|
||||
|
||||
Properties properties_2 = new Properties();
|
||||
AliyunConfigFilter aliyunConfigFilter_2 = new AliyunConfigFilter();
|
||||
aliyunConfigFilter_2.init(properties_2);
|
||||
KmsEncryptor kmsEncryptor_2 = (KmsEncryptor) field.get(aliyunConfigFilter_2);
|
||||
assertTrue(kmsEncryptor_2 instanceof RamKmsEncryptor);
|
||||
}
|
||||
|
||||
// must be running in vpc
|
||||
// @Test
|
||||
// public void testAliyunConfigFilterWithKmsV3() {
|
||||
// properties.setProperty(AliyunConst.KMS_VERSION_KEY, AliyunConst.KmsVersion.Kmsv3.getValue());
|
||||
// properties.setProperty("keyId", "alias/chasu");
|
||||
// properties.setProperty("kmsEndpoint", "kst-bjxxxxxxxxxc.cryptoservice.kms.aliyuncs.com");
|
||||
// properties.setProperty("kmsClientKeyFilePath", "/client_key.json");
|
||||
// properties.setProperty("kmsPasswordKey", "19axxx213");
|
||||
// properties.setProperty("kmsCaFilePath", "/ca.pem");
|
||||
// executeConfigFilter();
|
||||
// }
|
||||
|
||||
private void executeConfigFilter() {
|
||||
for (String dataId : dataIdList) {
|
||||
ConfigFilterChainManager configFilterChainManager = new ConfigFilterChainManager(properties);
|
||||
AliyunConfigFilter aliyunConfigFilter = new AliyunConfigFilter();
|
||||
configFilterChainManager.addFilter(aliyunConfigFilter);
|
||||
|
||||
ConfigRequest configRequest = new ConfigRequest();
|
||||
configRequest.setGroup(group);
|
||||
configRequest.setDataId(dataId);
|
||||
configRequest.setContent(content);
|
||||
String encryptedContent = null;
|
||||
try {
|
||||
configFilterChainManager.doFilter(configRequest, null);
|
||||
encryptedContent = configRequest.getContent();
|
||||
Assertions.assertFalse(StringUtils.isBlank(encryptedContent));
|
||||
} catch (NacosException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
ConfigResponse configResponse = new ConfigResponse();
|
||||
configResponse.setGroup(group);
|
||||
configResponse.setDataId(dataId);
|
||||
configResponse.setEncryptedDataKey((String) configRequest.getParameter(ENCRYPTED_DATA_KEY));
|
||||
configResponse.setContent(encryptedContent);
|
||||
try {
|
||||
configFilterChainManager.doFilter(null, configResponse);
|
||||
Assertions.assertEquals(content, configResponse.getContent());
|
||||
} catch (NacosException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void doFilter() throws NacosException {
|
||||
|
||||
Properties properties_2 = new Properties();
|
||||
AliyunConfigFilter aliyunConfigFilter_2 = new AliyunConfigFilter();
|
||||
aliyunConfigFilter_2.init(properties_2);
|
||||
|
||||
ConfigRequest request = new ConfigRequest();
|
||||
request.putParameter("dataId", "cipher-test");
|
||||
request.putParameter("content","test-context");
|
||||
|
||||
ConfigResponse response = new ConfigResponse();
|
||||
response.putParameter("dataId", "cipher-test");
|
||||
response.putParameter("content","test-context");
|
||||
doNothing().when(chain).doFilter(any(),any());
|
||||
aliyunConfigFilter_2.doFilter(request, response, chain);
|
||||
|
||||
assertEquals("encryptedContext",request.getParameter("content"));
|
||||
assertEquals("plainText",response.getParameter("content"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOrder() {
|
||||
Properties properties = new Properties();
|
||||
AliyunConfigFilter aliyunConfigFilter = new AliyunConfigFilter();
|
||||
aliyunConfigFilter.init(properties);
|
||||
assertEquals(1, aliyunConfigFilter.getOrder());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getFilterName() {
|
||||
Properties properties = new Properties();
|
||||
AliyunConfigFilter aliyunConfigFilter = new AliyunConfigFilter();
|
||||
aliyunConfigFilter.init(properties);
|
||||
assertEquals("com.alibaba.nacos.client.aliyun.AliyunConfigFilter", aliyunConfigFilter.getFilterName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigRequest;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
|
||||
import com.aliyun.kms.KmsTransferAcsClient;
|
||||
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.DecryptResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.DescribeKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.EncryptRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.EncryptResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyRequest;
|
||||
import com.aliyuncs.kms.model.v20160120.GenerateDataKeyResponse;
|
||||
import com.aliyuncs.kms.model.v20160120.SetDeletionProtectionRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.MockedConstruction;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_256_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.ENCODE_UTF8;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mockConstruction;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ClientKeyKmsEncryptorTest {
|
||||
|
||||
MockedConstruction<KmsTransferAcsClient> mockClientConstruction;
|
||||
|
||||
MockedStatic<AesUtils> mockAesUtils;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
||||
mockAesUtils = mockStatic(AesUtils.class);
|
||||
|
||||
mockAesUtils.when(()->AesUtils.decrypt("cipherText","plainText",ENCODE_UTF8))
|
||||
.thenReturn("plainTextByAES");
|
||||
|
||||
mockAesUtils.when(()->AesUtils.encrypt("plainText","plainKey",ENCODE_UTF8))
|
||||
.thenReturn("cipherTextByAES");
|
||||
|
||||
GenerateDataKeyResponse generateDataKeyResponse = new GenerateDataKeyResponse();
|
||||
generateDataKeyResponse.setPlaintext("plainKey");
|
||||
generateDataKeyResponse.setCiphertextBlob("cipherKey");
|
||||
|
||||
DescribeKeyResponse describeKeyResponse = new DescribeKeyResponse();
|
||||
DescribeKeyResponse.KeyMetadata keyMetadata = new DescribeKeyResponse.KeyMetadata();
|
||||
keyMetadata.setKeyState("Enabled");
|
||||
describeKeyResponse.setKeyMetadata(keyMetadata);
|
||||
|
||||
DecryptResponse decryptResponse = new DecryptResponse();
|
||||
decryptResponse.setPlaintext("plainText");
|
||||
|
||||
EncryptResponse encryptResponse = new EncryptResponse();
|
||||
encryptResponse.setCiphertextBlob("cipherText");
|
||||
|
||||
mockClientConstruction = mockConstruction(KmsTransferAcsClient.class,(mock,context)->{
|
||||
when(mock.getAcsResponse(any(DescribeKeyRequest.class))).thenReturn(describeKeyResponse);
|
||||
when(mock.getAcsResponse(any(GenerateDataKeyRequest.class))).thenReturn(generateDataKeyResponse);
|
||||
when(mock.getAcsResponse(any(SetDeletionProtectionRequest.class))).thenReturn(null);
|
||||
when(mock.getAcsResponse(any(DecryptRequest.class))).thenReturn(decryptResponse);
|
||||
when(mock.getAcsResponse(any(EncryptRequest.class))).thenReturn(encryptResponse);
|
||||
});
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
mockClientConstruction.close();
|
||||
mockAesUtils.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testInit() throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
properties.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
// properties.put(AliyunConst.KEY_ID,"keyId");
|
||||
properties.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor1 = new ClientKeyKmsEncryptor(properties);
|
||||
|
||||
ConfigRequest configRequest = new ConfigRequest();
|
||||
try{
|
||||
clientKeyKmsEncryptor1.encrypt(configRequest);
|
||||
}catch (Exception e){
|
||||
assertTrue(e.getMessage().contains("keyId is null or empty"));
|
||||
}
|
||||
|
||||
Properties properties2 = new Properties();
|
||||
// properties2.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
properties2.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
properties2.put(AliyunConst.KEY_ID,"keyId");
|
||||
properties2.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties2.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor2 = new ClientKeyKmsEncryptor(properties2);
|
||||
try{
|
||||
clientKeyKmsEncryptor2.encrypt(configRequest);
|
||||
}catch (Exception e){
|
||||
assertTrue(e.getMessage().contains( "kmsClientKeyFilePath and kmsClientKeyContent are both empty"));
|
||||
}
|
||||
|
||||
Properties properties3 = new Properties();
|
||||
properties3.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
// properties3.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
properties3.put(AliyunConst.KEY_ID,"keyId");
|
||||
properties3.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties3.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor3 = new ClientKeyKmsEncryptor(properties3);
|
||||
try{
|
||||
clientKeyKmsEncryptor3.encrypt(configRequest);
|
||||
} catch (Exception e){
|
||||
assertTrue(e.getMessage().contains("kmsEndpoint is empty"));
|
||||
}
|
||||
|
||||
Properties properties4 = new Properties();
|
||||
properties4.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
properties4.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
properties4.put(AliyunConst.KEY_ID,"keyId");
|
||||
// properties4.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties4.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor4 = new ClientKeyKmsEncryptor(properties4);
|
||||
try{
|
||||
clientKeyKmsEncryptor4.encrypt(configRequest);
|
||||
} catch (Exception e){
|
||||
assertTrue(e.getMessage().contains("kmsPasswordKey is empty"));
|
||||
}
|
||||
|
||||
Properties properties5 = new Properties();
|
||||
properties5.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
properties5.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
properties5.put(AliyunConst.KEY_ID,"keyId");
|
||||
properties5.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties5.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor5 = new ClientKeyKmsEncryptor(properties5);
|
||||
|
||||
Field field = ClientKeyKmsEncryptor.class.getDeclaredField("kmsClient");
|
||||
field.setAccessible(true);
|
||||
assertNotNull(field.get(clientKeyKmsEncryptor5));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void encryptAndDecryptTest() throws Exception {
|
||||
ConfigRequest configRequest = new ConfigRequest();
|
||||
configRequest.setDataId(CIPHER_KMS_AES_256_PREFIX+"dataId");
|
||||
configRequest.setGroup("DEFAULT_GROUP");
|
||||
configRequest.setContent("plainText");
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(AliyunConst.KMS_CLIENT_KEY_CONTENT_KEY, "clientKeyContent");
|
||||
properties.put(AliyunConst.KMS_ENDPOINT,"endPoint");
|
||||
properties.put(AliyunConst.KEY_ID,"keyId");
|
||||
properties.put(AliyunConst.KMS_PASSWORD_KEY,"password");
|
||||
properties.put(AliyunConst.KMS_CA_FILE_CONTENT,"caFileContent");
|
||||
ClientKeyKmsEncryptor clientKeyKmsEncryptor = new ClientKeyKmsEncryptor(properties);
|
||||
assertEquals(clientKeyKmsEncryptor.encrypt(configRequest),"cipherTextByAES");
|
||||
|
||||
configRequest.setDataId(CIPHER_PREFIX+"dataId");
|
||||
assertEquals(clientKeyKmsEncryptor.encrypt(configRequest),"cipherText");
|
||||
|
||||
ConfigResponse configResponse = new ConfigResponse();
|
||||
configResponse.setContent("cipherText");
|
||||
configResponse.setEncryptedDataKey("encryptedDataKey");
|
||||
configResponse.setDataId(CIPHER_KMS_AES_256_PREFIX+"dataId");
|
||||
configResponse.setGroup("DEFAULT_GROUP");
|
||||
assertEquals(clientKeyKmsEncryptor.decrypt(configResponse),"plainTextByAES");
|
||||
|
||||
configResponse.setDataId(CIPHER_PREFIX+"dataId");
|
||||
assertEquals(clientKeyKmsEncryptor.decrypt(configResponse),"plainText");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class LocalTest {
|
||||
|
||||
@Test
|
||||
public void testLocal() throws Exception {
|
||||
String commonCipherContent = AesUtils.encrypt("common cipher content", "6QSdvMf3ivYADypZejz2OQTX7EYc0+9750MoHGnVOJk=", "UTF-8");
|
||||
String commonCipherContent1 = AesUtils.encrypt("common cipher content", "6QSdvMf3ivYADypZejz2OQTX7EYc0+9750MoHGnVOJk=", "UTF-8");
|
||||
Assertions.assertEquals(commonCipherContent1, commonCipherContent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package com.alibaba.nacos.client.aliyun;
|
||||
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigRequest;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
|
||||
import com.aliyun.kms20160120.Client;
|
||||
import com.aliyun.kms20160120.models.DecryptRequest;
|
||||
import com.aliyun.kms20160120.models.DecryptResponse;
|
||||
import com.aliyun.kms20160120.models.DecryptResponseBody;
|
||||
import com.aliyun.kms20160120.models.DescribeKeyRequest;
|
||||
import com.aliyun.kms20160120.models.DescribeKeyResponse;
|
||||
import com.aliyun.kms20160120.models.DescribeKeyResponseBody;
|
||||
import com.aliyun.kms20160120.models.EncryptRequest;
|
||||
import com.aliyun.kms20160120.models.EncryptResponse;
|
||||
import com.aliyun.kms20160120.models.EncryptResponseBody;
|
||||
import com.aliyun.kms20160120.models.GenerateDataKeyRequest;
|
||||
import com.aliyun.kms20160120.models.GenerateDataKeyResponse;
|
||||
import com.aliyun.kms20160120.models.GenerateDataKeyResponseBody;
|
||||
import com.aliyun.kms20160120.models.SetDeletionProtectionRequest;
|
||||
import com.aliyun.teautil.models.RuntimeOptions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.MockedConstruction;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_KMS_AES_256_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.CIPHER_PREFIX;
|
||||
import static com.alibaba.nacos.client.aliyun.AliyunConst.ENCODE_UTF8;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mockConstruction;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RamKmsEncryptorTest {
|
||||
|
||||
MockedConstruction<Client> mockClientConstruction;
|
||||
|
||||
MockedStatic<AesUtils> mockAesUtils;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
|
||||
mockAesUtils = mockStatic(AesUtils.class);
|
||||
|
||||
mockAesUtils.when(() -> AesUtils.decrypt("cipherText", "plainText", ENCODE_UTF8)).thenReturn("plainTextByAES");
|
||||
|
||||
mockAesUtils.when(() -> AesUtils.encrypt("plainText", "plainKey", ENCODE_UTF8)).thenReturn("cipherTextByAES");
|
||||
EncryptResponse encryptResponse = new EncryptResponse();
|
||||
EncryptResponseBody body = new EncryptResponseBody();
|
||||
body.setCiphertextBlob("cipherText");
|
||||
encryptResponse.setBody(body);
|
||||
|
||||
DecryptResponse decryptResponse = new DecryptResponse();
|
||||
DecryptResponseBody body1 = new DecryptResponseBody();
|
||||
decryptResponse.setBody(body1);
|
||||
body1.setPlaintext("plainText");
|
||||
|
||||
DescribeKeyResponse describeKeyResponse = new DescribeKeyResponse();
|
||||
DescribeKeyResponseBody body2 = new DescribeKeyResponseBody();
|
||||
DescribeKeyResponseBody.DescribeKeyResponseBodyKeyMetadata keyMetadata = new DescribeKeyResponseBody.DescribeKeyResponseBodyKeyMetadata();
|
||||
keyMetadata.setKeyState("Enabled");
|
||||
body2.setKeyMetadata(keyMetadata);
|
||||
describeKeyResponse.setBody(body2);
|
||||
|
||||
GenerateDataKeyResponse generateDataKeyResponse = new GenerateDataKeyResponse();
|
||||
GenerateDataKeyResponseBody body3 = new GenerateDataKeyResponseBody();
|
||||
body3.setPlaintext("plainKey");
|
||||
body3.setCiphertextBlob("cipherKey");
|
||||
generateDataKeyResponse.setBody(body3);
|
||||
|
||||
mockClientConstruction = mockConstruction(Client.class, (mock, context) -> {
|
||||
when(mock.encryptWithOptions(any(EncryptRequest.class), any(RuntimeOptions.class))).thenReturn(
|
||||
encryptResponse);
|
||||
when(mock.decryptWithOptions(any(DecryptRequest.class), any(RuntimeOptions.class))).thenReturn(
|
||||
decryptResponse);
|
||||
when(mock.describeKeyWithOptions(any(DescribeKeyRequest.class), any(RuntimeOptions.class))).thenReturn(
|
||||
describeKeyResponse);
|
||||
when(mock.setDeletionProtectionWithOptions(any(SetDeletionProtectionRequest.class),
|
||||
any(RuntimeOptions.class))).thenReturn(null);
|
||||
when(mock.generateDataKeyWithOptions(any(GenerateDataKeyRequest.class),
|
||||
any(RuntimeOptions.class))).thenReturn(generateDataKeyResponse);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
mockClientConstruction.close();
|
||||
mockAesUtils.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInit() throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("accessKey", "accessKey");
|
||||
properties.setProperty("secretKey", "secretKey");
|
||||
properties.setProperty("regionId", "regionId");
|
||||
properties.setProperty(AliyunConst.KMS_ENDPOINT, "endPoint");
|
||||
|
||||
ConfigRequest configRequest = new ConfigRequest();
|
||||
RamKmsEncryptor ramKmsEncryptor = new RamKmsEncryptor(properties);
|
||||
try {
|
||||
ramKmsEncryptor.encrypt(configRequest);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("keyId is null or empty"));
|
||||
}
|
||||
|
||||
Properties properties1 = new Properties();
|
||||
properties1.setProperty("accessKey", "accessKey");
|
||||
// properties1.setProperty("secretKey","secretKey");
|
||||
properties1.setProperty("regionId", "regionId");
|
||||
|
||||
RamKmsEncryptor ramKmsEncryptor1 = new RamKmsEncryptor(properties1);
|
||||
try {
|
||||
ramKmsEncryptor1.encrypt(configRequest);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("Ram Auth Information are not set up yet"));
|
||||
}
|
||||
|
||||
Properties properties2 = new Properties();
|
||||
properties2.setProperty("ramRoleName", "ramRoleName");
|
||||
properties2.setProperty("regionId", "regionId");
|
||||
RamKmsEncryptor ramKmsEncryptor2 = new RamKmsEncryptor(properties2);
|
||||
Field field = RamKmsEncryptor.class.getDeclaredField("kmsClient");
|
||||
field.setAccessible(true);
|
||||
assertNotNull(field.get(ramKmsEncryptor2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void encryptAndDecryptTest() throws Exception {
|
||||
ConfigRequest configRequest = new ConfigRequest();
|
||||
configRequest.setDataId(CIPHER_KMS_AES_256_PREFIX + "dataId");
|
||||
configRequest.setGroup("DEFAULT_GROUP");
|
||||
configRequest.setContent("plainText");
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("ramRoleName", "ramRoleName");
|
||||
properties.setProperty("regionId", "regionId");
|
||||
RamKmsEncryptor ramKmsEncryptor = new RamKmsEncryptor(properties);
|
||||
assertEquals(ramKmsEncryptor.encrypt(configRequest), "cipherTextByAES");
|
||||
|
||||
configRequest.setDataId(CIPHER_PREFIX + "dataId");
|
||||
assertEquals(ramKmsEncryptor.encrypt(configRequest), "cipherText");
|
||||
|
||||
ConfigResponse configResponse = new ConfigResponse();
|
||||
configResponse.setContent("cipherText");
|
||||
configResponse.setEncryptedDataKey("encryptedDataKey");
|
||||
configResponse.setDataId(CIPHER_KMS_AES_256_PREFIX + "dataId");
|
||||
configResponse.setGroup("DEFAULT_GROUP");
|
||||
assertEquals(ramKmsEncryptor.decrypt(configResponse), "plainTextByAES");
|
||||
|
||||
configResponse.setDataId(CIPHER_PREFIX + "dataId");
|
||||
assertEquals(ramKmsEncryptor.decrypt(configResponse), "plainText");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.aliyun.auth.provider.ExtensionCredentialsProvider;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class AliyunExtensionClientAuthServiceImplTest {
|
||||
|
||||
AliyunExtensionClientAuthServiceImpl clientAuthService;
|
||||
|
||||
RequestResource resource;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
clientAuthService = new AliyunExtensionClientAuthServiceImpl();
|
||||
resource = RequestResource.configBuilder().build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
clientAuthService.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginNoMatch() {
|
||||
assertFalse(clientAuthService.login(new Properties()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginWithException() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECRET_NAME.getKey(), "secret");
|
||||
assertFalse(clientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginSuccess() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECURITY_TOKEN.getKey(), "securityToken");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_ID.getKey(), "accessKeyId");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_SECRET.getKey(), "accessKeySecret");
|
||||
assertTrue(clientAuthService.login(properties));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextForStsToken() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockProvider(true, true);
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertEquals("accessKey", context.getParameter("Spas-AccessKey"));
|
||||
assertEquals("securityToken", context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNotNull(context.getParameter("Spas-Signature"));
|
||||
assertNotNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextForAkSk() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockProvider(false, true);
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertEquals("accessKey", context.getParameter("Spas-AccessKey"));
|
||||
assertNull(context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNotNull(context.getParameter("Spas-Signature"));
|
||||
assertNotNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextForStsTokenInvalid() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockProvider(true, false);
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertNull(context.getParameter("Spas-AccessKey"));
|
||||
assertNull(context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNull(context.getParameter("Spas-Signature"));
|
||||
assertNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextForAkSkInvalid() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockProvider(false, false);
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertNull(context.getParameter("Spas-AccessKey"));
|
||||
assertNull(context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNull(context.getParameter("Spas-Signature"));
|
||||
assertNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextForNoInjector() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockProvider(true, true);
|
||||
resource.setType("Mock");
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertNull(context.getParameter("Spas-AccessKey"));
|
||||
assertNull(context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNull(context.getParameter("Spas-Signature"));
|
||||
assertNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLoginIdentityContextWithoutInit() {
|
||||
LoginIdentityContext context = clientAuthService.getLoginIdentityContext(resource);
|
||||
assertNull(context.getParameter("Spas-AccessKey"));
|
||||
assertNull(context.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
assertNull(context.getParameter("Spas-Signature"));
|
||||
assertNull(context.getParameter("Timestamp"));
|
||||
}
|
||||
|
||||
private void injectMockProvider(boolean ephemeralAccessKeyId, boolean validate)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
MockCredentialsProvider mockProvider = new MockCredentialsProvider();
|
||||
mockProvider.ephemeralAccessKeyId = ephemeralAccessKeyId;
|
||||
mockProvider.validate = validate;
|
||||
Field matchedProviderField = clientAuthService.getClass().getDeclaredField("matchedProvider");
|
||||
matchedProviderField.setAccessible(true);
|
||||
matchedProviderField.set(clientAuthService, mockProvider);
|
||||
}
|
||||
|
||||
private static class MockCredentialsProvider implements ExtensionCredentialsProvider {
|
||||
|
||||
boolean ephemeralAccessKeyId = true;
|
||||
|
||||
boolean validate;
|
||||
|
||||
@Override
|
||||
public boolean matchProvider(Properties properties) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionRamContext getCredentialsForNacosClient() {
|
||||
ExtensionRamContext ramContext = new ExtensionRamContext();
|
||||
ramContext.setEphemeralAccessKeyId(ephemeralAccessKeyId);
|
||||
if (validate) {
|
||||
ramContext.setSecretKey("secretKey");
|
||||
ramContext.setAccessKey("accessKey");
|
||||
ramContext.setSecurityToken(ephemeralAccessKeyId ? "securityToken" : "");
|
||||
} else {
|
||||
ramContext.setSecurityToken(ephemeralAccessKeyId ? "" : "securityToken");
|
||||
}
|
||||
return ramContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws NacosException {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthConstants;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.LoginIdentityContext;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
class AbstractExtensionResourceInjectorTest {
|
||||
|
||||
AbstractExtensionResourceInjector resourceInjector;
|
||||
|
||||
ExtensionRamContext ramContext;
|
||||
|
||||
RequestResource resource;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
resourceInjector = new MockExtensionResourceInjector();
|
||||
ramContext = new ExtensionRamContext();
|
||||
ramContext.setSecretKey("secret");
|
||||
ramContext.setEphemeralAccessKeyId(false);
|
||||
resource = new RequestResource();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void doInjectForV4WithoutRegionId() {
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
resourceInjector.doInject(resource, ramContext, result);
|
||||
assertEquals("secret", result.getParameter("sk"));
|
||||
assertNull(result.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doInjectForV4WithRegionId() {
|
||||
ramContext.setExtensionSignatureRegionId("cn-hangzhou");
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
resourceInjector.doInject(resource, ramContext, result);
|
||||
assertNotEquals("secret", result.getParameter("sk"));
|
||||
assertNull(result.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doInjectForV4WithRegionIdAndStsToken() {
|
||||
ramContext.setExtensionSignatureRegionId("cn-hangzhou");
|
||||
ramContext.setSecurityToken("token");
|
||||
ramContext.setEphemeralAccessKeyId(true);
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
resourceInjector.doInject(resource, ramContext, result);
|
||||
assertNotEquals("secret", result.getParameter("sk"));
|
||||
assertEquals("token", result.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doInjectForV1WithRegionId() throws NoSuchFieldException, IllegalAccessException {
|
||||
Field supportV4signatureField = resourceInjector.getClass().getSuperclass()
|
||||
.getDeclaredField("supportV4signature");
|
||||
supportV4signatureField.setAccessible(true);
|
||||
supportV4signatureField.set(resourceInjector, false);
|
||||
ramContext.setExtensionSignatureRegionId("cn-hangzhou");
|
||||
LoginIdentityContext result = new LoginIdentityContext();
|
||||
resourceInjector.doInject(resource, ramContext, result);
|
||||
assertEquals("secret", result.getParameter("sk"));
|
||||
assertNull(result.getParameter(ExtensionAuthConstants.SECURITY_TOKEN_HEADER));
|
||||
}
|
||||
|
||||
private static class MockExtensionResourceInjector extends AbstractExtensionResourceInjector {
|
||||
|
||||
@Override
|
||||
protected String getAccessKeyHeaderKey() {
|
||||
return "Mock";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, String> calculateSignature(RequestResource resource, String actualSecretKey,
|
||||
ExtensionRamContext ramContext) {
|
||||
return Collections.singletonMap("sk", actualSecretKey);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.client.auth.ram.utils.SpasAdapter;
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ConfigExtensionResourceInjectorTest {
|
||||
|
||||
ConfigExtensionResourceInjector resourceInjector;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
resourceInjector = new ConfigExtensionResourceInjector();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAccessKeyHeaderKey() {
|
||||
assertEquals("Spas-AccessKey", resourceInjector.getAccessKeyHeaderKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithTenant() {
|
||||
RequestResource resource = RequestResource.configBuilder().setNamespace("TestNamespace").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsKey("Timestamp"));
|
||||
String expected = SpasAdapter.signWithHmacSha1Encrypt("TestNamespace+" + result.get("Timestamp"), "secret");
|
||||
assertEquals(expected, result.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithGroup() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setGroup("TestGroup").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsKey("Timestamp"));
|
||||
String expected = SpasAdapter.signWithHmacSha1Encrypt("TestGroup+" + result.get("Timestamp"), "secret");
|
||||
assertEquals(expected, result.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithAll() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setGroup("TestGroup").setNamespace("TestNamespace")
|
||||
.build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsKey("Timestamp"));
|
||||
String expected = SpasAdapter.signWithHmacSha1Encrypt("TestNamespace+TestGroup+" + result.get("Timestamp"),
|
||||
"secret");
|
||||
assertEquals(expected, result.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithEmptyResource() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setResource("").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsKey("Timestamp"));
|
||||
String expected = SpasAdapter.signWithHmacSha1Encrypt(result.get("Timestamp"), "secret");
|
||||
assertEquals(expected, result.get("Spas-Signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithException() {
|
||||
// Will Throw NPE.
|
||||
Map<String, String> result = resourceInjector.calculateSignature(null, "secret", null);
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.injector;
|
||||
|
||||
import com.alibaba.nacos.plugin.auth.api.RequestResource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class NamingExtensionResourceInjectorTest {
|
||||
|
||||
NamingExtensionResourceInjector resourceInjector;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
resourceInjector = new NamingExtensionResourceInjector();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAccessKeyHeaderKey() {
|
||||
assertEquals("ak", resourceInjector.getAccessKeyHeaderKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithoutGroup() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setResource("TestService").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.get("data").endsWith("TestService"));
|
||||
assertTrue(result.containsKey("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithGroup() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setGroup("TestGroup").setResource("TestService")
|
||||
.build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.get("data").endsWith("TestGroup@@TestService"));
|
||||
assertTrue(result.containsKey("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithGroupedService() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setResource("TestGroup@@TestService").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.get("data").endsWith("TestGroup@@TestService"));
|
||||
assertTrue(result.containsKey("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithEmptyResource() {
|
||||
RequestResource resource = RequestResource.namingBuilder().setResource("").build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.get("data").matches("^\\d*$"));
|
||||
assertTrue(result.containsKey("signature"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void calculateSignatureWithException() {
|
||||
// Will Throw NPE.
|
||||
RequestResource resource = RequestResource.namingBuilder().build();
|
||||
Map<String, String> result = resourceInjector.calculateSignature(resource, "secret", null);
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.aliyun.credentials.Client;
|
||||
import com.aliyun.credentials.models.CredentialModel;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
abstract class AbstractCredentialClientProviderTest extends AbstractCredentialsProviderTest {
|
||||
|
||||
@Mock
|
||||
Client credentialsClient;
|
||||
|
||||
protected CredentialModel credentialModel;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
credentialModel = CredentialModel.builder().accessKeyId(ACCESS_KEY_ID).accessKeySecret(ACCESS_KEY_SECRET)
|
||||
.securityToken(SECURITY_TOKEN).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClient() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockCredentialsClient();
|
||||
initWithProperties();
|
||||
mockCredentialsClientReturn(credentialModel);
|
||||
ExtensionRamContext context = getCredentialsProvider().getCredentialsForNacosClient();
|
||||
assertEquals(ACCESS_KEY_ID, context.getAccessKey());
|
||||
assertEquals(ACCESS_KEY_SECRET, context.getSecretKey());
|
||||
assertEquals(SECURITY_TOKEN, context.getSecurityToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientByEnv() throws NoSuchFieldException, IllegalAccessException {
|
||||
injectMockCredentialsClient();
|
||||
initWithEnvProperties();
|
||||
mockCredentialsClientReturn(credentialModel);
|
||||
ExtensionRamContext context = getCredentialsProvider().getCredentialsForNacosClient();
|
||||
assertEquals(ACCESS_KEY_ID, context.getAccessKey());
|
||||
assertEquals(ACCESS_KEY_SECRET, context.getSecretKey());
|
||||
assertEquals(SECURITY_TOKEN, context.getSecurityToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientWithoutInit() {
|
||||
ExtensionRamContext context = getCredentialsProvider().getCredentialsForNacosClient();
|
||||
assertNull(context.getAccessKey());
|
||||
assertNull(context.getSecretKey());
|
||||
assertNull(context.getSecurityToken());
|
||||
}
|
||||
|
||||
protected void injectMockCredentialsClient() throws NoSuchFieldException, IllegalAccessException {
|
||||
Field clientField = credentialsProvider.getClass().getSuperclass().getDeclaredField("credentialsClient");
|
||||
clientField.setAccessible(true);
|
||||
clientField.set(credentialsProvider, credentialsClient);
|
||||
}
|
||||
|
||||
protected void mockCredentialsClientReturn(CredentialModel credential)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
when(credentialsClient.getCredential()).thenReturn(credential);
|
||||
}
|
||||
|
||||
protected AbstractCredentialClientProvider getCredentialsProvider() {
|
||||
return (AbstractCredentialClientProvider) credentialsProvider;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public abstract class AbstractCredentialsProviderTest {
|
||||
|
||||
protected static final String ACCESS_KEY_ID = "accessKeyId";
|
||||
|
||||
protected static final String ACCESS_KEY_SECRET = "accessKeySecret";
|
||||
|
||||
protected static final String SECURITY_TOKEN = "securityToken";
|
||||
|
||||
protected static final String SIGNATURE_REGION_ID = "signatureRegionId";
|
||||
|
||||
ExtensionCredentialsProvider credentialsProvider;
|
||||
|
||||
Properties properties;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
credentialsProvider = buildCredentialsProvider();
|
||||
properties = new Properties();
|
||||
}
|
||||
|
||||
protected abstract ExtensionCredentialsProvider buildCredentialsProvider();
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws NacosException {
|
||||
credentialsProvider.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchProvider() {
|
||||
assertFalse(credentialsProvider.matchProvider(properties));
|
||||
injectProperties(properties);
|
||||
assertTrue(credentialsProvider.matchProvider(properties));
|
||||
}
|
||||
|
||||
protected void initWithProperties() {
|
||||
injectProperties(properties);
|
||||
credentialsProvider.init(properties);
|
||||
}
|
||||
|
||||
protected void initWithEnvProperties() {
|
||||
injectEnvProperties(properties);
|
||||
credentialsProvider.init(properties);
|
||||
}
|
||||
|
||||
protected abstract void injectProperties(Properties properties);
|
||||
|
||||
protected abstract void injectEnvProperties(Properties properties);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.aliyuncs.kms.secretsmanager.client.SecretCacheClient;
|
||||
import com.aliyuncs.kms.secretsmanager.client.exception.CacheSecretException;
|
||||
import com.aliyuncs.kms.secretsmanager.client.model.SecretInfo;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AutoRotateCredentialsProviderTest extends AbstractCredentialsProviderTest {
|
||||
|
||||
@Mock
|
||||
private SecretCacheClient client;
|
||||
|
||||
@Override
|
||||
protected ExtensionCredentialsProvider buildCredentialsProvider() {
|
||||
return new AutoRotateCredentialsProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECRET_NAME.getKey(), "secretName");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectEnvProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECRET_NAME.getEnvKey(), "secretName");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitWithException() {
|
||||
assertThrows(NacosRuntimeException.class, this::initWithProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClient() throws NoSuchFieldException, IllegalAccessException, CacheSecretException {
|
||||
setClient();
|
||||
initWithProperties();
|
||||
ExtensionRamContext result = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertEquals("accessKeyId", result.getAccessKey());
|
||||
assertEquals("accessKeySecret", result.getSecretKey());
|
||||
assertFalse(result.isEphemeralAccessKeyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientByEnv() throws NoSuchFieldException, IllegalAccessException, CacheSecretException {
|
||||
setClient();
|
||||
initWithEnvProperties();
|
||||
ExtensionRamContext result = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertEquals("accessKeyId", result.getAccessKey());
|
||||
assertEquals("accessKeySecret", result.getSecretKey());
|
||||
assertFalse(result.isEphemeralAccessKeyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientWithException()
|
||||
throws NoSuchFieldException, IllegalAccessException, CacheSecretException {
|
||||
setClient();
|
||||
when(client.getSecretInfo("secretName")).thenThrow(new CacheSecretException());
|
||||
initWithEnvProperties();
|
||||
ExtensionRamContext result = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertNull(result.getAccessKey());
|
||||
assertNull(result.getSecretKey());
|
||||
assertFalse(result.isEphemeralAccessKeyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientWithoutInit() {
|
||||
ExtensionRamContext result = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertNull(result.getAccessKey());
|
||||
assertNull(result.getSecretKey());
|
||||
assertFalse(result.isEphemeralAccessKeyId());
|
||||
}
|
||||
|
||||
private void setClient() throws NoSuchFieldException, IllegalAccessException, CacheSecretException {
|
||||
Field clientField = credentialsProvider.getClass().getDeclaredField("client");
|
||||
clientField.setAccessible(true);
|
||||
clientField.set(credentialsProvider, client);
|
||||
SecretInfo secretInfo = new SecretInfo();
|
||||
secretInfo.setSecretValue("{\"AccessKeyId\":\"accessKeyId\",\"AccessKeySecret\":\"accessKeySecret\"}");
|
||||
when(client.getSecretInfo("secretName")).thenReturn(secretInfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
import com.aliyun.credentials.models.CredentialModel;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CredentialsUriCredentialsProviderTest extends AbstractCredentialClientProviderTest {
|
||||
|
||||
@Override
|
||||
protected ExtensionCredentialsProvider buildCredentialsProvider() {
|
||||
return new CredentialsUriCredentialsProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.CREDENTIALS_URI.getKey(), "http://localhost");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectEnvProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.CREDENTIALS_URI.getEnvKey(), "http://envhost");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfig() {
|
||||
initWithProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("credentials_uri", config.getType());
|
||||
assertEquals("http://localhost", config.getCredentialsUri());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfigByEnv() {
|
||||
initWithEnvProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("credentials_uri", config.getType());
|
||||
assertEquals("http://envhost", config.getCredentialsUri());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
class OidcRoleArnCredentialsProviderTest extends AbstractCredentialClientProviderTest {
|
||||
|
||||
@Override
|
||||
protected ExtensionCredentialsProvider buildCredentialsProvider() {
|
||||
return new OidcRoleArnCredentialsProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_ARN.getKey(), "role_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_NAME.getKey(), "ram_role_arn_test");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN.getKey(), "oidc_provider_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.OIDC_TOKEN_FILE_PATH.getKey(), "oidc_token_file");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectEnvProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_ARN.getEnvKey(), "role_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_NAME.getEnvKey(), "ram_role_arn_test");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.OIDC_PROVIDER_ARN.getEnvKey(), "oidc_provider_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.OIDC_TOKEN_FILE_PATH.getEnvKey(), "oidc_token_file");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfig() {
|
||||
initWithProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("oidc_role_arn", config.getType());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertEquals("oidc_provider_arn", config.getOidcProviderArn());
|
||||
assertEquals("oidc_token_file", config.getOidcTokenFilePath());
|
||||
assertNull(config.getPolicy());
|
||||
assertEquals(3600, config.getRoleSessionExpiration());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfigByEnv() {
|
||||
initWithEnvProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("oidc_role_arn", config.getType());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertEquals("oidc_provider_arn", config.getOidcProviderArn());
|
||||
assertEquals("oidc_token_file", config.getOidcTokenFilePath());
|
||||
assertNull(config.getPolicy());
|
||||
assertEquals(3600, config.getRoleSessionExpiration());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.aliyun.credentials.models.Config;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
class RamRoleArnCredentialsProviderTest extends AbstractCredentialClientProviderTest {
|
||||
|
||||
@Override
|
||||
protected ExtensionCredentialsProvider buildCredentialsProvider() {
|
||||
return new RamRoleArnCredentialsProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_ID.getKey(), ACCESS_KEY_ID);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_SECRET.getKey(), ACCESS_KEY_SECRET);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_ARN.getKey(), "role_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_NAME.getKey(), "ram_role_arn_test");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectEnvProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_ID.getEnvKey(), ACCESS_KEY_ID);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_SECRET.getEnvKey(), ACCESS_KEY_SECRET);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_ARN.getEnvKey(), "role_arn");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_NAME.getEnvKey(), "ram_role_arn_test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfig() {
|
||||
initWithProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("ram_role_arn", config.getType());
|
||||
assertEquals(ACCESS_KEY_ID, config.getAccessKeyId());
|
||||
assertEquals(ACCESS_KEY_SECRET, config.getAccessKeySecret());
|
||||
assertNull(config.getSecurityToken());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertNull(config.getPolicy());
|
||||
assertEquals(3600, config.getRoleSessionExpiration());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfigFull() {
|
||||
initWithProperties();
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECURITY_TOKEN.getKey(), SECURITY_TOKEN);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.POLICY.getKey(), "policy");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_EXPIRATION.getKey(), "360");
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("ram_role_arn", config.getType());
|
||||
assertEquals(ACCESS_KEY_ID, config.getAccessKeyId());
|
||||
assertEquals(ACCESS_KEY_SECRET, config.getAccessKeySecret());
|
||||
assertEquals(SECURITY_TOKEN, config.getSecurityToken());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertEquals("policy", config.getPolicy());
|
||||
assertEquals(360, config.getRoleSessionExpiration());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfigByEnv() {
|
||||
initWithEnvProperties();
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("ram_role_arn", config.getType());
|
||||
assertEquals(ACCESS_KEY_ID, config.getAccessKeyId());
|
||||
assertEquals(ACCESS_KEY_SECRET, config.getAccessKeySecret());
|
||||
assertNull(config.getSecurityToken());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertNull(config.getPolicy());
|
||||
assertEquals(3600, config.getRoleSessionExpiration());
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateCredentialsConfigByEnvFull() {
|
||||
initWithProperties();
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECURITY_TOKEN.getEnvKey(), SECURITY_TOKEN);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.POLICY.getEnvKey(), "policy");
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ROLE_SESSION_EXPIRATION.getEnvKey(), "360");
|
||||
Config config = getCredentialsProvider().generateCredentialsConfig(properties);
|
||||
assertEquals("ram_role_arn", config.getType());
|
||||
assertEquals(ACCESS_KEY_ID, config.getAccessKeyId());
|
||||
assertEquals(ACCESS_KEY_SECRET, config.getAccessKeySecret());
|
||||
assertEquals(SECURITY_TOKEN, config.getSecurityToken());
|
||||
assertEquals("role_arn", config.getRoleArn());
|
||||
assertEquals("ram_role_arn_test", config.getRoleSessionName());
|
||||
assertEquals("policy", config.getPolicy());
|
||||
assertEquals(360, config.getRoleSessionExpiration());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.alibaba.nacos.client.aliyun.auth.provider;
|
||||
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionAuthPropertyKey;
|
||||
import com.alibaba.nacos.client.aliyun.auth.ExtensionRamContext;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
class StsTokenCredentialsProviderTest extends AbstractCredentialsProviderTest {
|
||||
|
||||
@Override
|
||||
protected ExtensionCredentialsProvider buildCredentialsProvider() {
|
||||
return new StsTokenCredentialsProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_ID.getKey(), ACCESS_KEY_ID);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_SECRET.getKey(), ACCESS_KEY_SECRET);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECURITY_TOKEN.getKey(), SECURITY_TOKEN);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SIGNATURE_REGION_ID.getKey(), SIGNATURE_REGION_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectEnvProperties(Properties properties) {
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_ID.getEnvKey(), ACCESS_KEY_ID);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.ACCESS_KEY_SECRET.getEnvKey(), ACCESS_KEY_SECRET);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SECURITY_TOKEN.getEnvKey(), SECURITY_TOKEN);
|
||||
properties.setProperty(ExtensionAuthPropertyKey.SIGNATURE_REGION_ID.getEnvKey(), SIGNATURE_REGION_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClient() {
|
||||
initWithProperties();
|
||||
ExtensionRamContext context = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertEquals(ACCESS_KEY_ID, context.getAccessKey());
|
||||
assertEquals(ACCESS_KEY_SECRET, context.getSecretKey());
|
||||
assertEquals(SECURITY_TOKEN, context.getSecurityToken());
|
||||
assertEquals(SIGNATURE_REGION_ID, context.getExtensionSignatureRegionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientWithEnv() {
|
||||
initWithEnvProperties();
|
||||
ExtensionRamContext context = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertEquals(ACCESS_KEY_ID, context.getAccessKey());
|
||||
assertEquals(ACCESS_KEY_SECRET, context.getSecretKey());
|
||||
assertEquals(SECURITY_TOKEN, context.getSecurityToken());
|
||||
assertEquals(SIGNATURE_REGION_ID, context.getExtensionSignatureRegionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCredentialsForNacosClientWithoutSignatureRegionId() {
|
||||
injectProperties(properties);
|
||||
properties.remove(ExtensionAuthPropertyKey.SIGNATURE_REGION_ID.getKey());
|
||||
credentialsProvider.init(properties);
|
||||
ExtensionRamContext context = credentialsProvider.getCredentialsForNacosClient();
|
||||
assertEquals(ACCESS_KEY_ID, context.getAccessKey());
|
||||
assertEquals(ACCESS_KEY_SECRET, context.getSecretKey());
|
||||
assertEquals(SECURITY_TOKEN, context.getSecurityToken());
|
||||
assertNull(context.getExtensionSignatureRegionId());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue