Skip to content

Commit 554f037

Browse files
Kevin-CBjenkinsci-cert-ci
authored andcommitted
1 parent de45096 commit 554f037

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

core/src/main/java/hudson/cli/CLICommand.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import edu.umd.cs.findbugs.annotations.CheckForNull;
2828
import edu.umd.cs.findbugs.annotations.NonNull;
29+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2930
import hudson.AbortException;
3031
import hudson.Extension;
3132
import hudson.ExtensionList;
@@ -51,6 +52,7 @@
5152
import java.util.logging.Level;
5253
import java.util.logging.Logger;
5354
import jenkins.model.Jenkins;
55+
import jenkins.util.SystemProperties;
5456
import org.apache.commons.discovery.ResourceClassIterator;
5557
import org.apache.commons.discovery.ResourceNameIterator;
5658
import org.apache.commons.discovery.resource.ClassLoaders;
@@ -62,6 +64,7 @@
6264
import org.kohsuke.accmod.restrictions.NoExternalUse;
6365
import org.kohsuke.args4j.CmdLineException;
6466
import org.kohsuke.args4j.CmdLineParser;
67+
import org.kohsuke.args4j.ParserProperties;
6568
import org.kohsuke.args4j.spi.OptionHandler;
6669
import org.springframework.security.access.AccessDeniedException;
6770
import org.springframework.security.authentication.BadCredentialsException;
@@ -107,6 +110,16 @@
107110
*/
108111
@LegacyInstancesAreScopedToHudson
109112
public abstract class CLICommand implements ExtensionPoint, Cloneable {
113+
114+
/**
115+
* Boolean values to either allow or disallow parsing of @-prefixes.
116+
* If a command line value starts with @, it is interpreted as being a file, loaded,
117+
* and interpreted as if the file content would have been passed to the command line
118+
*/
119+
@SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "Accessible via System Groovy Scripts")
120+
@Restricted(NoExternalUse.class)
121+
public static boolean ALLOW_AT_SYNTAX = SystemProperties.getBoolean(CLICommand.class.getName() + ".allowAtSyntax");
122+
110123
/**
111124
* Connected to stdout and stderr of the CLI agent that initiated the session.
112125
* IOW, if you write to these streams, the person who launched the CLI command
@@ -307,7 +320,8 @@ private void logAndPrintError(Throwable e, String errorMessage, String logMessag
307320
* @since 1.538
308321
*/
309322
protected CmdLineParser getCmdLineParser() {
310-
return new CmdLineParser(this);
323+
ParserProperties properties = ParserProperties.defaults().withAtSyntax(ALLOW_AT_SYNTAX);
324+
return new CmdLineParser(this, properties);
311325
}
312326

313327
/**

core/src/main/java/hudson/cli/declarative/CLIRegisterer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.jvnet.localizer.ResourceBundleHolder;
6060
import org.kohsuke.args4j.CmdLineException;
6161
import org.kohsuke.args4j.CmdLineParser;
62+
import org.kohsuke.args4j.ParserProperties;
6263
import org.springframework.security.access.AccessDeniedException;
6364
import org.springframework.security.authentication.BadCredentialsException;
6465
import org.springframework.security.core.Authentication;
@@ -131,7 +132,8 @@ protected CmdLineParser getCmdLineParser() {
131132
private CmdLineParser bindMethod(List<MethodBinder> binders) {
132133

133134
registerOptionHandlers();
134-
CmdLineParser parser = new CmdLineParser(null);
135+
ParserProperties properties = ParserProperties.defaults().withAtSyntax(ALLOW_AT_SYNTAX);
136+
CmdLineParser parser = new CmdLineParser(null, properties);
135137

136138
// build up the call sequence
137139
Stack<Method> chains = new Stack<>();
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package jenkins.security;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.containsString;
5+
import static org.hamcrest.Matchers.not;
6+
7+
import hudson.cli.CLICommandInvoker;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.util.Arrays;
11+
import java.util.List;
12+
import jenkins.model.Jenkins;
13+
import org.junit.Rule;
14+
import org.junit.Test;
15+
import org.junit.runner.RunWith;
16+
import org.junit.runners.Parameterized;
17+
import org.jvnet.hudson.test.JenkinsRule;
18+
19+
@RunWith(Parameterized.class)
20+
public class Security3314Test {
21+
private String commandName;
22+
23+
@Rule
24+
public final JenkinsRule j = new JenkinsRule();
25+
26+
/**
27+
* connect-node to test the CLICommand behavior
28+
* disable-job to test the CLIRegisterer behavior (@CLIMethod)
29+
*/
30+
@Parameterized.Parameters
31+
public static List<String> commands() {
32+
return Arrays.asList("connect-node", "disable-job");
33+
}
34+
35+
public Security3314Test(String commandName) {
36+
this.commandName = commandName;
37+
}
38+
39+
@Test
40+
public void commandShouldNotParseAt() throws Exception {
41+
CLICommandInvoker command = new CLICommandInvoker(j, commandName);
42+
43+
Path tempPath = Files.createTempFile("tempFile", ".txt");
44+
tempPath.toFile().deleteOnExit();
45+
String content = "AtGotParsed";
46+
Files.write(tempPath, content.getBytes());
47+
48+
final CLICommandInvoker.Result result = command
49+
.authorizedTo(Jenkins.READ)
50+
.invokeWithArgs("@" + tempPath);
51+
52+
assertThat(result.stderr(), containsString("@" + tempPath));
53+
assertThat(result.stderr(), not(containsString("AtGotParsed")));
54+
}
55+
}

0 commit comments

Comments
 (0)