Skip to content

Commit d2d4104

Browse files
committed
Only add hyperlink if the user has RUN_SCRIPTS.
1 parent 7eddd97 commit d2d4104

File tree

3 files changed

+89
-8
lines changed

3 files changed

+89
-8
lines changed

src/main/java/org/jenkinsci/plugins/workflow/cps/SandboxContinuable.java

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@
66
import java.io.IOException;
77
import java.util.List;
88

9-
import hudson.console.HyperlinkNote;
9+
import hudson.Extension;
10+
import hudson.MarkupText;
11+
import hudson.console.ConsoleAnnotationDescriptor;
12+
import hudson.console.ConsoleAnnotator;
13+
import hudson.console.ConsoleNote;
14+
import jenkins.model.Jenkins;
15+
import org.jenkinsci.Symbol;
1016
import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
1117
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox;
1218
import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext;
1319
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
20+
import org.kohsuke.stapler.Stapler;
21+
import org.kohsuke.stapler.StaplerRequest;
1422

1523
import java.util.concurrent.Callable;
1624
import java.util.logging.Level;
@@ -44,8 +52,7 @@ public Outcome call() {
4452
ScriptApproval.get().accessRejected(x, ApprovalContext.create());
4553
try {
4654
e.getOwner().getListener().getLogger().println(x.getMessage() + ". " +
47-
HyperlinkNote.encodeTo("/" + ScriptApproval.get().getUrlName(),
48-
Messages.SandboxContinuable_ScriptApprovalLink()));
55+
ScriptApprovalNote.encodeTo(Messages.SandboxContinuable_ScriptApprovalLink()));
4956
} catch (IOException ex) {
5057
LOGGER.log(Level.WARNING, null, ex);
5158
}
@@ -72,5 +79,52 @@ public Outcome call() {
7279
}
7380
}
7481

82+
public static final class ScriptApprovalNote extends ConsoleNote {
83+
private int length;
84+
85+
public ScriptApprovalNote(int length) {
86+
this.length = length;
87+
}
88+
89+
@Override
90+
public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
91+
if (Jenkins.getActiveInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
92+
String url = "/" + ScriptApproval.get().getUrlName();
93+
94+
StaplerRequest req = Stapler.getCurrentRequest();
95+
96+
if (req!=null) {
97+
// if we are serving HTTP request, we want to use app relative URL
98+
url = req.getContextPath()+url;
99+
} else {
100+
// otherwise presumably this is rendered for e-mails and other non-HTTP stuff
101+
url = Jenkins.getInstance().getRootUrl()+url.substring(1);
102+
}
103+
104+
text.addMarkup(charPos, charPos + length, "<a href='" + url + "'>", "</a>");
105+
}
106+
107+
return null;
108+
}
109+
110+
public static String encodeTo(String text) {
111+
try {
112+
return new ScriptApprovalNote(text.length()).encode()+text;
113+
} catch (IOException e) {
114+
// impossible, but don't make this a fatal problem
115+
LOGGER.log(Level.WARNING, "Failed to serialize "+ScriptApprovalNote.class,e);
116+
return text;
117+
}
118+
}
119+
120+
@Extension
121+
@Symbol("scriptApprovalLink")
122+
public static class DescriptorImpl extends ConsoleAnnotationDescriptor {
123+
public String getDisplayName() {
124+
return "Script Approval Link";
125+
}
126+
}
127+
}
128+
75129
private static final Logger LOGGER = Logger.getLogger(SandboxContinuable.class.getName());
76130
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
Snippetizer.this_step_should_not_normally_be_used_in=This step should not normally be used in your script. Consult the inline help for details.
2-
SandboxContinuable.ScriptApprovalLink=Administrators can click here to approve or reject this signature.
2+
SandboxContinuable.ScriptApprovalLink=Administrators can decide whether to approve or reject this signature.

src/test/java/org/jenkinsci/plugins/workflow/cps/CpsFlowDefinition2Test.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@
3131
import hudson.Functions;
3232
import hudson.model.Computer;
3333
import hudson.model.Executor;
34+
import hudson.model.Item;
3435
import hudson.model.Result;
36+
3537
import java.util.logging.Level;
38+
39+
import hudson.security.GlobalMatrixAuthorizationStrategy;
40+
import jenkins.model.Jenkins;
3641
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
3742
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
3843
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
@@ -49,6 +54,7 @@
4954
import org.junit.Test;
5055
import org.jvnet.hudson.test.BuildWatcher;
5156
import org.jvnet.hudson.test.Issue;
57+
import org.jvnet.hudson.test.JenkinsRule;
5258
import org.jvnet.hudson.test.LoggerRule;
5359

5460
public class CpsFlowDefinition2Test extends AbstractCpsFlowTest {
@@ -174,6 +180,15 @@ public void superCallsSandboxed() throws Exception {
174180

175181
@Test
176182
public void sandboxInvokerUsed() throws Exception {
183+
jenkins.jenkins.setSecurityRealm(jenkins.createDummySecurityRealm());
184+
GlobalMatrixAuthorizationStrategy gmas = new GlobalMatrixAuthorizationStrategy();
185+
// Set up a user with RUN_SCRIPTS and one without..
186+
gmas.add(Jenkins.RUN_SCRIPTS, "runScriptsUser");
187+
gmas.add(Jenkins.READ, "runScriptsUser");
188+
gmas.add(Item.READ, "runScriptsUser");
189+
gmas.add(Jenkins.READ, "otherUser");
190+
gmas.add(Item.READ, "otherUser");
191+
jenkins.jenkins.setAuthorizationStrategy(gmas);
177192
WorkflowJob job = jenkins.jenkins.createProject(WorkflowJob.class, "p");
178193
job.setDefinition(new CpsFlowDefinition("[a: 1, b: 2].collectEntries { k, v ->\n" +
179194
" Jenkins.getInstance()\n" +
@@ -184,13 +199,25 @@ public void sandboxInvokerUsed() throws Exception {
184199
jenkins.assertLogContains("org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance", r);
185200
jenkins.assertLogContains("Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance. " + Messages.SandboxContinuable_ScriptApprovalLink(), r);
186201

187-
// make sure we see the annotation
188-
HtmlPage rsp = jenkins.createWebClient().getPage(r, "console");
202+
JenkinsRule.WebClient wc = jenkins.createWebClient();
203+
204+
wc.login("runScriptsUser");
205+
// make sure we see the annotation for the RUN_SCRIPTS user.
206+
HtmlPage rsp = wc.getPage(r, "console");
189207
assertEquals(1, DomNodeUtil.selectNodes(rsp, "//A[@href='" + jenkins.contextPath + "/scriptApproval']").size());
190208

191-
// make sure raw console output doesn't include the garbage
192-
TextPage raw = (TextPage)jenkins.createWebClient().goTo(r.getUrl()+"consoleText","text/plain");
209+
// make sure raw console output doesn't include the garbage and has the right message.
210+
TextPage raw = (TextPage)wc.goTo(r.getUrl()+"consoleText","text/plain");
193211
assertThat(raw.getContent(), containsString(" getInstance. " + Messages.SandboxContinuable_ScriptApprovalLink()));
212+
213+
wc.login("otherUser");
214+
// make sure we don't see the link for the other user.
215+
HtmlPage rsp2 = wc.getPage(r, "console");
216+
assertEquals(0, DomNodeUtil.selectNodes(rsp2, "//A[@href='" + jenkins.contextPath + "/scriptApproval']").size());
217+
218+
// make sure raw console output doesn't include the garbage and has the right message.
219+
TextPage raw2 = (TextPage)wc.goTo(r.getUrl()+"consoleText","text/plain");
220+
assertThat(raw2.getContent(), containsString(" getInstance. " + Messages.SandboxContinuable_ScriptApprovalLink()));
194221
}
195222

196223
@Issue("SECURITY-551")

0 commit comments

Comments
 (0)