Skip to content

Commit 3059161

Browse files
authored
Add test for SECURITY-3135 (#8427)
* Add test for SECURITY-3135 * Address review feedback
1 parent 30540d7 commit 3059161

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package jenkins.security;
2+
3+
import static org.junit.Assert.assertNull;
4+
import static org.junit.Assert.assertTrue;
5+
6+
import hudson.model.FreeStyleProject;
7+
import hudson.model.InvisibleAction;
8+
import hudson.model.UnprotectedRootAction;
9+
import org.htmlunit.FailingHttpStatusCodeException;
10+
import org.htmlunit.html.DomElement;
11+
import org.htmlunit.html.HtmlPage;
12+
import org.junit.Rule;
13+
import org.junit.Test;
14+
import org.jvnet.hudson.test.Issue;
15+
import org.jvnet.hudson.test.JenkinsRule;
16+
import org.jvnet.hudson.test.TestExtension;
17+
import org.kohsuke.stapler.StaplerRequest;
18+
import org.kohsuke.stapler.StaplerResponse;
19+
20+
public class Security3135Test {
21+
public static final String ACTION_URL = "security3135";
22+
@Rule
23+
public JenkinsRule j = new JenkinsRule();
24+
25+
@Test
26+
@Issue("SECURITY-3135")
27+
public void contextMenuShouldNotBypassCSRFProtection() throws Exception {
28+
JenkinsRule.WebClient wc = j.createWebClient();
29+
FreeStyleProject project = j.createFreeStyleProject("FreestyleProject");
30+
ViewHolder viewHolder = j.jenkins.getExtensionList(ViewHolder.class).get(ViewHolder.class);
31+
boolean exceptionThrown = false;
32+
33+
HtmlPage page = wc.goTo(ACTION_URL);
34+
DomElement standardMenu = page.getElementById("standard-menu");
35+
standardMenu.click();
36+
DomElement contextMenu = page.getElementById("context-menu");
37+
try {
38+
contextMenu.click();
39+
} catch (FailingHttpStatusCodeException e) {
40+
if (e.getStatusCode() == 405) {
41+
exceptionThrown = true;
42+
}
43+
}
44+
45+
j.waitUntilNoActivityUpTo(2000); // Give the job 2 seconds to be submitted
46+
47+
assertTrue("Request was not made", viewHolder.isRequestMade());
48+
assertTrue("Expected 405 Method Not Allowed", exceptionThrown);
49+
assertNull("Build should not be scheduled", j.jenkins.getQueue().getItem(project));
50+
assertNull("Build should not be scheduled", project.getBuildByNumber(1));
51+
}
52+
53+
@TestExtension
54+
public static class ViewHolder extends InvisibleAction implements UnprotectedRootAction {
55+
56+
public boolean requestMade = false;
57+
58+
@Override
59+
public String getUrlName() {
60+
return ACTION_URL;
61+
}
62+
63+
public String getPayload() {
64+
return "../job/FreestyleProject/build?delay=0sec&";
65+
}
66+
67+
public String getStandardPayload() {
68+
return "../security3135/validate?";
69+
}
70+
71+
public boolean isRequestMade() {
72+
return requestMade;
73+
}
74+
75+
public void doValidate(StaplerRequest request, StaplerResponse response) {
76+
requestMade = true;
77+
}
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:f="/lib/form">
3+
<l:layout title="Security-3135">
4+
<l:main-panel>
5+
<a href="${rootUrl}${it.payload}" class="model-link" id="context-menu">Context Menu</a>
6+
<a href="${rootUrl}${it.standardPayload}" class="model-link" id="standard-menu">Standard Menu</a>
7+
</l:main-panel>
8+
</l:layout>
9+
</j:jelly>

0 commit comments

Comments
 (0)