Skip to content
Permalink
Browse files
Merge pull request #120 from escoem/JENKINS-41653
[JENKINS-41653] Support core warning when collecting data
  • Loading branch information
batmat committed Nov 13, 2017
2 parents eabbb45 + 653b6c7 commit ef1f4092bda8cf4fd4cbe22dd34c77cbd91a287c
@@ -3,6 +3,7 @@
import com.cloudbees.plugins.credentials.SecretBytes;
import hudson.util.Secret;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -20,6 +21,8 @@
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;
@@ -35,6 +38,14 @@
*/
protected static final String SECRET_MARKER = "#secret#";
public static final String OUTPUT_ENCODING = "UTF-8";
public static final Pattern SECRET_PATTERN = Pattern.compile(">\\{(.*)\\}<|>(.*)\\=<");

/**
* Enabled by default.
* FALLBACK will be disable in case you define a system property like -Dsupport-core-plugin.SecretHandler.ENABLE_FALLBACK=false
* Otherwise will be enabled.
*/
private static boolean ENABLE_FALLBACK = !StringUtils.equalsIgnoreCase(System.getProperty("support-core-plugin.SecretHandler.ENABLE_FALLBACK", "TRUE"), "FALSE");

/**
* find the secret in the xml file and replace it with the place holder
@@ -66,7 +77,8 @@ public void characters(char[] ch, int start, int length) throws SAXException {
if (!"".equals(tagName)) {
String value = new String(ch, start, length).trim();
//if it's a secret, then use a place holder
if (!"".equals(value)) {
// convenience check !"{}".equals(value) because of JENKINS-47500
if (!"".equals(value) && !"{}".equals(value)) {
if ((Secret.decrypt(value)) != null || SecretBytes.isSecretBytes(value)) {
ch = SECRET_MARKER.toCharArray();
start = 0;
@@ -77,15 +89,41 @@ public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
}
};
Source src = new SAXSource(xr, new InputSource(new StringReader(FileUtils.readFileToString(xmlFile))));
String str = FileUtils.readFileToString(xmlFile);
Source src = new SAXSource(xr, new InputSource(new StringReader(str)));
final ByteArrayOutputStream result = new ByteArrayOutputStream();
Result res = new StreamResult(result);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
//omit xml declaration because of https://bugs.openjdk.java.net/browse/JDK-8035437
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, OUTPUT_ENCODING);
transformer.transform(src, res);

return result.toString("UTF-8");
try {
transformer.transform(src, res);
return result.toString("UTF-8");
} catch (TransformerException e) {
if (ENABLE_FALLBACK) {
return findSecretFallback(str);
} else {
throw e;
}
}
}


private static String findSecretFallback(String xml) {
Matcher matcher = SECRET_PATTERN.matcher(xml);
while(matcher.find()) {
String secret = matcher.group();
if(secret.length() > 1)
secret = secret.substring(1,secret.length()-1);
if ((Secret.decrypt(secret)) != null || SecretBytes.isSecretBytes(secret)) {
xml = StringUtils.replace(xml, secret, SECRET_MARKER);
}
}

return xml;
}


}
@@ -0,0 +1,91 @@
package com.cloudbees.jenkins.support.configfiles;

import com.cloudbees.plugins.credentials.SecretBytes;
import hudson.util.Secret;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.File;

import static org.junit.Assert.assertEquals;

public class SecretHandlerTest {

@Rule
public JenkinsRule r = new JenkinsRule();

private String xml;

private final String expectedXml = "<com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin=\"credentials@1.18\">\n" +
" <domainCredentialsMap class=\"hudson.util.CopyOnWriteMap$Hash\">\n" +
" <entry>\n" +
" <com.cloudbees.plugins.credentials.domains.Domain>\n" +
" <specifications/>\n" +
" </com.cloudbees.plugins.credentials.domains.Domain>\n" +
" <java.util.concurrent.CopyOnWriteArrayList>\n" +
" <com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <scope>GLOBAL</scope>\n" +
" <id>f9ebaa5c-a7fc-46e4-93ab-453699781181</id>\n" +
" <description>Alice</description>\n" +
" <username/>\n" +
" <password>" + SecretHandler.SECRET_MARKER + "</password>\n" +
" </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <scope>GLOBAL</scope>\n" +
" <id>f9ebaa5c-a7fc-46e4-93ab-453699781182</id>\n" +
" <description>Bobby&#0x;</description>\n" +
" <username/>\n" +
" <password>" + SecretHandler.SECRET_MARKER + "</password>\n" +
" </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" </java.util.concurrent.CopyOnWriteArrayList>\n" +
" </entry>\n" +
" </domainCredentialsMap>\n" +
"</com.cloudbees.plugins.credentials.SystemCredentialsProvider>";

@Before
public void setup() {
Secret secret = Secret.fromString("this-is-a-secret");
SecretBytes secret2 = SecretBytes.fromBytes("this-is-another-type-of-secret".getBytes());
assertEquals("this-is-a-secret", secret.getPlainText());
assertEquals("this-is-another-type-of-secret", new String(secret2.getPlainData()));
String encrypted_secret = secret.getEncryptedValue();
String encrypted_secret2 = secret2.toString();
xml = "<com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin=\"credentials@1.18\">\n" +
" <domainCredentialsMap class=\"hudson.util.CopyOnWriteMap$Hash\">\n" +
" <entry>\n" +
" <com.cloudbees.plugins.credentials.domains.Domain>\n" +
" <specifications/>\n" +
" </com.cloudbees.plugins.credentials.domains.Domain>\n" +
" <java.util.concurrent.CopyOnWriteArrayList>\n" +
" <com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <scope>GLOBAL</scope>\n" +
" <id>f9ebaa5c-a7fc-46e4-93ab-453699781181</id>\n" +
" <description>Alice</description>\n" +
" <username/>\n" +
" <password>" + encrypted_secret + "</password>\n" +
" </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" <scope>GLOBAL</scope>\n" +
" <id>f9ebaa5c-a7fc-46e4-93ab-453699781182</id>\n" +
" <description>Bobby&#0x;</description>\n" +
" <username/>\n" +
" <password>" + encrypted_secret2 + "</password>\n" +
" </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>\n" +
" </java.util.concurrent.CopyOnWriteArrayList>\n" +
" </entry>\n" +
" </domainCredentialsMap>\n" +
"</com.cloudbees.plugins.credentials.SystemCredentialsProvider>";
}

@Issue("JENKINS-41653")
@Test
public void shouldPutAPlaceHolderInsteadOfSecret() throws Exception {
File file = File.createTempFile("test", ".xml");
FileUtils.writeStringToFile(file, xml);
String patchedXml = SecretHandler.findSecrets(file);
assertEquals(expectedXml, patchedXml);
}}

0 comments on commit ef1f409

Please sign in to comment.