Skip to content

Commit

Permalink
support for proxy authentication fill-in added
Browse files Browse the repository at this point in the history
  • Loading branch information
sealor committed Sep 6, 2018
1 parent 1b6fb30 commit 487ac7c
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public String supplyContent(Config configFile, Run<?, ?> build, FilePath workDir
String fileContent = super.supplyContent(configFile, build, workDir, listener, tempFiles);
if (!resolvedCredentials.isEmpty()) {
try {
fileContent = CredentialsHelper.fillProxyAuthentication(fileContent, resolvedCredentials);
fileContent = CredentialsHelper.fillAuthentication(fileContent, isReplaceAll, resolvedCredentials, workDir, tempFiles);
} catch (Exception exception) {
throw new IOException("[ERROR] could not insert credentials into the settings file " + configFile, exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public FilePath supplySettings(AbstractBuild<?, ?> build, TaskListener listener)

if (resolvedCredentials != null && !resolvedCredentials.isEmpty()) {
List<String> tempFiles = new ArrayList<String>();
fileContent = CredentialsHelper.fillProxyAuthentication(fileContent, resolvedCredentials);
fileContent = CredentialsHelper.fillAuthentication(fileContent, isReplaceAll, resolvedCredentials, workDir, tempFiles);
for (String tempFile : tempFiles) {
build.addAction(new CleanTempFilesAction(tempFile));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public FilePath supplySettings(AbstractBuild<?, ?> build, TaskListener listener)

if (!resolvedCredentials.isEmpty()) {
List<String> tempFiles = new ArrayList<String>();
fileContent = CredentialsHelper.fillProxyAuthentication(fileContent, resolvedCredentials);
fileContent = CredentialsHelper.fillAuthentication(fileContent, isReplaceAll, resolvedCredentials, workDir, tempFiles);
for (String tempFile : tempFiles) {
build.addAction(new CleanTempFilesAction(tempFile));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@

package org.jenkinsci.plugins.configfiles.maven.security;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import hudson.FilePath;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.util.Secret;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
Expand All @@ -24,24 +26,12 @@
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;

import hudson.FilePath;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.util.Secret;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CredentialsHelper {

Expand Down Expand Up @@ -219,6 +209,59 @@ public static String fillAuthentication(String mavenSettingsContent, final Boole
return content;
}

/**
* @param mavenSettingsContent Maven settings.xml (must be valid XML)
* @param mavenServerId2jenkinsCredential the credentials to be inserted into the XML (key: Maven serverId, value: Jenkins credentials)
* @return the updated version of the {@code mavenSettingsContent} with the server credentials added
*/
public static String fillProxyAuthentication(String mavenSettingsContent,
Map<String, StandardUsernameCredentials> mavenServerId2jenkinsCredential) throws Exception {
String content = mavenSettingsContent;

if (mavenServerId2jenkinsCredential.isEmpty()) {
return mavenSettingsContent;
}

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(content)));

XPath xpath = XPathFactory.newInstance().newXPath();
NodeList proxies = (NodeList) xpath.evaluate("/settings/proxies/proxy", doc, XPathConstants.NODESET);

for (int i = 0; i < proxies.getLength(); i++) {
Node proxy = proxies.item(i);
String proxyId = xpath.evaluate("./id", proxy, XPathConstants.STRING).toString();

StandardUsernameCredentials proxyCredentials = mavenServerId2jenkinsCredential.get(proxyId);
if (proxyCredentials instanceof StandardUsernamePasswordCredentials) {
StandardUsernamePasswordCredentials userCredentials = (StandardUsernamePasswordCredentials) proxyCredentials;

Node proxyUsername = (Node) xpath.evaluate("./username", proxy, XPathConstants.NODE);
if (proxyUsername == null) {
proxyUsername = doc.createElement("username");
proxy.appendChild(proxyUsername);
}
proxyUsername.setTextContent(userCredentials.getUsername());

Node proxyPassword = (Node) xpath.evaluate("./password", proxy, XPathConstants.NODE);
if (proxyPassword == null) {
proxyPassword = doc.createElement("password");
proxy.appendChild(proxyPassword);
}
proxyPassword.setTextContent(Secret.toString(userCredentials.getPassword()));
}
}

// save the result
StringWriter writer = new StringWriter();
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
xformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
xformer.transform(new DOMSource(doc), new StreamResult(writer));
content = writer.toString();

return content;
}

/*
* Copy non credential attributes from a node to other
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,40 @@ public void testIfServerAuthIsReplacedWithinSettingsXmlWhenReplaceFalse() throws

}

@Test
public void testIfServerAuthIsReplacedWithinProxySettingsXmlWhenReplaceTrue() throws Exception {

Map<String, StandardUsernameCredentials> serverId2Credentials = new HashMap<String, StandardUsernameCredentials>();
serverId2Credentials.put("proxy1", new UsernamePasswordCredentialsImpl(CredentialsScope.SYSTEM, "UUID-1", "some desc", "peter", PWD));
serverId2Credentials.put("proxy2", new UsernamePasswordCredentialsImpl(CredentialsScope.SYSTEM, "UUID-2", "some desc2", "dan", PWD_2));

final String settingsContent = IOUtils.toString(CredentialsHelperTest.class.getResourceAsStream("/settings_test.xml"));

final String replacedContent = CredentialsHelper.fillProxyAuthentication(settingsContent, serverId2Credentials);

Assert.assertTrue("replaced settings.xml must contain new password", replacedContent.contains(PWD));

// ensure it is still a valid XML document
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(replacedContent)));
// locate the node(s)
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xpath.evaluate("/settings/proxies/proxy", doc, XPathConstants.NODESET);
Assert.assertEquals("no proxy tag should be removed in the settings.xml", 3, nodes.getLength());

Node proxy1 = (Node) xpath.evaluate("/settings/proxies/proxy[id='proxy1']", doc, XPathConstants.NODE);
Assert.assertEquals("password is not at the correct location", PWD, xpath.evaluate("password", proxy1));
Assert.assertEquals("username is not set correct", "peter", xpath.evaluate("username", proxy1));

Node proxy2 = (Node) xpath.evaluate("/settings/proxies/proxy[id='proxy2']", doc, XPathConstants.NODE);
Assert.assertEquals("password is not set correct", PWD_2, xpath.evaluate("password", proxy2));
Assert.assertEquals("username is not set correct", "dan", xpath.evaluate("username", proxy2));

Node proxy3 = (Node) xpath.evaluate("/settings/proxies/proxy[id='proxy3']", doc, XPathConstants.NODE);
Assert.assertEquals("proxy3 should still not have a password", "", xpath.evaluate("password", proxy3));
Assert.assertEquals("proxy3 should still not have a username", "", xpath.evaluate("username", proxy3));

}

@Test
public void testSettingsXmlIsNotChangedWithoutCredentialsWhenReplaceTrue() throws Exception {

Expand Down
26 changes: 26 additions & 0 deletions src/test/resources/settings_test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@
network. | <proxy> <id>optional</id> <active>true</active> <protocol>http</protocol>
<username>proxyuser</username> <password>proxypass</password> <host>proxy.host.net</host>
<port>80</port> <nonProxyHosts>local.net|some.host.com</nonProxyHosts> </proxy> -->
<proxy>
<id>proxy1</id>
<active>true</active>
<protocol>http</protocol>
<host>129.168.0.1</host>
<port>8080</port>
<username>[placeholder]</username>
<password>[placeholder]</password>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
<proxy>
<id>proxy2</id>
<active>true</active>
<protocol>http</protocol>
<host>129.168.0.2</host>
<port>8080</port>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
<proxy>
<id>proxy3</id>
<active>true</active>
<protocol>http</protocol>
<host>localhost</host>
<port>8080</port>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
</proxies>

<!-- servers | This is a list of authentication profiles, keyed by the server-id
Expand Down

0 comments on commit 487ac7c

Please sign in to comment.