From 956ce5de1e71c900f6f35f3a0761183d188d8567 Mon Sep 17 00:00:00 2001 From: Zihlu Wang Date: Sat, 9 Sep 2023 20:21:34 +0800 Subject: [PATCH] feat(property-guard): Added property-guard to protect the secrets in configuration files. --- .../propertyencryptor/PropertyGuard.java | 96 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + 2 files changed, 97 insertions(+) create mode 100644 property-guard-spring-boot-starter/src/main/java/cn/org/codecrafters/propertyencryptor/PropertyGuard.java create mode 100644 property-guard-spring-boot-starter/src/main/resources/META-INF/spring.factories diff --git a/property-guard-spring-boot-starter/src/main/java/cn/org/codecrafters/propertyencryptor/PropertyGuard.java b/property-guard-spring-boot-starter/src/main/java/cn/org/codecrafters/propertyencryptor/PropertyGuard.java new file mode 100644 index 0000000..c1d95ef --- /dev/null +++ b/property-guard-spring-boot-starter/src/main/java/cn/org/codecrafters/propertyencryptor/PropertyGuard.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 CodeCraftersCN. + * + * 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 cn.org.codecrafters.propertyencryptor; + +import cn.org.codecrafters.devkit.utils.AesUtil; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.SimpleCommandLinePropertySource; + +import java.util.HashMap; +import java.util.Optional; + +/** + * PropertyEncryptor is a utility class designed for encrypting configuration + * information in Spring Boot applications. + *

+ * Spring Boot applications often need to store sensitive configuration details + * such as database passwords, API keys, etc. To ensure that these sensitive + * pieces of information are not exposed, developers can utilize the + * {@code PropertyGuard} class to encrypt and store them within configuration + * files. + *

+ * Usage + * In {@code application.yml} or {@code application.properties}: + *

+ *     # original
+ *     app.example-properties=Sample Value
+ *
+ *     # encrypted with key 3856faef0d2d4f33
+ *     app.example-properties=pe:t4YBfv8M9ZmTzWgTi2gJqg==
+ * 
+ * Then, add the command line arguments like {@code --pe.key=3856faef0d2d4f33}. + *

+ * This class is extracted from MyBatis-Plus. + * + * @author hubin@baomidou + * @see org.springframework.boot.env.EnvironmentPostProcessor + */ +public class PropertyGuard implements EnvironmentPostProcessor { + + /** + * Process the encryption environment variables. + * + * @param environment the environment to post-process + * @param application the application to which the environment belongs + */ + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + // Get the key for encryption from command line. + var encryptionKey = ""; + for (var ps : environment.getPropertySources()) { + if (ps instanceof SimpleCommandLinePropertySource source) { + encryptionKey = source.getProperty("pe.key"); + break; + } + } + + if (Optional.ofNullable(encryptionKey).map((key) -> !key.isEmpty()).orElse(false)) { + var map = new HashMap(); + for (var propertySources : environment.getPropertySources()) { + if (propertySources instanceof OriginTrackedMapPropertySource source) { + for (var name : source.getPropertyNames()) { + if (source.getProperty(name) instanceof String str) { + if (str.startsWith("pe:")) { + map.put(name, AesUtil.decrypt(str.substring(3), encryptionKey)); + } + } + } + } + } + // Put the decrypted data into environment variables, and made them at top-level. + if (!map.isEmpty()) { + environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map)); + } + } + } +} diff --git a/property-guard-spring-boot-starter/src/main/resources/META-INF/spring.factories b/property-guard-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..dcdcd64 --- /dev/null +++ b/property-guard-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.env.EnvironmentPostProcessor=cn.org.codecrafters.propertyencryptor.PropertyGuard \ No newline at end of file