package hudson.plugins.emailext.plugins.trigger; import groovy.lang.Binding; import groovy.lang.GroovyShell; import hudson.model.AbstractBuild; import hudson.model.Item; import hudson.model.TaskListener; import hudson.plugins.emailext.groovy.sandbox.PrintStreamInstanceWhitelist; import hudson.plugins.emailext.plugins.EmailTrigger; import hudson.plugins.emailext.plugins.RecipientProvider; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ImportCustomizer; import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException; import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript; import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist; import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; import org.jenkinsci.plugins.scriptsecurity.scripts.ClasspathEntry; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; import org.jenkinsci.plugins.scriptsecurity.scripts.languages.GroovyLanguage; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import javax.annotation.Nonnull; import java.io.IOException; import java.io.ObjectStreamException; import java.io.PrintStream; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; public abstract class AbstractScriptTrigger extends EmailTrigger { protected SecureGroovyScript secureTriggerScript; public AbstractScriptTrigger(List<RecipientProvider> recipientProviders, String recipientList, String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType, SecureGroovyScript secureTriggerScript) { super(recipientProviders, recipientList, replyTo, subject, body, attachmentsPattern, attachBuildLog, contentType); this.secureTriggerScript = secureTriggerScript; StaplerRequest request = Stapler.getCurrentRequest(); ApprovalContext context = ApprovalContext.create().withCurrentUser(); if (request != null) { context = context.withItem(request.findAncestorObject(Item.class)); } this.secureTriggerScript.configuring(context); } @Deprecated public AbstractScriptTrigger(List<RecipientProvider> recipientProviders, String recipientList, String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType, String triggerScript) { this(recipientProviders, recipientList, replyTo, subject, body, attachmentsPattern, attachBuildLog, contentType, new SecureGroovyScript(triggerScript, false, null)); } @Deprecated public AbstractScriptTrigger(boolean sendToList, boolean sendToDevs, boolean sendToRequester, boolean sendToCulprits, String recipientList, String replyTo, String subject, String body, String attachmentsPattern, int attachBuildLog, String contentType, String triggerScript) { super(sendToList, sendToDevs, sendToRequester, sendToCulprits,recipientList, replyTo, subject, body, attachmentsPattern, attachBuildLog, contentType); this.triggerScript = triggerScript; } @Deprecated public String getTriggerScript() { return secureTriggerScript.getScript(); } public SecureGroovyScript getSecureTriggerScript() { return secureTriggerScript; } private boolean hasScript() { return secureTriggerScript != null && StringUtils.isNotEmpty(secureTriggerScript.getScript()); } @Override public boolean configure(@Nonnull StaplerRequest req, @Nonnull JSONObject formData) { super.configure(req, formData); if(formData.containsKey("secureTriggerScript")) { this.secureTriggerScript = req.bindJSON(SecureGroovyScript.class, formData.getJSONObject("secureTriggerScript")); this.secureTriggerScript.configuring(ApprovalContext.create().withCurrentUser().withItem(req.findAncestorObject(Item.class))); } return true; } @Override public abstract boolean isPreBuild(); @Override public boolean trigger(AbstractBuild<?, ?> build, TaskListener listener) { boolean result = false; if (hasScript()) { try { Object res = evaluate(build, listener); if (res != null) { result = (Boolean) res; } } catch (IOException e) { e.printStackTrace(listener.fatalError("Failed evaluating script trigger %s%n", e.getMessage())); } finally { } } return result; } private Object evaluate(AbstractBuild<?, ?> build, TaskListener listener) throws IOException { ClassLoader loader = Jenkins.getActiveInstance().getPluginManager().uberClassLoader; JenkinsLocationConfiguration configuration = JenkinsLocationConfiguration.get(); assert configuration != null; URLClassLoader urlcl = null; List<ClasspathEntry> cp = secureTriggerScript.getClasspath(); if (!cp.isEmpty()) { List<URL> urlList = new ArrayList<URL>(cp.size()); for (ClasspathEntry entry : cp) { ScriptApproval.get().using(entry); urlList.add(entry.getURL()); } loader = urlcl = new URLClassLoader(urlList.toArray(new URL[urlList.size()]), loader); } try { loader = GroovySandbox.createSecureClassLoader(loader); CompilerConfiguration cc; if(secureTriggerScript.isSandbox()) { cc = GroovySandbox.createSecureCompilerConfiguration(); } else { cc = new CompilerConfiguration(); } cc.addCompilationCustomizers(new ImportCustomizer().addStarImports( "jenkins", "jenkins.model", "hudson", "hudson.model")); Binding binding = new Binding(); binding.setVariable("build", build); binding.setVariable("project", build.getParent()); binding.setVariable("rooturl", configuration.getUrl()); PrintStream logger = listener.getLogger(); binding.setVariable("out", logger); GroovyShell shell = new GroovyShell(loader, binding, cc); if (secureTriggerScript.isSandbox()) { try { return GroovySandbox.run(shell.parse(secureTriggerScript.getScript()), new ProxyWhitelist( Whitelist.all(), new PrintStreamInstanceWhitelist(logger))); } catch (RejectedAccessException x) { throw ScriptApproval.get().accessRejected(x, ApprovalContext.create()); } } else { return shell.evaluate(ScriptApproval.get().using(secureTriggerScript.getScript(), GroovyLanguage.get())); } } finally { if (urlcl != null) { urlcl.close(); } } } @Deprecated protected transient String triggerScript; /** * Called when object has been deserialized from a stream. * * @return {@code this}, or a replacement for {@code this}. * @throws ObjectStreamException if the object cannot be restored. * @see <a href="http://download.oracle.com/javase/1.3/docs/guide/serialization/spec/input.doc6.html">The Java Object Serialization Specification</a> */ private Object readResolve() throws ObjectStreamException { if (triggerScript != null && secureTriggerScript == null) { this.secureTriggerScript = new SecureGroovyScript(triggerScript, false, null); this.secureTriggerScript.configuring(ApprovalContext.create()); triggerScript = null; } return this; } }