Skip to content

Commit 4e2cf11

Browse files
committed
Add agent-secret endpoint to SlaveComputer
Introduces a new /agent-secret web method in SlaveComputer to expose the agent's JNLP MAC. Adds corresponding tests to verify access control and response correctness for users with and without the required permission.
1 parent e690ade commit 4e2cf11

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

core/src/main/java/hudson/slaves/SlaveComputer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import hudson.security.ACLContext;
5757
import hudson.slaves.OfflineCause.ChannelTermination;
5858
import hudson.util.Futures;
59+
import hudson.util.HttpResponses;
5960
import hudson.util.RingBufferLogHandler;
6061
import hudson.util.StreamTaskListener;
6162
import hudson.util.VersionNumber;
@@ -890,6 +891,15 @@ public HttpResponse doJenkinsAgentJnlp(StaplerRequest2 req, StaplerResponse2 res
890891
return new EncryptedSlaveAgentJnlpFile(this, "jenkins-agent.jnlp.jelly", getName(), CONNECT);
891892
}
892893

894+
@WebMethod(name = "agent-secret")
895+
public HttpResponse doAgentSecret(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
896+
checkPermission(CONNECT);
897+
898+
rsp.setContentType("text/plain;charset=UTF-8");
899+
rsp.getWriter().write(getJnlpMac());
900+
return HttpResponses.ok();
901+
}
902+
893903
class LowPermissionResponse {
894904
@WebMethod(name = "jenkins-agent.jnlp")
895905
public HttpResponse doJenkinsAgentJnlp(StaplerRequest2 req, StaplerResponse2 res) {

test/src/test/java/hudson/slaves/SlaveComputerTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static org.junit.jupiter.api.Assertions.assertFalse;
3333
import static org.junit.jupiter.api.Assertions.assertNotNull;
3434
import static org.junit.jupiter.api.Assertions.assertNull;
35+
import static org.junit.jupiter.api.Assertions.assertThrows;
3536
import static org.junit.jupiter.api.Assertions.assertTrue;
3637
import static org.junit.jupiter.api.Assumptions.assumeFalse;
3738

@@ -48,6 +49,8 @@
4849
import jenkins.model.Jenkins;
4950
import net.sf.json.JSONNull;
5051
import net.sf.json.JSONObject;
52+
import org.htmlunit.FailingHttpStatusCodeException;
53+
import org.htmlunit.Page;
5154
import org.htmlunit.WebResponse;
5255
import org.junit.jupiter.api.BeforeEach;
5356
import org.junit.jupiter.api.Test;
@@ -228,4 +231,51 @@ private String getRemoteFS(Node node, String user) throws Exception {
228231
return pathObj.toString();
229232
}
230233
}
234+
235+
@Test
236+
void testAgentSecretWithAgentConnectPermission() throws Exception {
237+
DumbSlave testAgent = j.createOnlineSlave();
238+
239+
// Setup user with Agent/Connect permission
240+
String userWithConnect = "user-with-connect";
241+
MockAuthorizationStrategy authStrategy = new MockAuthorizationStrategy();
242+
authStrategy.grant(Computer.CONNECT, Jenkins.READ).everywhere().to(userWithConnect);
243+
244+
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
245+
j.jenkins.setAuthorizationStrategy(authStrategy);
246+
247+
JenkinsRule.WebClient wc = j.createWebClient();
248+
wc.login(userWithConnect);
249+
250+
Page page = wc.goTo("computer/" + testAgent.getNodeName() + "/agent-secret", "text/plain");
251+
WebResponse response = page.getWebResponse();
252+
253+
// Verify response
254+
assertEquals(200, response.getStatusCode());
255+
256+
String secret = response.getContentAsString().trim();
257+
assertNotNull(secret);
258+
assertEquals(testAgent.getComputer().getJnlpMac(), secret);
259+
}
260+
261+
@Test
262+
void testAgentSecretWithoutAgentConnectPermission() throws Exception {
263+
DumbSlave testAgent = j.createOnlineSlave();
264+
265+
// Setup user without Agent/Connect permission
266+
String userWithoutConnect = "user-without-connect";
267+
MockAuthorizationStrategy authStrategy = new MockAuthorizationStrategy();
268+
269+
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
270+
j.jenkins.setAuthorizationStrategy(authStrategy);
271+
272+
JenkinsRule.WebClient wc = j.createWebClient();
273+
// Expect 403 Forbidden
274+
FailingHttpStatusCodeException e = assertThrows(FailingHttpStatusCodeException.class, () -> {
275+
wc.goTo("computer/" + testAgent.getNodeName() + "/agent-secret", "text/plain");
276+
});
277+
278+
// Verify it's a 403 Forbidden
279+
assertEquals(403, e.getStatusCode());
280+
}
231281
}

0 commit comments

Comments
 (0)