-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into SECURITY-367_UNRESTRICTED_GROOVY_SCRIPTING…
…_VULN
- Loading branch information
Showing
8 changed files
with
1,238 additions
and
53 deletions.
There are no files selected for viewing
316 changes: 267 additions & 49 deletions
316
src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
671 changes: 671 additions & 0 deletions
671
src/test/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilderTest.java
Large diffs are not rendered by default.
Oops, something went wrong.
235 changes: 235 additions & 0 deletions
235
src/test/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilderWithRestartTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright (c) 2018, CloudBees, Inc. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
package org.jenkinsci.plugins.scriptler.builder; | ||
|
||
import com.gargoylesoftware.htmlunit.HttpMethod; | ||
import com.gargoylesoftware.htmlunit.WebRequest; | ||
import com.gargoylesoftware.htmlunit.html.HtmlPage; | ||
import com.gargoylesoftware.htmlunit.util.NameValuePair; | ||
import com.gargoylesoftware.htmlunit.xml.XmlPage; | ||
import hudson.model.FileParameterValue; | ||
import hudson.model.FreeStyleProject; | ||
import net.sf.json.JSONObject; | ||
import org.apache.commons.fileupload.FileItem; | ||
import org.apache.commons.io.FileUtils; | ||
import org.jenkinsci.plugins.scriptler.ScriptlerManagement; | ||
import org.jenkinsci.plugins.scriptler.ScriptlerManagementHelper; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.runners.model.Statement; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.jvnet.hudson.test.RestartableJenkinsRule; | ||
|
||
import java.io.File; | ||
import java.net.URL; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotNull; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
/** | ||
* Warning: a user without RUN_SCRIPT can currently only clone an existing builder INSIDE a project. | ||
* You can search CLONE_NOTE inside this test to see the cases | ||
*/ | ||
public class ScriptlerBuilderWithRestartTest { | ||
@Rule | ||
public RestartableJenkinsRule r = new RestartableJenkinsRule(); | ||
|
||
private static final String SCRIPT_USABLE_1 = "script_usable_1.groovy"; | ||
private static final String SCRIPT_USABLE_2 = "script_usable_2.groovy"; | ||
private static final String SCRIPT_USABLE_3 = "script_usable_3.groovy"; | ||
private static final String SCRIPT_USABLE_4 = "script_usable_4.groovy"; | ||
|
||
private static final String SCRIPT_NOT_USABLE = "not_usable.groovy"; | ||
|
||
@Test | ||
public void configRoundtrip() throws Exception { | ||
r.addStep(new Statement() { | ||
@Override public void evaluate() throws Throwable { | ||
r.j.jenkins.setCrumbIssuer(null); | ||
|
||
ScriptlerManagement scriptler = r.j.jenkins.getExtensionList(ScriptlerManagement.class).get(0); | ||
ScriptlerManagementHelper helper = new ScriptlerManagementHelper(scriptler); | ||
|
||
setupScript(helper, SCRIPT_USABLE_1, true); | ||
setupScript(helper, SCRIPT_USABLE_2, true); | ||
setupScript(helper, SCRIPT_USABLE_3, true); | ||
setupScript(helper, SCRIPT_USABLE_4, true); | ||
setupScript(helper, SCRIPT_NOT_USABLE, false); | ||
|
||
FreeStyleProject project = r.j.createFreeStyleProject("test"); | ||
|
||
JenkinsRule.WebClient wc = r.j.createWebClient(); | ||
|
||
WebRequest request = new WebRequest(new URL(r.j.getURL() + project.getShortUrl() + "configSubmit"), HttpMethod.POST); | ||
|
||
final String projectName = project.getName(); | ||
request.setRequestParameters(Arrays.asList(new NameValuePair("json", JSONObject.fromObject( | ||
new HashMap() {{ | ||
put("name", projectName); | ||
put("builder", new HashMap() {{ | ||
put("kind", ScriptlerBuilder.class.getName()); | ||
put("builderId", ""); | ||
put("scriptlerScriptId", SCRIPT_USABLE_1); | ||
put("propagateParams", true); | ||
put("defineParams", new HashMap() {{ | ||
put("parameters", Arrays.asList( | ||
new HashMap() {{ | ||
put("name", "param1"); | ||
put("value", "value1"); | ||
}}, | ||
new HashMap() {{ | ||
put("name", "param2"); | ||
put("value", "value2"); | ||
}} | ||
)); | ||
}}); | ||
}}); | ||
}} | ||
).toString()))); | ||
HtmlPage page = wc.getPage(request); | ||
r.j.assertGoodStatus(page); | ||
|
||
ScriptlerBuilder scriptlerBuilder = project.getBuildersList().get(ScriptlerBuilder.class); | ||
assertNotNull(scriptlerBuilder); | ||
assertNotNull(scriptlerBuilder.getBuilderId()); | ||
assertEquals(SCRIPT_USABLE_1, scriptlerBuilder.getScriptId()); | ||
assertEquals(true, scriptlerBuilder.isPropagateParams()); | ||
assertEquals(2, scriptlerBuilder.getParameters().length); | ||
assertEquals("param1", scriptlerBuilder.getParameters()[0].getName()); | ||
assertEquals("value1", scriptlerBuilder.getParameters()[0].getValue()); | ||
assertEquals("param2", scriptlerBuilder.getParameters()[1].getName()); | ||
assertEquals("value2", scriptlerBuilder.getParameters()[1].getValue()); | ||
} | ||
}); | ||
|
||
r.addStep(new Statement() { | ||
@Override public void evaluate() throws Throwable { | ||
FreeStyleProject p = r.j.jenkins.getItemByFullName("test", FreeStyleProject.class); | ||
|
||
ScriptlerBuilder scriptlerBuilder = p.getBuildersList().get(ScriptlerBuilder.class); | ||
assertNotNull(scriptlerBuilder); | ||
assertNotNull(scriptlerBuilder.getBuilderId()); | ||
assertEquals(SCRIPT_USABLE_1, scriptlerBuilder.getScriptId()); | ||
assertEquals(true, scriptlerBuilder.isPropagateParams()); | ||
assertEquals(2, scriptlerBuilder.getParameters().length); | ||
assertEquals("param1", scriptlerBuilder.getParameters()[0].getName()); | ||
assertEquals("value1", scriptlerBuilder.getParameters()[0].getValue()); | ||
assertEquals("param2", scriptlerBuilder.getParameters()[1].getName()); | ||
assertEquals("value2", scriptlerBuilder.getParameters()[1].getValue()); | ||
} | ||
}); | ||
} | ||
|
||
private void setupScript(ScriptlerManagementHelper helper, String scriptId, boolean nonAdministerUsing) throws Exception { | ||
File f = new File(scriptId); | ||
FileUtils.writeStringToFile(f, "print 'Hello World!'"); | ||
FileItem fi = new FileParameterValue.FileItemImpl(f); | ||
helper.saveScript(fi, nonAdministerUsing, scriptId); | ||
f.delete(); | ||
} | ||
|
||
@Test | ||
public void configRoundtripConfigXml() throws Exception { | ||
r.addStep(new Statement() { | ||
@Override public void evaluate() throws Throwable { | ||
r.j.jenkins.setCrumbIssuer(null); | ||
|
||
ScriptlerManagement scriptler = r.j.jenkins.getExtensionList(ScriptlerManagement.class).get(0); | ||
ScriptlerManagementHelper helper = new ScriptlerManagementHelper(scriptler); | ||
|
||
setupScript(helper, SCRIPT_USABLE_1, true); | ||
setupScript(helper, SCRIPT_USABLE_2, true); | ||
setupScript(helper, SCRIPT_USABLE_3, true); | ||
setupScript(helper, SCRIPT_USABLE_4, true); | ||
setupScript(helper, SCRIPT_NOT_USABLE, false); | ||
|
||
FreeStyleProject project = r.j.createFreeStyleProject("test"); | ||
|
||
JenkinsRule.WebClient wc = r.j.createWebClient(); | ||
|
||
XmlPage xmlPage = wc.goToXml(project.getShortUrl() + "config.xml"); | ||
r.j.assertGoodStatus(xmlPage); | ||
String xml = xmlPage.getWebResponse().getContentAsString(); | ||
|
||
String modifiedXml = xml.replace("<builders/>", "" + | ||
"<builders>\n" + | ||
" <org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder>\n" + | ||
" <builderId></builderId>\n" + | ||
" <scriptId>" + SCRIPT_USABLE_1 + "</scriptId>\n" + | ||
" <propagateParams>true</propagateParams>\n" + | ||
" <parameters>\n" + | ||
" <org.jenkinsci.plugins.scriptler.config.Parameter>\n" + | ||
" <name>param1</name>\n" + | ||
" <value>value1</value>\n" + | ||
" </org.jenkinsci.plugins.scriptler.config.Parameter>\n" + | ||
" <org.jenkinsci.plugins.scriptler.config.Parameter>\n" + | ||
" <name>param2</name>\n" + | ||
" <value>value2</value>\n" + | ||
" </org.jenkinsci.plugins.scriptler.config.Parameter>\n" + | ||
" </parameters>\n" + | ||
" </org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder>\n" + | ||
"</builders>" | ||
); | ||
|
||
WebRequest request = new WebRequest(new URL(project.getAbsoluteUrl() + "config.xml"), HttpMethod.POST); | ||
request.setRequestBody(modifiedXml); | ||
request.setEncodingType(null); | ||
HtmlPage page = wc.getPage(request); | ||
r.j.assertGoodStatus(page); | ||
|
||
project = r.j.jenkins.getItemByFullName(project.getFullName(), FreeStyleProject.class); | ||
ScriptlerBuilder scriptlerBuilder = project.getBuildersList().get(ScriptlerBuilder.class); | ||
assertNotNull(scriptlerBuilder); | ||
assertTrue(scriptlerBuilder.getBuilderId().equals("")); | ||
assertEquals(SCRIPT_USABLE_1, scriptlerBuilder.getScriptId()); | ||
assertEquals(true, scriptlerBuilder.isPropagateParams()); | ||
assertEquals(2, scriptlerBuilder.getParameters().length); | ||
assertEquals("param1", scriptlerBuilder.getParameters()[0].getName()); | ||
assertEquals("value1", scriptlerBuilder.getParameters()[0].getValue()); | ||
assertEquals("param2", scriptlerBuilder.getParameters()[1].getName()); | ||
assertEquals("value2", scriptlerBuilder.getParameters()[1].getValue()); | ||
} | ||
}); | ||
|
||
r.addStep(new Statement() { | ||
@Override public void evaluate() throws Throwable { | ||
FreeStyleProject p = r.j.jenkins.getItemByFullName("test", FreeStyleProject.class); | ||
|
||
ScriptlerBuilder scriptlerBuilder = p.getBuildersList().get(ScriptlerBuilder.class); | ||
assertNotNull(scriptlerBuilder); | ||
assertNotNull(scriptlerBuilder.getBuilderId()); | ||
assertEquals(SCRIPT_USABLE_1, scriptlerBuilder.getScriptId()); | ||
assertEquals(true, scriptlerBuilder.isPropagateParams()); | ||
assertEquals(2, scriptlerBuilder.getParameters().length); | ||
assertEquals("param1", scriptlerBuilder.getParameters()[0].getName()); | ||
assertEquals("value1", scriptlerBuilder.getParameters()[0].getValue()); | ||
assertEquals("param2", scriptlerBuilder.getParameters()[1].getName()); | ||
assertEquals("value2", scriptlerBuilder.getParameters()[1].getValue()); | ||
} | ||
}); | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/test/java/org/jenkinsci/plugins/scriptler/util/UIHelperTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.jenkinsci.plugins.scriptler.util; | ||
|
||
import junit.framework.TestCase; | ||
import net.sf.json.JSONObject; | ||
import net.sf.json.JSONSerializer; | ||
import org.apache.commons.io.IOUtils; | ||
import org.jenkinsci.plugins.scriptler.config.Parameter; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
public class UIHelperTest extends TestCase { | ||
public void testExtractParameters1() throws Exception { | ||
JSONObject json = getJsonFromFile("/simple1.json"); | ||
final Parameter[] extractParameters = UIHelper.extractParameters(json); | ||
assertNotNull("no parameters extracted", extractParameters); | ||
assertEquals("not all params extracted", 2, extractParameters.length); | ||
} | ||
|
||
public void testExtractParameters2() throws Exception { | ||
JSONObject json = getJsonFromFile("/simple2.json"); | ||
final Parameter[] extractParameters = UIHelper.extractParameters(json); | ||
assertNotNull("no parameters extracted", extractParameters); | ||
assertEquals("not all params extracted", 2, extractParameters.length); | ||
} | ||
|
||
public void testExtractParameters_JENKINS_13518() throws Exception { | ||
JSONObject json = getJsonFromFile("/JENKINS-13518.json"); | ||
final Parameter[] extractParameters = UIHelper.extractParameters(json); | ||
assertNotNull("no parameters extracted", extractParameters); | ||
assertEquals("not all params extracted", 0, extractParameters.length); | ||
} | ||
|
||
private JSONObject getJsonFromFile(String resource) throws IOException { | ||
InputStream is = UIHelperTest.class.getResourceAsStream(resource); | ||
String jsonTxt = IOUtils.toString(is); | ||
JSONObject json = (JSONObject) JSONSerializer.toJSON(jsonTxt); | ||
return json; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"":"","builder":{"backupJobName":"","builderId":"","defineParams":false,"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder","parameters":[{"name":"","value":""},{"name":"","value":""}],"scriptlerScriptId":"testOutput.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"},"core:apply":"","description":"","displayNameOrNull":"","name":"test","properties":{"hudson-model-ParametersDefinitionProperty":{},"org-jenkinsci-plugins-envinject-EnvInjectJobProperty":{},"stapler-class-bag":"true"},"scm":{"value":"0"}} | ||
{"":"","builder":{"builderId":"","defineParams":false,"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder","parameters":[{"name":"","value":""},{"name":"","value":""}],"scriptlerScriptId":"testOutput.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"},"core:apply":"","description":"","displayNameOrNull":"","name":"test","properties":{"hudson-model-ParametersDefinitionProperty":{},"org-jenkinsci-plugins-envinject-EnvInjectJobProperty":{},"stapler-class-bag":"true"},"scm":{"value":"0"}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"backupJobName":"new","builderId":"1331321162149_1","defineParams":{"parameters":[{"name":"jobName","value":"${JOB}"},{"name":"buildRange","value":"1-10"}]},"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder$DescriptorImpl","scriptlerScriptId":"bulkDeleteBuilds.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"} | ||
{"builderId":"1331321162149_1","defineParams":{"parameters":[{"name":"jobName","value":"${JOB}"},{"name":"buildRange","value":"1-10"}]},"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder$DescriptorImpl","scriptlerScriptId":"bulkDeleteBuilds.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"backupJobName":"","builderId":"","defineParams":{"parameters":[{"name":"param1","value":"value1"},{"name":"param2","value":"value2"}]},"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder$DescriptorImpl","scriptlerScriptId":"bulkDeleteBuilds.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"} | ||
{"builderId":"","defineParams":{"parameters":[{"name":"param1","value":"value1"},{"name":"param2","value":"value2"}]},"kind":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder$DescriptorImpl","scriptlerScriptId":"bulkDeleteBuilds.groovy","stapler-class":"org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder"} |