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 5bce32055..031ed061e 100644 --- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java +++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval.java @@ -66,6 +66,7 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Pattern; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import jenkins.model.Jenkins; @@ -701,6 +702,29 @@ public synchronized String[] getAclApprovedSignatures() { return aclApprovedSignatures.toArray(new String[aclApprovedSignatures.size()]); } + @DataBoundSetter + public synchronized void setApprovedScriptHashes(String[] scriptHashes) throws IOException { + Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS); + approvedScriptHashes.clear(); + List goodScriptHashes = new ArrayList<>(scriptHashes.length); + Pattern sha1Pattern = Pattern.compile("^[a-fA-F0-9]{40}$"); + for (String scriptHash : scriptHashes) { + if (scriptHash != null && sha1Pattern.matcher(scriptHash).matches()) { + goodScriptHashes.add(scriptHash); + } else { + LOG.warning("Ignoring malformed script hash: " + scriptHash); + } + } + approvedScriptHashes.addAll(goodScriptHashes); + save(); + reconfigure(); + } + + @Restricted(NoExternalUse.class) // Jelly, implementation + public synchronized String[] getApprovedScriptHashes() { + return approvedScriptHashes.toArray(new String[approvedScriptHashes.size()]); + } + @Restricted(NoExternalUse.class) // implementation @Extension public static final class ApprovedWhitelist extends ProxyWhitelist { public ApprovedWhitelist() { diff --git a/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/JcascTest.java b/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/JcascTest.java index 8a825b274..b562f911f 100644 --- a/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/JcascTest.java +++ b/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/JcascTest.java @@ -26,6 +26,9 @@ public void smokeTestEntry() throws Exception { String[] approved = ScriptApproval.get().getApprovedSignatures(); assertTrue(approved.length == 1); assertEquals(approved[0], "method java.net.URI getHost"); + String[] approvedScriptHashes = ScriptApproval.get().getApprovedScriptHashes(); + assertTrue(approvedScriptHashes.length == 1); + assertEquals(approvedScriptHashes[0], "fccae58c5762bdd15daca97318e9d74333203106"); } @Test diff --git a/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest.java b/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest.java index e92afda99..a5779714e 100644 --- a/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest.java +++ b/src/test/java/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest.java @@ -162,15 +162,17 @@ public void malformedScriptApproval() throws Exception { assertEquals(0, sa.getDangerousApprovedSignatures().length); } - @Issue("JENKINS-57563") - @LocalData // Just a scriptApproval.xml that whitelists 'staticMethod jenkins.model.Jenkins getInstance' + @Issue({"JENKINS-57563", "JENKINS-62708"}) + @LocalData // Just a scriptApproval.xml that whitelists 'staticMethod jenkins.model.Jenkins getInstance' and a script printing all labels @Test public void upgradeSmokes() throws Exception { + configureSecurity(); FreeStyleProject p = r.createFreeStyleProject(); p.getPublishersList().add(new TestGroovyRecorder( new SecureGroovyScript("jenkins.model.Jenkins.instance", true, null))); - r.assertLogNotContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: " - + "Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", + p.getPublishersList().add(new TestGroovyRecorder( + new SecureGroovyScript("println(jenkins.model.Jenkins.instance.getLabels())", false, null))); + r.assertLogNotContains("org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedUsageException: script not yet approved for use", r.assertBuildStatus(Result.SUCCESS, p.scheduleBuild2(0).get())); } diff --git a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest/upgradeSmokes/scriptApproval.xml b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest/upgradeSmokes/scriptApproval.xml index 753c1b0e6..b15a50a3d 100644 --- a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest/upgradeSmokes/scriptApproval.xml +++ b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApprovalTest/upgradeSmokes/scriptApproval.xml @@ -1,6 +1,8 @@ - + + fccae58c5762bdd15daca97318e9d74333203106 + staticMethod jenkins.model.Jenkins getInstance diff --git a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test.yaml b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test.yaml index 5225d1885..366aa49de 100644 --- a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test.yaml +++ b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test.yaml @@ -2,3 +2,5 @@ security: scriptApproval: approvedSignatures: - method java.net.URI getHost + approvedScriptHashes: + - fccae58c5762bdd15daca97318e9d74333203106 diff --git a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test_expected.yaml b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test_expected.yaml index 2e73906fc..73bc4b2da 100644 --- a/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test_expected.yaml +++ b/src/test/resources/org/jenkinsci/plugins/scriptsecurity/scripts/smoke_test_expected.yaml @@ -1,2 +1,4 @@ +approvedScriptHashes: +- "fccae58c5762bdd15daca97318e9d74333203106" approvedSignatures: - "method java.net.URI getHost"