Skip to content

Commit c2a5d85

Browse files
committedMar 13, 2017
Establishing baseline behavior of JENKINS-12543: no workaround when using Remoting transport other than SSH authentication.
(Verifying that this affects only @argument in CLICommand, not @CLIMethod.) With the new HTTP protocol in JENKINS-41745, API tokens may be used to set a transport authentication.
1 parent 4df2bf1 commit c2a5d85

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed
 

‎test/src/test/java/hudson/cli/CLIActionTest.java

+88
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,46 @@
44
import com.gargoylesoftware.htmlunit.Page;
55
import com.gargoylesoftware.htmlunit.WebRequest;
66
import com.gargoylesoftware.htmlunit.WebResponse;
7+
import com.google.common.collect.Lists;
78
import hudson.Functions;
9+
import hudson.Launcher;
10+
import hudson.model.Item;
11+
import hudson.model.User;
812
import hudson.remoting.Channel;
913
import hudson.remoting.ChannelBuilder;
14+
import hudson.util.StreamTaskListener;
15+
import java.io.File;
16+
import java.io.IOException;
1017
import java.net.HttpURLConnection;
1118
import java.net.URL;
1219
import java.util.ArrayList;
20+
import java.util.Arrays;
1321
import java.util.List;
1422
import java.util.UUID;
1523
import java.util.concurrent.ExecutorService;
1624
import java.util.concurrent.Executors;
25+
import jenkins.model.Jenkins;
26+
import jenkins.security.ApiTokenProperty;
27+
import org.apache.commons.io.FileUtils;
1728
import org.codehaus.groovy.runtime.Security218;
1829
import static org.hamcrest.Matchers.containsString;
1930
import static org.junit.Assert.*;
2031
import org.junit.Rule;
2132
import org.junit.Test;
33+
import org.junit.rules.TemporaryFolder;
2234
import org.jvnet.hudson.test.Issue;
2335
import org.jvnet.hudson.test.JenkinsRule;
36+
import org.jvnet.hudson.test.MockAuthorizationStrategy;
2437
import org.jvnet.hudson.test.recipes.PresetData;
2538
import org.jvnet.hudson.test.recipes.PresetData.DataSet;
2639

2740
public class CLIActionTest {
2841
@Rule
2942
public JenkinsRule j = new JenkinsRule();
3043

44+
@Rule
45+
public TemporaryFolder tmp = new TemporaryFolder();
46+
3147
private ExecutorService pool;
3248

3349
/**
@@ -102,4 +118,76 @@ public void serveCliActionToAnonymousUserWithAnonymousUserWithPermissions() thro
102118
wc.goTo("cli");
103119
}
104120

121+
@Issue({"JENKINS-12543", "JENKINS-41745"})
122+
@Test
123+
public void authentication() throws Exception {
124+
File jar = tmp.newFile("jenkins-cli.jar");
125+
FileUtils.copyURLToFile(j.jenkins.getJnlpJars("jenkins-cli.jar").getURL(), jar);
126+
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
127+
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin"));
128+
j.createFreeStyleProject("p");
129+
// CLICommand with @Argument:
130+
assertExitCode(3, false, jar, "-remoting", "get-job", "p"); // IllegalArgumentException from GenericItemOptionHandler
131+
assertExitCode(3, false, jar, "get-job", "p"); // ditto under new protocol
132+
assertExitCode(3, false, jar, "-remoting", "get-job", "--username", "admin", "--password", "admin", "p"); // JENKINS-12543: too late
133+
assertExitCode(3, false, jar, "get-job", "--username", "admin", "--password", "admin", "p"); // same
134+
assertExitCode(0, false, jar, "-remoting", "login", "--username", "admin", "--password", "admin");
135+
try {
136+
assertExitCode(3, false, jar, "-remoting", "get-job", "p"); // ClientAuthenticationCache also used too late
137+
} finally {
138+
assertExitCode(0, false, jar, "-remoting", "logout");
139+
}
140+
assertExitCode(3, true, jar, "-remoting", "get-job", "p"); // does not work with API tokens
141+
assertExitCode(0, true, jar, "get-job", "p"); // but does under new protocol
142+
// @CLIMethod:
143+
assertExitCode(6, false, jar, "-remoting", "disable-job", "p"); // AccessDeniedException from CLIRegisterer?
144+
assertExitCode(6, false, jar, "disable-job", "p");
145+
assertExitCode(0, false, jar, "-remoting", "disable-job", "--username", "admin", "--password", "admin", "p"); // works from CliAuthenticator
146+
assertExitCode(0, false, jar, "disable-job", "--username", "admin", "--password", "admin", "p");
147+
assertExitCode(0, false, jar, "-remoting", "login", "--username", "admin", "--password", "admin");
148+
try {
149+
assertExitCode(0, false, jar, "-remoting", "disable-job", "p"); // or from ClientAuthenticationCache
150+
} finally {
151+
assertExitCode(0, false, jar, "-remoting", "logout");
152+
}
153+
assertExitCode(6, true, jar, "-remoting", "disable-job", "p");
154+
assertExitCode(0, true, jar, "disable-job", "p");
155+
// If we have anonymous read access, then the situation is simpler.
156+
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin").grant(Jenkins.READ, Item.READ).everywhere().toEveryone());
157+
assertExitCode(6, false, jar, "-remoting", "get-job", "p"); // AccessDeniedException from AbstractItem.writeConfigDotXml
158+
assertExitCode(6, false, jar, "get-job", "p");
159+
assertExitCode(0, false, jar, "-remoting", "get-job", "--username", "admin", "--password", "admin", "p");
160+
assertExitCode(0, false, jar, "get-job", "--username", "admin", "--password", "admin", "p");
161+
assertExitCode(0, false, jar, "-remoting", "login", "--username", "admin", "--password", "admin");
162+
try {
163+
assertExitCode(0, false, jar, "-remoting", "get-job", "p");
164+
} finally {
165+
assertExitCode(0, false, jar, "-remoting", "logout");
166+
}
167+
assertExitCode(6, true, jar, "-remoting", "get-job", "p"); // does not work with API tokens
168+
assertExitCode(0, true, jar, "get-job", "p"); // but does under new protocol
169+
assertExitCode(6, false, jar, "-remoting", "disable-job", "p"); // AccessDeniedException from AbstractProject.doDisable
170+
assertExitCode(6, false, jar, "disable-job", "p");
171+
assertExitCode(0, false, jar, "-remoting", "disable-job", "--username", "admin", "--password", "admin", "p");
172+
assertExitCode(0, false, jar, "disable-job", "--username", "admin", "--password", "admin", "p");
173+
assertExitCode(0, false, jar, "-remoting", "login", "--username", "admin", "--password", "admin");
174+
try {
175+
assertExitCode(0, false, jar, "-remoting", "disable-job", "p");
176+
} finally {
177+
assertExitCode(0, false, jar, "-remoting", "logout");
178+
}
179+
assertExitCode(6, true, jar, "-remoting", "disable-job", "p");
180+
assertExitCode(0, true, jar, "disable-job", "p");
181+
}
182+
183+
private void assertExitCode(int code, boolean useApiToken, File jar, String... args) throws IOException, InterruptedException {
184+
String url = j.getURL().toString();
185+
if (useApiToken) {
186+
url = url.replace("://localhost:", "://admin:" + User.get("admin").getProperty(ApiTokenProperty.class).getApiToken() + "@localhost:");
187+
}
188+
List<String> commands = Lists.newArrayList("java", "-jar", jar.getAbsolutePath(), "-s", url, /* not covering SSH keys in this test */ "-noKeyAuth");
189+
commands.addAll(Arrays.asList(args));
190+
assertEquals(code, new Launcher.LocalLauncher(StreamTaskListener.fromStderr()).launch().cmds(commands).stdout(System.out).stderr(System.err).join());
191+
}
192+
105193
}

0 commit comments

Comments
 (0)
Please sign in to comment.