diff --git a/pom.xml b/pom.xml
index 83c59d5..ae40ed2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@ THE SOFTWARE.
cas-plugin
- 1.3.1-SNAPSHOT
+ 1.4.0-SNAPSHOT
hpi
CAS Plugin
http://wiki.jenkins-ci.org/display/JENKINS/CAS+Plugin
@@ -140,6 +140,11 @@ THE SOFTWARE.
mailer
1.16
+
+ org.jenkins-ci.plugins
+ script-security
+ 1.27
+
org.jasig.cas.client
cas-client-core
diff --git a/src/main/java/org/jenkinsci/plugins/cas/protocols/Cas10Protocol.java b/src/main/java/org/jenkinsci/plugins/cas/protocols/Cas10Protocol.java
index ca0beb6..be151c2 100644
--- a/src/main/java/org/jenkinsci/plugins/cas/protocols/Cas10Protocol.java
+++ b/src/main/java/org/jenkinsci/plugins/cas/protocols/Cas10Protocol.java
@@ -1,12 +1,5 @@
package org.jenkinsci.plugins.cas.protocols;
-import groovy.lang.GroovyShell;
-import groovy.lang.Script;
-import hudson.Extension;
-import hudson.Util;
-import hudson.model.Descriptor;
-import hudson.util.FormValidation;
-
import java.util.Collection;
import org.codehaus.groovy.control.CompilationFailedException;
@@ -14,9 +7,18 @@
import org.jenkinsci.plugins.cas.CasProtocol;
import org.jenkinsci.plugins.cas.Messages;
import org.jenkinsci.plugins.cas.validation.Cas10RoleParsingTicketValidator;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
+import org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedClasspathException;
+import org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedUsageException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
+import hudson.Extension;
+import hudson.Util;
+import hudson.model.Descriptor;
+import hudson.util.FormValidation;
+
/**
* CAS 1.0 protocol support.
*
@@ -27,11 +29,21 @@ public class Cas10Protocol extends CasProtocol {
public final String rolesValidationScript;
public final String testValidationResponse;
+ public final boolean sandbox;
- @DataBoundConstructor
+ private final SecureGroovyScript secureRolesValidationScript;
+
+ @Deprecated
public Cas10Protocol(String rolesValidationScript, String testValidationResponse) {
+ this(rolesValidationScript, testValidationResponse, false);
+ }
+
+ @DataBoundConstructor
+ public Cas10Protocol(String rolesValidationScript, String testValidationResponse, boolean sandbox) {
this.rolesValidationScript = Util.fixEmptyAndTrim(rolesValidationScript);
this.testValidationResponse = Util.fixEmpty(testValidationResponse);
+ this.sandbox = sandbox;
+ this.secureRolesValidationScript = getSecureGroovyScript(this.rolesValidationScript, this.sandbox);
}
@Override
@@ -42,10 +54,14 @@ public String getAuthoritiesAttribute() {
@Override
public TicketValidator createTicketValidator(String casServerUrl) {
Cas10RoleParsingTicketValidator ticketValidator = new Cas10RoleParsingTicketValidator(casServerUrl);
- ticketValidator.setRolesValidationScript(rolesValidationScript);
+ ticketValidator.setRolesValidationScript(secureRolesValidationScript);
return ticketValidator;
}
+ private static SecureGroovyScript getSecureGroovyScript(String script, boolean sandbox) {
+ return new SecureGroovyScript(script, sandbox, null).configuringWithKeyItem();
+ }
+
@Extension
public static final class DescriptorImpl extends Descriptor {
@Override
@@ -56,10 +72,10 @@ public String getDisplayName() {
@SuppressWarnings("rawtypes")
public FormValidation doTestScript(
@QueryParameter("rolesValidationScript") final String rolesValidationScript,
- @QueryParameter("testValidationResponse") final String testValidationResponse) {
+ @QueryParameter("testValidationResponse") final String testValidationResponse,
+ @QueryParameter("sandbox") final boolean sandbox) {
try {
- Script script = new GroovyShell().parse(rolesValidationScript);
- Collection roles = Cas10RoleParsingTicketValidator.parseRolesFromValidationResponse(script, testValidationResponse);
+ Collection roles = Cas10RoleParsingTicketValidator.parseRolesFromValidationResponse(getSecureGroovyScript(rolesValidationScript, sandbox), testValidationResponse);
if (roles == null) {
return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_noResult());
}
@@ -68,6 +84,14 @@ public FormValidation doTestScript(
return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_compilationError() + ": " + e);
} catch (ClassCastException e) {
return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_returnTypeError() + ": " + e);
+ } catch (RejectedAccessException e) {
+ return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_rejectedAccessError() + ": " + e);
+ } catch (UnapprovedUsageException e) {
+ return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_unapprovedUsageError() + ": " + e);
+ } catch (UnapprovedClasspathException e) {
+ return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_unapprovedClasspathError() + ": " + e);
+ } catch (Exception e) {
+ return FormValidation.error(Messages.Cas10Protocol_rolesValidationScript_unknownError() + ": " + e);
}
}
}
diff --git a/src/main/java/org/jenkinsci/plugins/cas/validation/Cas10RoleParsingTicketValidator.java b/src/main/java/org/jenkinsci/plugins/cas/validation/Cas10RoleParsingTicketValidator.java
index 34035ab..cc74dab 100644
--- a/src/main/java/org/jenkinsci/plugins/cas/validation/Cas10RoleParsingTicketValidator.java
+++ b/src/main/java/org/jenkinsci/plugins/cas/validation/Cas10RoleParsingTicketValidator.java
@@ -1,10 +1,6 @@
package org.jenkinsci.plugins.cas.validation;
-import groovy.lang.GroovyShell;
-import groovy.lang.Script;
-
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
@@ -12,13 +8,16 @@
import java.util.List;
import java.util.Map;
-import org.apache.commons.lang.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.TicketValidationException;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;
+
+import groovy.lang.Binding;
+import jenkins.model.Jenkins;
/**
* Implementation of a Ticket Validator that can validate tickets conforming to the CAS 1.0 specification.
@@ -31,9 +30,8 @@ public class Cas10RoleParsingTicketValidator extends AbstractCasProtocolUrlBased
public static final String DEFAULT_ROLE_ATTRIBUTE = "roles";
- private String rolesValidationScript;
+ private SecureGroovyScript rolesValidationScript;
private String rolesAttribute = DEFAULT_ROLE_ATTRIBUTE;
- private Script parsedScript;
public Cas10RoleParsingTicketValidator(final String casServerUrlPrefix) {
super(casServerUrlPrefix);
@@ -61,7 +59,7 @@ protected Assertion parseResponseFromServer(final String response) throws Ticket
reader.readLine();
final String name = reader.readLine();
- List roles = parseRolesFromValidationResponse(getParsedScript(), response);
+ List roles = parseRolesFromValidationResponse(rolesValidationScript, response);
if (roles != null) {
Map attributes = new HashMap(1);
attributes.put(rolesAttribute, roles);
@@ -71,7 +69,7 @@ protected Assertion parseResponseFromServer(final String response) throws Ticket
return new AssertionImpl(name);
}
- } catch (final IOException e) {
+ } catch (final Exception e) {
throw new TicketValidationException("Unable to parse response.", e);
}
}
@@ -83,13 +81,14 @@ protected Assertion parseResponseFromServer(final String response) throws Ticket
* @return list of roles
*/
@SuppressWarnings("rawtypes")
- public static List parseRolesFromValidationResponse(Script script, String response) {
+ public static List parseRolesFromValidationResponse(SecureGroovyScript script, String response) throws Exception {
if (script == null)
return null;
// Run the script to parse the response
- script.getBinding().setVariable("response", response);
- Collection coll = (Collection) script.run();
+ Binding binding = new Binding();
+ binding.setVariable("response", response);
+ Collection coll = (Collection) script.evaluate(Jenkins.getInstance().getPluginManager().uberClassLoader, binding);
if (coll == null || coll.isEmpty())
return null;
@@ -104,30 +103,18 @@ public static List parseRolesFromValidationResponse(Script script, Strin
return roles;
}
- /**
- * Get the parsed Groovy roles validation script.
- * @return parsed Groovy script
- */
- protected synchronized Script getParsedScript() {
- if (parsedScript == null && StringUtils.isNotEmpty(rolesValidationScript)) {
- parsedScript = new GroovyShell().parse(rolesValidationScript);
- }
- return parsedScript;
- }
-
/**
* @return the rolesValidationScript
*/
- public String getRolesValidationScript() {
+ public SecureGroovyScript getRolesValidationScript() {
return rolesValidationScript;
}
/**
* @param rolesValidationScript the rolesValidationScript to set
*/
- public void setRolesValidationScript(String rolesValidationScript) {
+ public void setRolesValidationScript(SecureGroovyScript rolesValidationScript) {
this.rolesValidationScript = rolesValidationScript;
- this.parsedScript = null;
}
/**
diff --git a/src/main/resources/org/jenkinsci/plugins/cas/Messages.properties b/src/main/resources/org/jenkinsci/plugins/cas/Messages.properties
index d3b3492..3ea59ce 100644
--- a/src/main/resources/org/jenkinsci/plugins/cas/Messages.properties
+++ b/src/main/resources/org/jenkinsci/plugins/cas/Messages.properties
@@ -7,3 +7,7 @@ Cas10Protocol.rolesValidationScript.result=Roles parsed from the test validation
Cas10Protocol.rolesValidationScript.noResult=Roles Validation Script returned no result
Cas10Protocol.rolesValidationScript.compilationError=Roles Validation Script failed to compile
Cas10Protocol.rolesValidationScript.returnTypeError=Roles Validation Script did not return a Collection
+Cas10Protocol.rolesValidationScript.rejectedAccessError=Roles Validation Script uses forbidden language elements
+Cas10Protocol.rolesValidationScript.unapprovedUsageError=Roles Validation Script is not approved for execution
+Cas10Protocol.rolesValidationScript.unapprovedClasspathError=Roles Validation Script classpath is not approved
+Cas10Protocol.rolesValidationScript.unknownError=Roles Validation Script could not be tested due to an unknown error
diff --git a/src/main/resources/org/jenkinsci/plugins/cas/Messages_fr.properties b/src/main/resources/org/jenkinsci/plugins/cas/Messages_fr.properties
index f851e8e..2eb93f3 100644
--- a/src/main/resources/org/jenkinsci/plugins/cas/Messages_fr.properties
+++ b/src/main/resources/org/jenkinsci/plugins/cas/Messages_fr.properties
@@ -7,3 +7,7 @@ Cas10Protocol.rolesValidationScript.result=R
Cas10Protocol.rolesValidationScript.noResult=Le script de validation des rôles n''a retourné aucun résultat
Cas10Protocol.rolesValidationScript.compilationError=Le script de validation des rôles n''a pas pu être compilé
Cas10Protocol.rolesValidationScript.returnTypeError=Le script de validation des rôles n''a pas retourné de Collection
+Cas10Protocol.rolesValidationScript.rejectedAccessError=Le script de validation des rôles utilise des éléments interdits du langage
+Cas10Protocol.rolesValidationScript.unapprovedUsageError=Le script de validation des rôles n''est pas approuvé
+Cas10Protocol.rolesValidationScript.unapprovedClasspathError=Le script de validation des rôles utilise un classpath non approuvé
+Cas10Protocol.rolesValidationScript.unknownError=Le script de validation des rôles n''a pas pu être testé en raison d''une erreur inconnue
diff --git a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.jelly b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.jelly
index c565a8d..46955f6 100644
--- a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.jelly
+++ b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.jelly
@@ -9,9 +9,12 @@
+
+
+
-
+
diff --git a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.properties b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.properties
index 41de01f..882967f 100644
--- a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.properties
+++ b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config.properties
@@ -1,4 +1,5 @@
description=CAS 1.0 is a text-based protocol. Custom extensions may provide support for roles, which can be parsed with a Groovy script.
rolesValidationScript=Roles Validation Script
testValidationResponse=Test Validation Response
+sandbox=Use Groovy sandbox
testScript=Test Script
diff --git a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config_fr.properties b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config_fr.properties
index db7e9fd..7a1d4ae 100644
--- a/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config_fr.properties
+++ b/src/main/resources/org/jenkinsci/plugins/cas/protocols/Cas10Protocol/config_fr.properties
@@ -1,4 +1,5 @@
description=CAS 1.0 est un protocole basé sur du texte. Des extensions spécifiques peuvent apporter le support de rôles, qui peuvent être extraits à l''aide d''un script Groovy.
rolesValidationScript=Script de validation des rôles
testValidationResponse=Réponse de validation de test
+sandbox=Utiliser la sandbox Groovy
testScript=Tester le script