Skip to content

Commit

Permalink
Fix ProxyConfigurator does not resolve secrets (#916)
Browse files Browse the repository at this point in the history
Co-authored-by: Joseph Petersen <josephp90@gmail.com>
  • Loading branch information
velma and jetersen committed Jun 7, 2019
1 parent 421ff5b commit 3a67b90
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.ProxyConfiguration;
import hudson.util.Secret;
import io.jenkins.plugins.casc.Attribute;
import io.jenkins.plugins.casc.BaseConfigurator;
import io.jenkins.plugins.casc.ConfigurationContext;
import io.jenkins.plugins.casc.Configurator;
import io.jenkins.plugins.casc.ConfiguratorException;
import io.jenkins.plugins.casc.model.Mapping;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import static io.jenkins.plugins.casc.Attribute.noop;

Expand All @@ -26,27 +30,18 @@ public Class<ProxyConfiguration> getTarget() {
return ProxyConfiguration.class;
}

@NonNull
@Override
protected void configure(Mapping config, ProxyConfiguration instance, boolean dryrun,
ConfigurationContext context) throws ConfiguratorException {
super.configure(config, instance, dryrun, context);
public Class getImplementedAPI() {
return ProxyConfigurationDataBounded.class;
}

@Override
protected ProxyConfiguration instance(Mapping mapping, ConfigurationContext context) throws ConfiguratorException {
Set<String> keys = mapping.keySet();
return new ProxyConfiguration(
mapping.getScalarValue("name"),
Integer.parseInt(mapping.getScalarValue("port")),
getOptionalParam(mapping, keys, "userName"),
getOptionalParam(mapping, keys, "password"),
getOptionalParam(mapping, keys, "noProxyHost"),
getOptionalParam(mapping, keys, "testUrl")
);
}

private String getOptionalParam(Mapping mapping, Set<String> keys, String key) throws ConfiguratorException {
return keys.contains(key) ? mapping.getScalarValue(key) : null;
final Configurator<ProxyConfigurationDataBounded> c = context.lookupOrFail(ProxyConfigurationDataBounded.class);
final ProxyConfigurationDataBounded proxy = c.configure(mapping, context);
return new ProxyConfiguration(proxy.name, proxy.port, proxy.userName,
Secret.toString(proxy.password), proxy.noProxyHost, proxy.testUrl);
}

@NonNull
Expand All @@ -73,4 +68,64 @@ private String getOptionalParam(Mapping mapping, Set<String> keys, String key) t
.setter(noop())
));
}

@Restricted(NoExternalUse.class)
public static class ProxyConfigurationDataBounded {
private final String name;
private final int port;
private String userName;
private String noProxyHost;
private Secret password;
private String testUrl;

@DataBoundConstructor
public ProxyConfigurationDataBounded(String name, int port) {
this.name = name;
this.port = port;
}

public String getName() {
return name;
}

public int getPort() {
return port;
}

public String getUserName() {
return userName;
}

@DataBoundSetter
public void setUserName(String userName) {
this.userName = userName;
}

public String getNoProxyHost() {
return noProxyHost;
}

@DataBoundSetter
public void setNoProxyHost(String noProxyHost) {
this.noProxyHost = noProxyHost;
}

public Secret getPassword() {
return password;
}

@DataBoundSetter
public void setPassword(Secret password) {
this.password = password;
}

public String getTestUrl() {
return testUrl;
}

@DataBoundSetter
public void setTestUrl(String testUrl) {
this.testUrl = testUrl;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import io.jenkins.plugins.casc.Configurator;
import io.jenkins.plugins.casc.ConfiguratorRegistry;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.Env;
import io.jenkins.plugins.casc.misc.EnvVarsRule;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import io.jenkins.plugins.casc.model.CNode;
import io.jenkins.plugins.casc.model.Mapping;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;

import static io.jenkins.plugins.casc.misc.Util.getJenkinsRoot;
import static io.jenkins.plugins.casc.misc.Util.toYamlString;
Expand All @@ -21,8 +24,12 @@

public class ProxyConfiguratorTest {

final JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();

@Rule
public JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();
public RuleChain chain = RuleChain
.outerRule(new EnvVarsRule())
.around(j);

@Test
@ConfiguredWithCode("Proxy.yml")
Expand Down Expand Up @@ -67,6 +74,25 @@ public void shouldSetProxyWithMinimumFields() throws Exception {
assertEquals("", Secret.decrypt(mapping.getScalarValue("password")).getPlainText());
}

@Test
@Env(name = "PROXY_HOST", value = "proxyhost")
@Env(name = "PROXY_PORT", value = "80")
@Env(name = "PROXY_USER", value = "proxy_user")
@Env(name = "PROXY_PASSWORD", value = "proxy_password")
@Env(name = "PROXY_NOPROXY", value = "external.host")
@Env(name = "PROXY_TEST_URL", value = "http://google.com")
@ConfiguredWithCode("ProxyWithSecrets.yml")
public void shouldSetProxyWithSecretInFields() {
ProxyConfiguration proxy = j.jenkins.proxy;
assertEquals(proxy.name, "proxyhost");
assertEquals(proxy.port, 80);

assertEquals(proxy.getUserName(), "proxy_user");
assertEquals(Secret.decrypt(proxy.getEncryptedPassword()).getPlainText(), "proxy_password");
assertEquals(proxy.noProxyHost, "external.host");
assertEquals(proxy.getTestUrl(), "http://google.com");
}

@Test
@ConfiguredWithCode("Proxy.yml")
public void describeProxyConfig() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
jenkins:
proxy:
name: "${PROXY_HOST}"
port: ${PROXY_PORT}
userName: "${PROXY_USER}"
password: "${PROXY_PASSWORD}"
noProxyHost: "${PROXY_NOPROXY}"
testUrl: "${PROXY_TEST_URL}"

0 comments on commit 3a67b90

Please sign in to comment.