[ISSUE #11544] Supplementary single test, when the prefix of dataId is cipher. (#11546)

* [ISSUE #11544] Supplementary single test, when the prefix of dataId is cipher.

* [ISSUE #11544] Supplementary single test, when the prefix of dataId is cipher. Adjusting code format.

* [ISSUE #11544] Supplementary single test, when the prefix of dataId is cipher. Change static code block to @Before annotation.

* [ISSUE #11544] Supplementary single test, when the prefix of dataId is cipher. run ci.
This commit is contained in:
喻世文 2023-12-27 11:08:23 +08:00 committed by GitHub
parent 9e48e8cb3b
commit 6587029851
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 562 additions and 0 deletions

View File

@ -0,0 +1,201 @@
/*
* Copyright 1999-2018 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.
*/
package com.alibaba.nacos.client.config.filter.impl;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.encryption.EncryptionPluginManager;
import com.alibaba.nacos.plugin.encryption.spi.EncryptionPluginService;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
/**
* AES encryption algorithm testing dataId with prefix cipher.
*
* @Author shiwenyu
* @Date 2023/12/23 9:45 PM
* @Version 1.0
*/
@RunWith(MockitoJUnitRunner.class)
public class ConfigEncryptionFilterTest1 {
private ConfigEncryptionFilter configEncryptionFilter;
private EncryptionPluginService mockEncryptionPluginService;
@Mock
private IConfigFilterChain iConfigFilterChain;
@Before
public void setUp() throws Exception {
mockEncryptionPluginService = new EncryptionPluginService() {
private static final String ALGORITHM = "AES";
private static final String AES_PKCS5P = "AES/ECB/PKCS5Padding";
// 随机生成密钥-用来加密数据内容
private final String contentKey = generateKey();
// 随机生成密钥-用来加密密钥
private final String theKeyOfContentKey = generateKey();
private String generateKey() {
SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyBytes = secretKey.getEncoded();
return Base64.encodeBase64String(keyBytes);
}
@Override
public String encrypt(String secretKey, String content) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, content, secretKey));
}
@Override
public String decrypt(String secretKey, String content) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(content, secretKey);
}
@Override
public String generateSecretKey() {
return contentKey;
}
@Override
public String algorithmName() {
return ALGORITHM.toLowerCase();
}
@Override
public String encryptSecretKey(String secretKey) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, generateSecretKey(), theKeyOfContentKey));
}
@Override
public String decryptSecretKey(String secretKey) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(secretKey, theKeyOfContentKey);
}
private byte[] aes(int mode, String content, String key) {
try {
return aesBytes(mode, content.getBytes(StandardCharsets.UTF_8), key);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private byte[] aesBytes(int mode, byte[] content, String key) {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = null;
try {
cipher = Cipher.getInstance(AES_PKCS5P);
cipher.init(mode, keySpec);
return cipher.doFinal(content);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String aesDecrypt(String content, String key) {
byte[] bytes = aesBytes(Cipher.DECRYPT_MODE, Base64.decodeBase64(content), key);
return new String(bytes, StandardCharsets.UTF_8);
}
};
EncryptionPluginManager.join(mockEncryptionPluginService);
configEncryptionFilter = new ConfigEncryptionFilter();
}
@Test
public void testDoFilterEncryptedData() throws NacosException {
String dataId = "cipher-aes-test";
String content = "nacos";
final String encryptionContent = mockEncryptionPluginService.encrypt(mockEncryptionPluginService.generateSecretKey(), content);
final String theKeyOfContentKey = mockEncryptionPluginService.encryptSecretKey(mockEncryptionPluginService.generateSecretKey());
ConfigRequest configRequest = new ConfigRequest();
configRequest.setDataId(dataId);
configRequest.setContent(content);
configEncryptionFilter.doFilter(configRequest, null, iConfigFilterChain);
Assert.assertEquals(configRequest.getContent(), encryptionContent);
Assert.assertEquals(configRequest.getEncryptedDataKey(), theKeyOfContentKey);
ConfigResponse configResponse = new ConfigResponse();
configResponse.setDataId(dataId);
configResponse.setContent(encryptionContent);
configResponse.setEncryptedDataKey(theKeyOfContentKey);
configEncryptionFilter.doFilter(null, configResponse, iConfigFilterChain);
Assert.assertEquals(configResponse.getContent(), content);
Assert.assertEquals(configResponse.getEncryptedDataKey(), mockEncryptionPluginService.generateSecretKey());
}
@Test
public void testDoFilter() throws NacosException {
String dataId = "test";
String content = "nacos";
ConfigRequest configRequest = new ConfigRequest();
configRequest.setDataId(dataId);
configRequest.setContent(content);
configEncryptionFilter.doFilter(configRequest, null, iConfigFilterChain);
Assert.assertEquals(configRequest.getContent(), content);
Assert.assertEquals(configRequest.getEncryptedDataKey(), "");
ConfigResponse configResponse = new ConfigResponse();
configResponse.setDataId(dataId);
configResponse.setContent(content);
configResponse.setEncryptedDataKey("");
configEncryptionFilter.doFilter(null, configResponse, iConfigFilterChain);
Assert.assertEquals(configResponse.getContent(), content);
Assert.assertEquals(configResponse.getEncryptedDataKey(), "");
}
@Test
public void testGetOrder() {
int order = configEncryptionFilter.getOrder();
Assert.assertEquals(order, 0);
}
}

View File

@ -0,0 +1,235 @@
/*
* Copyright 1999-2018 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.
*/
package com.alibaba.nacos.plugin.encryption.handler;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.plugin.encryption.EncryptionPluginManager;
import com.alibaba.nacos.plugin.encryption.spi.EncryptionPluginService;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* AES encryption algorithm testing dataId with prefix cipher.
*
* @Author shiwenyu
* @Date 2023/12/22 6:07 PM
* @Version 1.0
*/
public class EncryptionAesHandlerTest {
private EncryptionPluginService mockEncryptionPluginService;
@Before
public void setUp() {
mockEncryptionPluginService = new EncryptionPluginService() {
private static final String ALGORITHM = "AES";
private static final String AES_PKCS5P = "AES/ECB/PKCS5Padding";
// 随机生成密钥-用来加密数据内容
private final String contentKey = generateKey();
// 随机生成密钥-用来加密密钥
private final String theKeyOfContentKey = generateKey();
private String generateKey() {
SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyBytes = secretKey.getEncoded();
return Base64.encodeBase64String(keyBytes);
}
@Override
public String encrypt(String secretKey, String content) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, content, secretKey));
}
@Override
public String decrypt(String secretKey, String content) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(content, secretKey);
}
@Override
public String generateSecretKey() {
return contentKey;
}
@Override
public String algorithmName() {
return ALGORITHM.toLowerCase();
}
@Override
public String encryptSecretKey(String secretKey) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, generateSecretKey(), theKeyOfContentKey));
}
@Override
public String decryptSecretKey(String secretKey) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(secretKey, theKeyOfContentKey);
}
private byte[] aes(int mode, String content, String key) {
try {
return aesBytes(mode, content.getBytes(StandardCharsets.UTF_8), key);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private byte[] aesBytes(int mode, byte[] content, String key) {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = null;
try {
cipher = Cipher.getInstance(AES_PKCS5P);
cipher.init(mode, keySpec);
return cipher.doFinal(content);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String aesDecrypt(String content, String key) {
byte[] bytes = aesBytes(Cipher.DECRYPT_MODE, Base64.decodeBase64(content), key);
return new String(bytes, StandardCharsets.UTF_8);
}
};
EncryptionPluginManager.join(mockEncryptionPluginService);
}
@Test
public void testEncrypt() {
String content = "content";
String contentKey = mockEncryptionPluginService.generateSecretKey();
Pair<String, String> pair = EncryptionHandler.encryptHandler("cipher-aes-dataId", content);
Assert.assertEquals("should return the encryption secret key if algorithm defined.", mockEncryptionPluginService.encryptSecretKey(contentKey),
pair.getFirst());
Assert.assertEquals("should return the encryption content if algorithm defined.", mockEncryptionPluginService.encrypt(contentKey, content),
pair.getSecond());
}
@Test
public void testDecrypt() {
String content = "content";
String contentKey = mockEncryptionPluginService.generateSecretKey();
String encryptionSecretKey = mockEncryptionPluginService.encryptSecretKey(contentKey);
String encryptionContent = mockEncryptionPluginService.encrypt(contentKey, content);
Pair<String, String> pair = EncryptionHandler.decryptHandler("cipher-aes-dataId", encryptionSecretKey, encryptionContent);
Assert.assertEquals("should return the original secret key if algorithm defined.", mockEncryptionPluginService.generateSecretKey(),
pair.getFirst());
Assert.assertEquals("should return the original content if algorithm defined.", content, pair.getSecond());
}
@Test
public void testEncryptAndDecrypt() {
String dataId = "cipher-aes-dataId";
String content = "content";
String contentKey = mockEncryptionPluginService.generateSecretKey();
Pair<String, String> encryptPair = EncryptionHandler.encryptHandler(dataId, content);
String encryptionSecretKey = encryptPair.getFirst();
String encryptionContent = encryptPair.getSecond();
Assert.assertNotNull(encryptPair);
Assert.assertEquals("should return the encryption secret key if algorithm defined.", mockEncryptionPluginService.encryptSecretKey(contentKey),
encryptionSecretKey);
Assert.assertEquals("should return the encryption content if algorithm defined.", mockEncryptionPluginService.encrypt(contentKey, content),
encryptionContent);
Pair<String, String> decryptPair = EncryptionHandler.decryptHandler(dataId, encryptionSecretKey, encryptionContent);
Assert.assertNotNull(decryptPair);
Assert.assertEquals("should return the original secret key if algorithm defined.", mockEncryptionPluginService.generateSecretKey(),
decryptPair.getFirst());
Assert.assertEquals("should return the original content if algorithm defined.", content, decryptPair.getSecond());
}
@Test
public void testPrefixNotCipherEncrypt() {
String content = "content";
Pair<String, String> pair = EncryptionHandler.encryptHandler("test-dataId", content);
Assert.assertNotNull(pair);
Assert.assertEquals(pair.getFirst(), "");
Assert.assertEquals(pair.getSecond(), content);
}
@Test
public void testPrefixNotCipherDecrypt() {
String content = "content";
Pair<String, String> pair = EncryptionHandler.decryptHandler("test-dataId", "", content);
Assert.assertNotNull(pair);
Assert.assertEquals(pair.getFirst(), "");
Assert.assertEquals(pair.getSecond(), content);
}
@Test
public void testAlgorithmEmpty() {
String dataId = "cipher-";
String content = "content";
Pair<String, String> pair = EncryptionHandler.encryptHandler(dataId, content);
Assert.assertNotNull("should not throw exception when parsing enc algo for dataId '" + dataId + "'", pair);
Assert.assertEquals(pair.getFirst(), "");
Assert.assertEquals(pair.getSecond(), content);
}
@Test
public void testUnknownAlgorithmNameEncrypt() {
String dataId = "cipher-mySM4-application";
String content = "content";
Pair<String, String> pair = EncryptionHandler.encryptHandler(dataId, content);
Assert.assertNotNull(pair);
Assert.assertEquals(pair.getFirst(), "");
Assert.assertEquals("should return original content if algorithm is not defined.", content, pair.getSecond());
}
@Test
public void testUnknownAlgorithmNameDecrypt() {
String dataId = "cipher-mySM4-application";
String content = "content";
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, "", content);
Assert.assertNotNull(pair);
Assert.assertEquals(pair.getFirst(), "");
Assert.assertEquals("should return original content if algorithm is not defined.", content, pair.getSecond());
}
}

View File

@ -28,7 +28,18 @@ import com.alibaba.nacos.client.config.http.MetricsHttpAgent;
import com.alibaba.nacos.client.config.http.ServerHttpAgent;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.plugin.encryption.EncryptionPluginManager;
import com.alibaba.nacos.plugin.encryption.spi.EncryptionPluginService;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -65,6 +76,100 @@ public abstract class AbstractConfigAPI_CITCase {
@LocalServerPort
private int port;
private EncryptionPluginService mockEncryptionPluginService;
@Before
public void initEncryptionPluginService() {
mockEncryptionPluginService = new EncryptionPluginService() {
private static final String ALGORITHM = "AES";
private static final String AES_PKCS5P = "AES/ECB/PKCS5Padding";
// 随机生成密钥-用来加密数据内容
private final String contentKey = generateKey();
// 随机生成密钥-用来加密密钥
private final String theKeyOfContentKey = generateKey();
private String generateKey() {
SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] keyBytes = secretKey.getEncoded();
return Base64.encodeBase64String(keyBytes);
}
@Override
public String encrypt(String secretKey, String content) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, content, secretKey));
}
@Override
public String decrypt(String secretKey, String content) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(content, secretKey);
}
@Override
public String generateSecretKey() {
return contentKey;
}
@Override
public String algorithmName() {
return ALGORITHM.toLowerCase();
}
@Override
public String encryptSecretKey(String secretKey) {
return Base64.encodeBase64String(aes(Cipher.ENCRYPT_MODE, generateSecretKey(), theKeyOfContentKey));
}
@Override
public String decryptSecretKey(String secretKey) {
if (StringUtils.isBlank(secretKey)) {
return null;
}
return aesDecrypt(secretKey, theKeyOfContentKey);
}
private byte[] aes(int mode, String content, String key) {
try {
return aesBytes(mode, content.getBytes(StandardCharsets.UTF_8), key);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private byte[] aesBytes(int mode, byte[] content, String key) {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Cipher cipher = null;
try {
cipher = Cipher.getInstance(AES_PKCS5P);
cipher.init(mode, keySpec);
return cipher.doFinal(content);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String aesDecrypt(String content, String key) {
byte[] bytes = aesBytes(Cipher.DECRYPT_MODE, Base64.decodeBase64(content), key);
return new String(bytes, StandardCharsets.UTF_8);
}
};
EncryptionPluginManager.join(mockEncryptionPluginService);
}
@Before
public void setUp() throws Exception {
Properties properties = new Properties();
@ -116,6 +221,27 @@ public abstract class AbstractConfigAPI_CITCase {
Assert.assertNull(value);
}
/**
* @TCDescription : nacos_正常推送&获取加密数据
* @TestStep :
* @ExpectResult :
*/
@Test(timeout = 3 * TIME_OUT)
public void nacosPublishAndGetConfig() throws Exception {
String dataId = "cipher-aes-dataId";
final String content = "test";
boolean result = iconfig.publishConfig(dataId, group, content);
Thread.sleep(TIME_OUT);
Assert.assertTrue(result);
String value = iconfig.getConfig(dataId, group, TIME_OUT);
Assert.assertEquals(content, value);
result = iconfig.removeConfig(dataId, group);
Thread.sleep(TIME_OUT);
Assert.assertTrue(result);
value = iconfig.getConfig(dataId, group, TIME_OUT);
Assert.assertNull(value);
}
/**
* @throws Exception
* @TCDescription : nacos_服务端无配置时获取配置