From 161c501ed31908b9c1be46fea8ce09b206453d07 Mon Sep 17 00:00:00 2001 From: Aliaksei Date: Wed, 20 Jan 2021 23:19:48 +0300 Subject: [PATCH] Add possibility to reload secrets from properties file with JCasC reload (#1556) --- .../casc/PropertiesSecretSourceTest.java | 43 ++++++++++++++++++- .../impl/secrets/PropertiesSecretSource.java | 36 +++++++--------- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/integrations/src/test/java/io/jenkins/plugins/casc/PropertiesSecretSourceTest.java b/integrations/src/test/java/io/jenkins/plugins/casc/PropertiesSecretSourceTest.java index eeebc97648..6493fd84f5 100644 --- a/integrations/src/test/java/io/jenkins/plugins/casc/PropertiesSecretSourceTest.java +++ b/integrations/src/test/java/io/jenkins/plugins/casc/PropertiesSecretSourceTest.java @@ -4,8 +4,13 @@ import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials; import io.jenkins.plugins.casc.misc.ConfiguredWithCode; import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.InputStream; import java.util.Collections; import java.util.List; +import java.util.Properties; import jenkins.model.Jenkins; import org.junit.Rule; import org.junit.Test; @@ -16,6 +21,8 @@ public class PropertiesSecretSourceTest { + private static final String USERNAME_SECRET = "ken"; + @Rule public RuleChain chain = RuleChain.outerRule(new EnvironmentVariables() .set("SECRETS_FILE", getClass().getResource("secrets.properties").getFile())) @@ -23,7 +30,7 @@ public class PropertiesSecretSourceTest { @Test @ConfiguredWithCode("PropertiesSecretSourceTest.yaml") - public void test_reading_secrets_from_properties() throws Exception { + public void testReadingSecretsFromProperties() throws Exception { List credentialList = CredentialsProvider .lookupCredentials(UsernamePasswordCredentials.class, Jenkins.getInstanceOrNull(), null, Collections.emptyList()); @@ -32,7 +39,39 @@ public void test_reading_secrets_from_properties() throws Exception { UsernamePasswordCredentials credentials = credentialList.get(0); // https://leahneukirchen.org/blog/archive/2019/10/ken-thompson-s-unix-password.html - assertEquals("ken", credentials.getUsername()); + assertEquals(USERNAME_SECRET, credentials.getUsername()); assertEquals("p/q2-q4!", credentials.getPassword().getPlainText()); } + + @Test + @ConfiguredWithCode("PropertiesSecretSourceTest.yaml") + public void testSecretsFromPropertiesAreUpdatedAfterReload() throws Exception { + File secretsFile = new File(getClass().getResource("secrets.properties").getFile()); + Properties secrets = new Properties(); + InputStream inputStream = new FileInputStream(secretsFile); + secrets.load(inputStream); + + FileWriter fileWriter = new FileWriter(secretsFile); + + String secretName = "testuser"; + String updatedTestUserSecret = "charmander"; + secrets.setProperty(secretName, updatedTestUserSecret); + try { + secrets.store(fileWriter, "store to properties file"); + + ConfigurationAsCode.get().configure(this.getClass().getResource("PropertiesSecretSourceTest.yaml").toString()); + + List credentialList = CredentialsProvider + .lookupCredentials(UsernamePasswordCredentials.class, + Jenkins.getInstanceOrNull(), null, Collections.emptyList()); + assertEquals(1, credentialList.size()); + + UsernamePasswordCredentials credentials = credentialList.get(0); + + assertEquals(updatedTestUserSecret, credentials.getUsername()); + } finally { + secrets.setProperty(secretName, USERNAME_SECRET); + secrets.store(fileWriter, "store to properties file"); + } + } } diff --git a/plugin/src/main/java/io/jenkins/plugins/casc/impl/secrets/PropertiesSecretSource.java b/plugin/src/main/java/io/jenkins/plugins/casc/impl/secrets/PropertiesSecretSource.java index 136ccb7faa..6e227e86b5 100644 --- a/plugin/src/main/java/io/jenkins/plugins/casc/impl/secrets/PropertiesSecretSource.java +++ b/plugin/src/main/java/io/jenkins/plugins/casc/impl/secrets/PropertiesSecretSource.java @@ -32,30 +32,26 @@ public class PropertiesSecretSource extends SecretSource { */ public static final String SECRETS_DEFAULT_PATH = "/run/secrets/secrets.properties"; - private Properties secrets; + private final Properties secrets = new Properties(); @Override public Optional reveal(String secret) { - // lazy initialization - if (secrets == null) { - secrets = new Properties(); - final String secretsEnv = System.getenv("SECRETS_FILE"); - final String secretsPath = secretsEnv == null ? SECRETS_DEFAULT_PATH : secretsEnv; - final File secretsFile = new File(secretsPath); - if (secretsFile.exists() && secretsFile.isFile()) { - try (InputStream input = new FileInputStream(secretsFile)) { - secrets.load(input); - } catch (IOException ioe) { - LOGGER.log(Level.WARNING, - "Source properties file " + secretsPath + " could not be loaded", ioe); - } - } - } + return Optional.ofNullable(secrets.getProperty(secret)); + } - if (secrets.getProperty(secret) == null) { - return Optional.empty(); - } else { - return Optional.of(secrets.getProperty(secret)); + @Override + public void init() { + final String secretsEnv = System.getenv("SECRETS_FILE"); + final String secretsPath = secretsEnv == null ? SECRETS_DEFAULT_PATH : secretsEnv; + final File secretsFile = new File(secretsPath); + if (secretsFile.exists() && secretsFile.isFile()) { + try (InputStream input = new FileInputStream(secretsFile)) { + secrets.clear(); + secrets.load(input); + } catch (IOException ioe) { + LOGGER.log(Level.WARNING, + "Source properties file " + secretsPath + " could not be loaded", ioe); + } } } }