Skip to content

Commit

Permalink
Merge pull request #239 from jenkinsci/SECURITY-3075
Browse files Browse the repository at this point in the history
[SECURITY-3075] Mask passwords even when downstream plugins are unpatched
  • Loading branch information
jglick committed Apr 12, 2023
2 parents 5b6593f + c271a4f commit b64480b
Showing 1 changed file with 35 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,25 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.console.LineTransformationOutputStream;
import java.util.Arrays;
import jenkins.util.JenkinsJVM;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class SecretPatterns {

private static final Logger LOGGER = Logger.getLogger(SecretPatterns.class.getName());

private static final Comparator<String> BY_LENGTH_DESCENDING =
Comparator.comparingInt(String::length).reversed().thenComparing(String::compareTo);

Expand All @@ -51,10 +59,11 @@ public class SecretPatterns {
* absence of quoting, the longer form is masked.
*/
public static @NonNull Pattern getAggregateSecretPattern(@NonNull Collection<String> inputs) {
List<SecretPatternFactory> secretPatternFactories = getSecretPatternFactories();
String pattern = inputs.stream()
.filter(input -> !input.isEmpty())
.flatMap(input ->
SecretPatternFactory.all().stream().flatMap(factory ->
secretPatternFactories.stream().flatMap(factory ->
factory.getEncodedForms(input).stream()))
.sorted(BY_LENGTH_DESCENDING)
.distinct()
Expand All @@ -63,6 +72,31 @@ public class SecretPatterns {
return Pattern.compile(pattern);
}

private static List<SecretPatternFactory> getSecretPatternFactories() {
if (JenkinsJVM.isJenkinsJVM()) {
return SecretPatternFactory.all();
} else {
// TODO Change this to a hard fail in future, e.g. JenkinsJVM.checkJenkinsJVM();
LOGGER.log(
Level.WARNING,
"An agent attempted to look up secret patterns from the controller, which is unsupported. " +
"Falling back to basic implementation that may not mask common transformations of the secret. " +
"This workaround will be removed in a future release. " +
"This is a bug in the plugin calling SecretPatterns#getAggregateSecretPattern(String) " +
"and should be reported to its maintainers. " +
"The plugin can be identified through the stacktrace below.",
new RuntimeException()
);
return Arrays.asList(
new AlmquistShellSecretPatternFactory(),
new BashSecretPatternFactory(),
new BatchSecretPatternFactory(),
new DollarSecretPatternFactory(),
new LiteralSecretPatternFactory()
);
}
}

/**
* Delegating output stream that masks occurrences of a set of secrets.
*/
Expand Down

0 comments on commit b64480b

Please sign in to comment.