Skip to content

Commit

Permalink
Merge branch 'master' into JENKINS-25735
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-nenashev committed Nov 29, 2016
2 parents 6c1829d + 38bea3a commit c27cd39
Show file tree
Hide file tree
Showing 16 changed files with 725 additions and 42 deletions.
13 changes: 6 additions & 7 deletions README.md
Expand Up @@ -4,19 +4,18 @@ Copyright © 2010-2011, Manufacture Francaise des Pneumatiques Michelin, Rom

About this plugin
-----------------
The Mask Passwords plugin is meant to be used from [Hudson][1] or [Jenkins][2] to mask passwords which may appear from builds' console. Please take a look at [Jenkins' wiki][3] to get detailed information.
The Mask Passwords plugin is meant to be used from [Jenkins][1] to mask passwords or regular expressions which may appear from builds' console. Please take a look at [Jenkins' wiki][2] to get detailed information.

Installation
------------
The Mask Passwords plugin can be installed from any Hudson or Jenkins installation connected to the Internet using the **Plugin Manager** screen.

Source code
-----------
The primary location for the source code of this plugin is on [Jenkins' SVN repository][4]. It is also mirrored on [GitHub][5] for conveniency.
The primary location for the source code of this plugin is on [Jenkins' SVN repository][3]. It is also mirrored on [GitHub][4] for conveniency.

[0]: https://github.com/jenkinsci/mask-passwords-plugin/raw/master/LICENSE.txt
[1]: http://hudson-ci.org/
[2]: http://jenkins-ci.org/
[3]: http://wiki.jenkins-ci.org/display/JENKINS/Mask+Passwords+Plugin
[4]: https://svn.jenkins-ci.org/trunk/hudson/plugins/mask-passwords/
[5]: https://github.com/jenkinsci/mask-passwords-plugin
[1]: https://jenkins.io/
[2]: http://wiki.jenkins-ci.org/display/JENKINS/Mask+Passwords+Plugin
[3]: https://svn.jenkins-ci.org/trunk/hudson/plugins/mask-passwords/
[4]: https://github.com/jenkinsci/mask-passwords-plugin
Expand Up @@ -54,6 +54,7 @@
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import jenkins.tasks.SimpleBuildWrapper;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
Expand All @@ -65,21 +66,29 @@

/**
* Build wrapper that alters the console so that passwords don't get displayed.
*
*
* @author Romain Seguy (http://openromain.blogspot.com)
*/
public final class MaskPasswordsBuildWrapper extends SimpleBuildWrapper {

private final List<VarPasswordPair> varPasswordPairs;
private final List<VarMaskRegex> varMaskRegexes;

@DataBoundConstructor
public MaskPasswordsBuildWrapper(List<VarPasswordPair> varPasswordPairs, List<VarMaskRegex> varMaskRegexes) {
this.varPasswordPairs = varPasswordPairs;
this.varMaskRegexes = varMaskRegexes;
}

public MaskPasswordsBuildWrapper(List<VarPasswordPair> varPasswordPairs) {
this.varPasswordPairs = varPasswordPairs;
this.varMaskRegexes = new ArrayList<VarMaskRegex>();
}

@Override
public ConsoleLogFilter createLoggerDecorator(Run<?, ?> build) {
List<String> allPasswords = new ArrayList<String>(); // all passwords to be masked
List<String> allRegexes = new ArrayList<String>(); // all regexes to be masked
MaskPasswordsConfig config = MaskPasswordsConfig.getInstance();

// global passwords
Expand All @@ -88,6 +97,12 @@ public ConsoleLogFilter createLoggerDecorator(Run<?, ?> build) {
allPasswords.add(globalVarPasswordPair.getPassword());
}

// global regexes
List<VarMaskRegex> globalVarMaskRegexes = config.getGlobalVarMaskRegexes();
for(VarMaskRegex globalVarMaskRegex: globalVarMaskRegexes) {
allRegexes.add(globalVarMaskRegex.getRegex());
}

// job's passwords
if(varPasswordPairs != null) {
for(VarPasswordPair varPasswordPair: varPasswordPairs) {
Expand All @@ -98,6 +113,16 @@ public ConsoleLogFilter createLoggerDecorator(Run<?, ?> build) {
}
}

// job's regexes
if(varMaskRegexes != null) {
for(VarMaskRegex varMaskRegex: varMaskRegexes) {
String regex = varMaskRegex.getRegex();
if(StringUtils.isNotBlank(regex)) {
allRegexes.add(regex);
}
}
}

// find build parameters which are passwords (PasswordParameterValue)
ParametersAction params = build.getAction(ParametersAction.class);
if(params != null) {
Expand All @@ -113,30 +138,39 @@ public ConsoleLogFilter createLoggerDecorator(Run<?, ?> build) {
}
}

return new FilterImpl(allPasswords);
return new FilterImpl(allPasswords, allRegexes);
}

private static final class FilterImpl extends ConsoleLogFilter implements Serializable {

private static final long serialVersionUID = 1L;

private final List<Secret> allPasswords;
private final List<String> allRegexes;

FilterImpl(List<String> allPasswords) {
FilterImpl(List<String> allPasswords, List<String> allRegexes) {
this.allPasswords = new ArrayList<Secret>();
this.allRegexes = new ArrayList<String>();
for (String password : allPasswords) {
this.allPasswords.add(Secret.fromString(password));
}
for (String regex : allRegexes) {
this.allRegexes.add(regex);
}
}

@SuppressWarnings("rawtypes")
@Override
public OutputStream decorateLogger(AbstractBuild _ignore, OutputStream logger) throws IOException, InterruptedException {
List<String> passwords = new ArrayList<String>();
List<String> regexes = new ArrayList<String>();
for (Secret password : allPasswords) {
passwords.add(password.getPlainText());
}
return new MaskPasswordsOutputStream(logger, passwords);
for (String regex : allRegexes) {
regexes.add(regex);
}
return new MaskPasswordsOutputStream(logger, passwords, regexes);
}

}
Expand Down Expand Up @@ -169,10 +203,10 @@ public void makeBuildVariables(AbstractBuild build, Map<String, String> variable
@Override
public void makeSensitiveBuildVariables(AbstractBuild build, Set<String> sensitiveVariables) {
final Map<String, String> variables = new TreeMap<String, String>();
makeBuildVariables(build, variables);
makeBuildVariables(build, variables);
sensitiveVariables.addAll(variables.keySet());
}

@Override
public void setUp(Context context, Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException {
// nothing to do here
Expand All @@ -182,6 +216,10 @@ public List<VarPasswordPair> getVarPasswordPairs() {
return varPasswordPairs;
}

public List<VarMaskRegex> getVarMaskRegexes() {
return varMaskRegexes;
}

/**
* Represents name/password entries defined by users in their jobs.
* <p>Equality and hashcode are based on {@code var} only, not
Expand Down Expand Up @@ -239,9 +277,55 @@ public int hashCode() {

}

/**
* Represents regexes defined by users in their jobs.
*/
public static class VarMaskRegex implements Cloneable {

private final String regex;

@DataBoundConstructor
public VarMaskRegex(String regex) {
this.regex = regex;
}

@Override
public Object clone() {
return new VarMaskRegex(getRegex());
}

@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(getClass() != obj.getClass()) {
return false;
}
final VarMaskRegex other = (VarMaskRegex) obj;
if((this.regex == null) ? (other.regex != null) : !this.regex.equals(other.regex)) {
return false;
}
return true;
}

@CheckForNull
public String getRegex() {
return regex;
}

@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + (this.regex != null ? this.regex.hashCode() : 0);
return hash;
}

}

@Extension(ordinal = 1000) // JENKINS-12161
public static final class DescriptorImpl extends BuildWrapperDescriptor {

public DescriptorImpl() {
super(MaskPasswordsBuildWrapper.class);
}
Expand Down Expand Up @@ -286,6 +370,32 @@ else if(o instanceof JSONObject) {
}
}

// global regexes
if(submittedForm.has("globalVarMaskRegexes")) {
Object o = submittedForm.get("globalVarMaskRegexes");

if(o instanceof JSONArray) {
JSONArray jsonArray = submittedForm.getJSONArray("globalVarMaskRegexes");
for(int i = 0; i < jsonArray.size(); i++) {
getConfig().addGlobalVarMaskRegex(new VarMaskRegex(
jsonArray.getJSONObject(i).getString("regex")));
}
}
else if(o instanceof JSONObject) {
JSONObject jsonObject = submittedForm.getJSONObject("globalVarMaskRegexes");
getConfig().addGlobalVarMaskRegex(new VarMaskRegex(
jsonObject.getString("regex")));
}
}

// global enable
if(submittedForm.has("globalVarMaskEnabledGlobally")) {
boolean b = submittedForm.getBoolean("globalVarMaskEnabledGlobally");
if(b) {
getConfig().setGlobalVarEnabledGlobally(true);
}
}

MaskPasswordsConfig.save(getConfig());

return true;
Expand Down Expand Up @@ -324,8 +434,11 @@ public static final class ConverterImpl implements Converter {

private final static String VAR_PASSWORD_PAIRS_NODE = "varPasswordPairs";
private final static String VAR_PASSWORD_PAIR_NODE = "varPasswordPair";
private final static String VAR_MASK_REGEXES_NODE = "varMaskRegexes";
private final static String VAR_MASK_REGEX_NODE = "varMaskRegex";
private final static String VAR_ATT = "var";
private final static String PASSWORD_ATT = "password";
private final static String REGEX_ATT = "regex";

public boolean canConvert(Class clazz) {
return clazz.equals(MaskPasswordsBuildWrapper.class);
Expand All @@ -349,10 +462,25 @@ public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContex
}
writer.endNode();
}
// varMaskRegexes
if(maskPasswordsBuildWrapper.getVarMaskRegexes() != null) {
writer.startNode(VAR_MASK_REGEXES_NODE);
for(VarMaskRegex varMaskRegex: maskPasswordsBuildWrapper.getVarMaskRegexes()) {
// blank passwords are skipped
if(StringUtils.isBlank(varMaskRegex.getRegex())) {
continue;
}
writer.startNode(VAR_MASK_REGEX_NODE);
writer.addAttribute(REGEX_ATT, varMaskRegex.getRegex());
writer.endNode();
}
writer.endNode();
}
}

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext uc) {
List<VarPasswordPair> varPasswordPairs = new ArrayList<VarPasswordPair>();
List<VarMaskRegex> varMaskRegexes = new ArrayList<VarMaskRegex>();

while(reader.hasMoreChildren()) {
reader.moveDown();
Expand All @@ -373,13 +501,29 @@ public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext uc
}
reader.moveUp();
}
else if(reader.getNodeName().equals(VAR_MASK_REGEXES_NODE)) {
while(reader.hasMoreChildren()) {
reader.moveDown();
if(reader.getNodeName().equals(VAR_MASK_REGEX_NODE)) {
varMaskRegexes.add(new VarMaskRegex(
reader.getAttribute(REGEX_ATT)));
}
else {
LOGGER.log(Level.WARNING,
"Encountered incorrect node name: Expected \"" + VAR_MASK_REGEX_NODE + "\", got \"{0}\"",
reader.getNodeName());
}
reader.moveUp();
}
reader.moveUp();
}
else {
LOGGER.log(Level.WARNING,
"Encountered incorrect node name: \"{0}\"", reader.getNodeName());
}
}

return new MaskPasswordsBuildWrapper(varPasswordPairs);
return new MaskPasswordsBuildWrapper(varPasswordPairs, varMaskRegexes);
}

}
Expand Down

0 comments on commit c27cd39

Please sign in to comment.