From 487ac7c47d96d1aa5d86714c33906c99f23a8984 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 6 Sep 2018 18:23:12 +0200 Subject: [PATCH] support for proxy authentication fill-in added --- .../maven/AbstractMavenSettingsProvider.java | 1 + .../maven/job/MvnGlobalSettingsProvider.java | 1 + .../maven/job/MvnSettingsProvider.java | 1 + .../maven/security/CredentialsHelper.java | 105 ++++++++++++------ .../maven/security/CredentialsHelperTest.java | 34 ++++++ src/test/resources/settings_test.xml | 26 +++++ 6 files changed, 137 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/configfiles/maven/AbstractMavenSettingsProvider.java b/src/main/java/org/jenkinsci/plugins/configfiles/maven/AbstractMavenSettingsProvider.java index e1aeb7b8..8f34d74b 100644 --- a/src/main/java/org/jenkinsci/plugins/configfiles/maven/AbstractMavenSettingsProvider.java +++ b/src/main/java/org/jenkinsci/plugins/configfiles/maven/AbstractMavenSettingsProvider.java @@ -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); diff --git a/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnGlobalSettingsProvider.java b/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnGlobalSettingsProvider.java index ca646abd..380dbc9e 100644 --- a/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnGlobalSettingsProvider.java +++ b/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnGlobalSettingsProvider.java @@ -97,6 +97,7 @@ public FilePath supplySettings(AbstractBuild build, TaskListener listener) if (resolvedCredentials != null && !resolvedCredentials.isEmpty()) { List tempFiles = new ArrayList(); + fileContent = CredentialsHelper.fillProxyAuthentication(fileContent, resolvedCredentials); fileContent = CredentialsHelper.fillAuthentication(fileContent, isReplaceAll, resolvedCredentials, workDir, tempFiles); for (String tempFile : tempFiles) { build.addAction(new CleanTempFilesAction(tempFile)); diff --git a/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnSettingsProvider.java b/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnSettingsProvider.java index f34e3d8c..9e4d6e25 100644 --- a/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnSettingsProvider.java +++ b/src/main/java/org/jenkinsci/plugins/configfiles/maven/job/MvnSettingsProvider.java @@ -97,6 +97,7 @@ public FilePath supplySettings(AbstractBuild build, TaskListener listener) if (!resolvedCredentials.isEmpty()) { List tempFiles = new ArrayList(); + fileContent = CredentialsHelper.fillProxyAuthentication(fileContent, resolvedCredentials); fileContent = CredentialsHelper.fillAuthentication(fileContent, isReplaceAll, resolvedCredentials, workDir, tempFiles); for (String tempFile : tempFiles) { build.addAction(new CleanTempFilesAction(tempFile)); diff --git a/src/main/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelper.java b/src/main/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelper.java index 0ecf7624..851b0735 100644 --- a/src/main/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelper.java +++ b/src/main/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelper.java @@ -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; @@ -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 { @@ -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 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 */ diff --git a/src/test/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelperTest.java b/src/test/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelperTest.java index 19a177b0..42e88496 100644 --- a/src/test/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelperTest.java +++ b/src/test/java/org/jenkinsci/plugins/configfiles/maven/security/CredentialsHelperTest.java @@ -91,6 +91,40 @@ public void testIfServerAuthIsReplacedWithinSettingsXmlWhenReplaceFalse() throws } + @Test + public void testIfServerAuthIsReplacedWithinProxySettingsXmlWhenReplaceTrue() throws Exception { + + Map serverId2Credentials = new HashMap(); + 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 { diff --git a/src/test/resources/settings_test.xml b/src/test/resources/settings_test.xml index a317ea7f..f01e6ae5 100644 --- a/src/test/resources/settings_test.xml +++ b/src/test/resources/settings_test.xml @@ -59,6 +59,32 @@ network. | optional true http proxyuser proxypass proxy.host.net 80 local.net|some.host.com --> + + proxy1 + true + http + 129.168.0.1 + 8080 + [placeholder] + [placeholder] + localhost|127.0.0.1 + + + proxy2 + true + http + 129.168.0.2 + 8080 + localhost|127.0.0.1 + + + proxy3 + true + http + localhost + 8080 + localhost|127.0.0.1 +