Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the ability to inject global passwords in the EnvInject plugin
Fix JENKINS-12423
- Loading branch information
1 parent
3faee33
commit 9bbe67a
Showing
10 changed files
with
352 additions
and
1 deletion.
There are no files selected for viewing
30 changes: 30 additions & 0 deletions
30
src/main/java/org/jenkinsci/plugins/envinject/EnvInjectGlobalPasswordEntry.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.jenkinsci.plugins.envinject; | ||
|
||
import hudson.util.Secret; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
|
||
import java.io.Serializable; | ||
|
||
/** | ||
* @author Gregory Boissinot | ||
*/ | ||
public class EnvInjectGlobalPasswordEntry implements Serializable { | ||
|
||
private String name; | ||
|
||
private Secret value; | ||
|
||
@DataBoundConstructor | ||
public EnvInjectGlobalPasswordEntry(String name, String password) { | ||
this.name = name; | ||
this.value = Secret.fromString(password); | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Secret getValue() { | ||
return value; | ||
} | ||
} |
155 changes: 155 additions & 0 deletions
155
src/main/java/org/jenkinsci/plugins/envinject/EnvInjectGlobalPasswordWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package org.jenkinsci.plugins.envinject; | ||
|
||
import hudson.Extension; | ||
import hudson.Launcher; | ||
import hudson.console.LineTransformationOutputStream; | ||
import hudson.model.AbstractBuild; | ||
import hudson.model.AbstractProject; | ||
import hudson.model.BuildListener; | ||
import hudson.model.Run; | ||
import hudson.tasks.BuildWrapper; | ||
import hudson.tasks.BuildWrapperDescriptor; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.jenkinsci.lib.envinject.EnvInjectException; | ||
import org.jenkinsci.plugins.envinject.service.EnvInjectGlobalPasswordRetriever; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* @author Gregory Boissinot | ||
*/ | ||
public class EnvInjectGlobalPasswordWrapper extends BuildWrapper { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(EnvInjectGlobalPasswordWrapper.class.getName()); | ||
|
||
@DataBoundConstructor | ||
public EnvInjectGlobalPasswordWrapper() { | ||
} | ||
|
||
@Override | ||
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { | ||
return new Environment() { | ||
}; | ||
} | ||
|
||
/** | ||
* Class took from the mask-passwords plugin | ||
*/ | ||
class MaskPasswordsOutputStream extends LineTransformationOutputStream { | ||
|
||
private final static String MASKED_PASSWORD = "********"; | ||
|
||
private final OutputStream logger; | ||
private final Pattern passwordsAsPattern; | ||
|
||
MaskPasswordsOutputStream(OutputStream logger, Collection<String> passwords) { | ||
|
||
this.logger = logger; | ||
|
||
if (passwords != null && passwords.size() > 0) { | ||
// passwords are aggregated into a regex which is compiled as a pattern | ||
// for efficiency | ||
StringBuilder regex = new StringBuilder().append('('); | ||
|
||
int nbMaskedPasswords = 0; | ||
for (String password : passwords) { | ||
if (StringUtils.isNotEmpty(password)) { // we must not handle empty passwords | ||
regex.append(Pattern.quote(password)); | ||
regex.append('|'); | ||
nbMaskedPasswords++; | ||
} | ||
} | ||
if (nbMaskedPasswords++ >= 1) { // is there at least one password to mask? | ||
regex.deleteCharAt(regex.length() - 1); // removes the last unuseful pipe | ||
regex.append(')'); | ||
passwordsAsPattern = Pattern.compile(regex.toString()); | ||
} else { // no passwords to hide | ||
passwordsAsPattern = null; | ||
} | ||
} else { // no passwords to hide | ||
passwordsAsPattern = null; | ||
} | ||
} | ||
|
||
@Override | ||
protected void eol(byte[] bytes, int len) throws IOException { | ||
String line = new String(bytes, 0, len); | ||
if (passwordsAsPattern != null) { | ||
line = passwordsAsPattern.matcher(line).replaceAll(MASKED_PASSWORD); | ||
} | ||
logger.write(line.getBytes()); | ||
} | ||
|
||
} | ||
|
||
@Override | ||
public OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException, Run.RunnerAbortedException { | ||
|
||
List<String> passwords = new ArrayList<String>(); | ||
try { | ||
//Put Clear passwords | ||
EnvInjectGlobalPasswordRetriever globalPasswordRetriever = new EnvInjectGlobalPasswordRetriever(); | ||
EnvInjectGlobalPasswordEntry[] passwordEntries = globalPasswordRetriever.getGlobalPasswords(); | ||
if (passwordEntries != null) { | ||
for (EnvInjectGlobalPasswordEntry globalPasswordEntry : passwordEntries) { | ||
passwords.add(globalPasswordEntry.getValue().getPlainText()); | ||
} | ||
} | ||
|
||
} catch (EnvInjectException ee) { | ||
throw new IOException(ee); | ||
} | ||
|
||
return new MaskPasswordsOutputStream(logger, passwords); | ||
} | ||
|
||
@Override | ||
public void makeBuildVariables(AbstractBuild build, Map<String, String> variables) { | ||
|
||
try { | ||
//Put Clear passwords | ||
EnvInjectGlobalPasswordRetriever globalPasswordRetriever = new EnvInjectGlobalPasswordRetriever(); | ||
EnvInjectGlobalPasswordEntry[] passwordEntries = globalPasswordRetriever.getGlobalPasswords(); | ||
if (passwordEntries != null) { | ||
for (EnvInjectGlobalPasswordEntry globalPasswordEntry : passwordEntries) { | ||
variables.put(globalPasswordEntry.getName(), | ||
globalPasswordEntry.getValue().getPlainText()); | ||
} | ||
} | ||
|
||
} catch (EnvInjectException ee) { | ||
LOGGER.log(Level.SEVERE, "Can't inject global password", ee); | ||
} | ||
} | ||
|
||
@Extension | ||
@SuppressWarnings("unused") | ||
public static final class DescriptorImpl extends BuildWrapperDescriptor { | ||
|
||
@Override | ||
public boolean isApplicable(AbstractProject<?, ?> item) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return Messages.envinject_wrapper_globalPasswords_displayName(); | ||
} | ||
|
||
@Override | ||
public String getHelpFile() { | ||
return "/plugin/envinject/help-buildWrapperGlobalPasswords.html"; | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
src/main/java/org/jenkinsci/plugins/envinject/service/EnvInjectGlobalPasswordRetriever.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.jenkinsci.plugins.envinject.service; | ||
|
||
import hudson.XmlFile; | ||
import org.jenkinsci.lib.envinject.EnvInjectException; | ||
import org.jenkinsci.plugins.envinject.EnvInjectGlobalPasswordEntry; | ||
import org.jenkinsci.plugins.envinject.EnvInjectNodeProperty; | ||
|
||
import java.io.IOException; | ||
import java.io.Serializable; | ||
|
||
/** | ||
* @author Gregory Boissinot | ||
*/ | ||
public class EnvInjectGlobalPasswordRetriever implements Serializable { | ||
|
||
public EnvInjectGlobalPasswordEntry[] getGlobalPasswords() throws EnvInjectException { | ||
XmlFile xmlFile = EnvInjectNodeProperty.EnvInjectNodePropertyDescriptor.getConfigFile(); | ||
if (xmlFile.exists()) { | ||
EnvInjectNodeProperty.EnvInjectNodePropertyDescriptor desc; | ||
try { | ||
desc = (EnvInjectNodeProperty.EnvInjectNodePropertyDescriptor) xmlFile.read(); | ||
} catch (IOException ioe) { | ||
throw new EnvInjectException(ioe); | ||
} | ||
return desc.getEnvInjectGlobalPasswordEntries(); | ||
} | ||
|
||
return null; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/resources/org/jenkinsci/plugins/envinject/EnvInjectNodeProperty/global.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" | ||
xmlns:t="/lib/hudson" xmlns:f="/lib/form"> | ||
<f:section title="Global Passwords"> | ||
|
||
<f:entry title="Global Passwords" description="${%Global passwords list}"> | ||
|
||
<f:repeatable var="inst" items="${descriptor.envInjectGlobalPasswordEntries}"> | ||
<table width="100%"> | ||
|
||
<f:entry title="Name" | ||
help="/descriptor/org.jenkinsci.plugins.envinject.EnvInjectNodeProperty/help/name"> | ||
<f:textbox name="envInject.name" value="${inst.name}"/> | ||
</f:entry> | ||
|
||
<f:entry title="Passowrd" | ||
help="/descriptor/org.jenkinsci.plugins.envinject.EnvInjectNodeProperty/help/password"> | ||
<f:password name="envInject.password" value="${inst.value}" /> | ||
</f:entry> | ||
|
||
<f:entry title=""> | ||
<div align="right"> | ||
<f:repeatableDeleteButton/> | ||
</div> | ||
</f:entry> | ||
|
||
</table> | ||
</f:repeatable> | ||
|
||
</f:entry> | ||
|
||
</f:section> | ||
</j:jelly> |
6 changes: 6 additions & 0 deletions
6
src/main/resources/org/jenkinsci/plugins/envinject/EnvInjectNodeProperty/help-name.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<div> | ||
<p> | ||
Give a name to a global password value. <br/> | ||
This name will be accessible by an environment variable. | ||
</p> | ||
</div> |
Oops, something went wrong.