diff --git a/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java b/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java index a037d8d44..5b3116497 100644 --- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java +++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java @@ -498,6 +498,7 @@ public synchronized void configureingClasspath(@Nonnull String path, @Nonnull Ap boolean shouldSave = false; if (!Jenkins.getInstance().isUseSecurity() || (Jenkins.getAuthentication() != ACL.SYSTEM && Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS))) { LOG.info(String.format("Classpath %s (%s) is approved as configured with RUN_SCRIPTS permission.", path, hash)); + removePendingClasspath(hash); addApprovedClasspath(new ApprovedClasspath(hash, path)); shouldSave = true; } else { diff --git a/src/test/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SecureGroovyScriptTest.java b/src/test/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SecureGroovyScriptTest.java index 16481564d..5c65600d0 100644 --- a/src/test/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SecureGroovyScriptTest.java +++ b/src/test/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SecureGroovyScriptTest.java @@ -27,7 +27,6 @@ import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlTextArea; -import com.gargoylesoftware.htmlunit.html.Util; import hudson.model.FreeStyleProject; import hudson.model.FreeStyleBuild; @@ -605,4 +604,121 @@ private List getAllUpdatedJarFiles() throws URISyntaxException { assertEquals(testingDisplayName, b.getDisplayName()); } } + + @Test public void testClasspathAutomaticApprove() throws Exception { + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy(); + gmas.add(Jenkins.READ, "devel"); + gmas.add(Jenkins.READ, "approver"); + gmas.add(Jenkins.RUN_SCRIPTS, "approver"); + for (Permission p : Item.PERMISSIONS.getPermissions()) { + gmas.add(p, "devel"); + gmas.add(p, "approver"); + } + r.jenkins.setAuthorizationStrategy(gmas); + + JenkinsRule.WebClient wcDevel = r.createWebClient(); + wcDevel.login("devel"); + + JenkinsRule.WebClient wcApprover = r.createWebClient(); + wcApprover.login("approver"); + + + List classpathList = new ArrayList(); + + for (File jarfile: getAllJarFiles()) { + classpathList.add(new AdditionalClasspath(jarfile.getAbsolutePath())); + System.out.println(jarfile); + } + + final String testingDisplayName = "TESTDISPLAYNAME"; + + FreeStyleProject p = r.createFreeStyleProject(); + p.getPublishersList().add(new TestGroovyRecorder(new SecureGroovyScript( + String.format( + "import org.jenkinsci.plugins.scriptsecurity.testjar.BuildUtil;" + + "BuildUtil.setDisplayNameWhitelisted(build, \"%s\");" + + "\"\"", testingDisplayName), + true, + classpathList + ))); + + // Deny classpath. + { + List pcps = ScriptApproval.get().getPendingClasspaths(); + assertNotEquals(0, pcps.size()); + for(ScriptApproval.PendingClasspath pcp: pcps) { + ScriptApproval.get().denyClasspath(pcp.getHash(), pcp.getPath()); + } + + assertEquals(0, ScriptApproval.get().getPendingClasspaths().size()); + assertEquals(0, ScriptApproval.get().getApprovedClasspaths().size()); + } + + // If configured by a user with RUN_SCRIPTS, the classpath is automatically approved + { + r.submit(wcApprover.getPage(p, "configure").getFormByName("config")); + + List pcps = ScriptApproval.get().getPendingClasspaths(); + assertEquals(0, pcps.size()); + List acps = ScriptApproval.get().getApprovedClasspaths(); + assertNotEquals(0, acps.size()); + + for(ScriptApproval.ApprovedClasspath acp: acps) { + ScriptApproval.get().denyApprovedClasspath(acp.getHash()); + } + + assertEquals(0, ScriptApproval.get().getPendingClasspaths().size()); + assertEquals(0, ScriptApproval.get().getApprovedClasspaths().size()); + } + + // If configured by a user without RUN_SCRIPTS, approval is requested + { + r.submit(wcDevel.getPage(p, "configure").getFormByName("config")); + + List pcps = ScriptApproval.get().getPendingClasspaths(); + assertNotEquals(0, pcps.size()); + List acps = ScriptApproval.get().getApprovedClasspaths(); + assertEquals(0, acps.size()); + + // don't remove pending classpaths. + } + + // If configured by a user with RUN_SCRIPTS, the classpath is automatically approved, and removed from approval request. + { + assertNotEquals(0, ScriptApproval.get().getPendingClasspaths().size()); + assertEquals(0, ScriptApproval.get().getApprovedClasspaths().size()); + + r.submit(wcApprover.getPage(p, "configure").getFormByName("config")); + + List pcps = ScriptApproval.get().getPendingClasspaths(); + assertEquals(0, pcps.size()); + List acps = ScriptApproval.get().getApprovedClasspaths(); + assertNotEquals(0, acps.size()); + + for(ScriptApproval.ApprovedClasspath acp: acps) { + ScriptApproval.get().denyApprovedClasspath(acp.getHash()); + } + + assertEquals(0, ScriptApproval.get().getPendingClasspaths().size()); + assertEquals(0, ScriptApproval.get().getApprovedClasspaths().size()); + } + + // If run with SYSTEM user, an approval is requested. + { + r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0).get()); + + List pcps = ScriptApproval.get().getPendingClasspaths(); + assertNotEquals(0, pcps.size()); + List acps = ScriptApproval.get().getApprovedClasspaths(); + assertEquals(0, acps.size()); + + for(ScriptApproval.PendingClasspath pcp: pcps) { + ScriptApproval.get().denyClasspath(pcp.getHash(), pcp.getPath()); + } + + assertEquals(0, ScriptApproval.get().getPendingClasspaths().size()); + assertEquals(0, ScriptApproval.get().getApprovedClasspaths().size()); + } + } }