Skip to content

Commit c7477b1

Browse files
committed
Merge pull request #209 from AndreBrinkop/add-jenkins-agent-support
Add Jenkins agent support for GitHub Committer Authorization Strategy
2 parents 7664e3b + fc00869 commit c7477b1

File tree

5 files changed

+84
-6
lines changed

5 files changed

+84
-6
lines changed

src/main/java/org/jenkinsci/plugins/GithubAuthorizationStrategy.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ of this software and associated documentation files (the "Software"), to deal
3030
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
3131
import org.jenkinsci.plugins.workflow.multibranch.BranchJobProperty;
3232
import org.kohsuke.stapler.DataBoundConstructor;
33+
import org.kohsuke.stapler.DataBoundSetter;
3334

3435
import java.util.Collection;
3536
import java.util.Collections;
@@ -140,6 +141,23 @@ public String getAdminUserNames() {
140141
return StringUtils.join(rootACL.getAdminUserNameList().iterator(), ", ");
141142
}
142143

144+
/** Set the agent username. We use a setter instead of a constructor to make this an optional field
145+
* to avoid a breaking change.
146+
* @see org.jenkinsci.plugins.GithubRequireOrganizationMembershipACL#setAgentUserName(String)
147+
*/
148+
@DataBoundSetter
149+
public void setAgentUserName(String agentUserName) {
150+
rootACL.setAgentUserName(agentUserName);
151+
}
152+
153+
/**
154+
* @return agentUserName
155+
* @see GithubRequireOrganizationMembershipACL#getAgentUserName()
156+
*/
157+
public String getAgentUserName() {
158+
return rootACL.getAgentUserName();
159+
}
160+
143161
/**
144162
* @return isUseRepositoryPermissions
145163
* @see org.jenkinsci.plugins.GithubRequireOrganizationMembershipACL#isUseRepositoryPermissions()
@@ -208,6 +226,7 @@ public boolean equals(Object object){
208226
GithubAuthorizationStrategy obj = (GithubAuthorizationStrategy) object;
209227
return this.getOrganizationNames().equals(obj.getOrganizationNames()) &&
210228
this.getAdminUserNames().equals(obj.getAdminUserNames()) &&
229+
this.getAgentUserName().equals(obj.getAgentUserName()) &&
211230
this.isUseRepositoryPermissions() == obj.isUseRepositoryPermissions() &&
212231
this.isAuthenticatedUserCreateJobPermission() == obj.isAuthenticatedUserCreateJobPermission() &&
213232
this.isAuthenticatedUserReadPermission() == obj.isAuthenticatedUserReadPermission() &&

src/main/java/org/jenkinsci/plugins/GithubRequireOrganizationMembershipACL.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ of this software and associated documentation files (the "Software"), to deal
2626
*/
2727
package org.jenkinsci.plugins;
2828

29+
import hudson.model.*;
2930
import org.acegisecurity.Authentication;
3031
import org.jenkinsci.plugins.github_branch_source.GitHubSCMSource;
3132
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
@@ -41,10 +42,6 @@ of this software and associated documentation files (the "Software"), to deal
4142
import edu.umd.cs.findbugs.annotations.NonNull;
4243
import edu.umd.cs.findbugs.annotations.Nullable;
4344

44-
import hudson.model.AbstractItem;
45-
import hudson.model.AbstractProject;
46-
import hudson.model.Describable;
47-
import hudson.model.Item;
4845
import hudson.plugins.git.GitSCM;
4946
import hudson.plugins.git.UserRemoteConfig;
5047
import hudson.security.ACL;
@@ -64,6 +61,7 @@ public class GithubRequireOrganizationMembershipACL extends ACL {
6461

6562
private final List<String> organizationNameList;
6663
private final List<String> adminUserNameList;
64+
private String agentUserName;
6765
private final boolean authenticatedUserReadPermission;
6866
private final boolean useRepositoryPermissions;
6967
private final boolean authenticatedUserCreateJobPermission;
@@ -102,6 +100,12 @@ public boolean hasPermission(@NonNull Authentication a, @NonNull Permission perm
102100
return true;
103101
}
104102

103+
// Grant agent permissions to agent user
104+
if (candidateName.equalsIgnoreCase(agentUserName) && checkAgentUserPermission(permission)) {
105+
log.finest("Granting Agent Connect rights to user " + candidateName);
106+
return true;
107+
}
108+
105109
// Are they trying to read?
106110
if (checkReadPermission(permission)) {
107111
// if we support authenticated read return early
@@ -153,6 +157,12 @@ else if (testBuildPermission(permission) && isInWhitelistedOrgs(authenticationTo
153157
return true;
154158
}
155159

160+
// Grant agent permissions to agent user
161+
if (authenticatedUserName.equalsIgnoreCase(agentUserName) && checkAgentUserPermission(permission)) {
162+
log.finest("Granting Agent Connect rights to user " + authenticatedUserName);
163+
return true;
164+
}
165+
156166
if (authenticatedUserName.equals("anonymous")) {
157167
if (checkJobStatusPermission(permission) && allowAnonymousJobStatusPermission) {
158168
return true;
@@ -239,6 +249,13 @@ private boolean checkReadPermission(@NonNull Permission permission) {
239249
|| id.equals("hudson.model.Item.Read"));
240250
}
241251

252+
private boolean checkAgentUserPermission(@NonNull Permission permission) {
253+
return permission.equals(Hudson.READ)
254+
|| permission.equals(Computer.CREATE)
255+
|| permission.equals(Computer.CONNECT)
256+
|| permission.equals(Computer.CONFIGURE);
257+
}
258+
242259
private boolean checkJobStatusPermission(@NonNull Permission permission) {
243260
return permission.getId().equals("hudson.model.Item.ViewStatus");
244261
}
@@ -314,10 +331,11 @@ public GithubRequireOrganizationMembershipACL(String adminUserNames,
314331
}
315332

316333
this.item = null;
334+
this.agentUserName = ""; // Initially blank - populated by a setter since this field is optional
317335
}
318336

319337
public GithubRequireOrganizationMembershipACL cloneForProject(AbstractItem item) {
320-
return new GithubRequireOrganizationMembershipACL(
338+
GithubRequireOrganizationMembershipACL acl = new GithubRequireOrganizationMembershipACL(
321339
this.adminUserNameList,
322340
this.organizationNameList,
323341
this.authenticatedUserReadPermission,
@@ -328,6 +346,8 @@ public GithubRequireOrganizationMembershipACL cloneForProject(AbstractItem item)
328346
this.allowAnonymousReadPermission,
329347
this.allowAnonymousJobStatusPermission,
330348
item);
349+
acl.setAgentUserName(agentUserName);
350+
return acl;
331351
}
332352

333353
public GithubRequireOrganizationMembershipACL(List<String> adminUserNameList,
@@ -362,6 +382,11 @@ public List<String> getAdminUserNameList() {
362382
return adminUserNameList;
363383
}
364384

385+
public void setAgentUserName(String agentUserName) {
386+
this.agentUserName = agentUserName;
387+
}
388+
public String getAgentUserName() { return agentUserName; }
389+
365390
public boolean isUseRepositoryPermissions() {
366391
return useRepositoryPermissions;
367392
}

src/main/resources/org/jenkinsci/plugins/GithubAuthorizationStrategy/config.jelly

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
<f:textbox />
99
</f:entry>
1010

11+
<f:entry title="Agent User Name" field="agentUserName" help="/plugin/github-oauth/help/auth/agent-user-name-help.html" >
12+
<f:textbox />
13+
</f:entry>
14+
1115
<f:entry title="Participant in Organization" field="organizationNames" help="/plugin/github-oauth/help/auth/organization-names-help.html">
1216
<f:textbox />
1317
</f:entry>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div>
2+
If you are using inbound Jenkins agents, this is the user that is used for authenticating agents. This user will receive rights to create, connect and configure agents.
3+
</div>

src/test/java/org/jenkinsci/plugins/GithubRequireOrganizationMembershipACLTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ of this software and associated documentation files (the "Software"), to deal
6060
import java.util.Collections;
6161
import java.util.List;
6262

63+
import hudson.model.Computer;
6364
import hudson.model.Hudson;
6465
import hudson.model.Item;
6566
import hudson.model.Messages;
@@ -130,7 +131,7 @@ private void mockJenkins(MockedStatic<Jenkins> mockedJenkins) {
130131
new GrantedAuthority[]{new GrantedAuthorityImpl("anonymous")});
131132

132133
private GithubRequireOrganizationMembershipACL createACL() {
133-
return new GithubRequireOrganizationMembershipACL(
134+
GithubRequireOrganizationMembershipACL acl = new GithubRequireOrganizationMembershipACL(
134135
"admin",
135136
"myOrg",
136137
authenticatedUserReadPermission,
@@ -140,6 +141,8 @@ private GithubRequireOrganizationMembershipACL createACL() {
140141
allowAnonymousCCTrayPermission,
141142
allowAnonymousReadPermission,
142143
allowAnonymousJobStatusPermission);
144+
acl.setAgentUserName("agent");
145+
return acl;
143146
}
144147

145148
private GithubRequireOrganizationMembershipACL aclForProject(Project project) {
@@ -554,6 +557,30 @@ public void testCannotReadRepositoryWithInvalidRepoUrl() throws IOException {
554557
}
555558
}
556559

560+
@Test
561+
public void testAgentUserCanCreateConnectAndConfigureAgents() {
562+
GithubAuthenticationToken authenticationToken = Mockito.mock(GithubAuthenticationToken.class);
563+
Mockito.when(authenticationToken.isAuthenticated()).thenReturn(true);
564+
Mockito.when(authenticationToken.getName()).thenReturn("agent");
565+
GithubRequireOrganizationMembershipACL acl = createACL();
566+
567+
assertTrue(acl.hasPermission(authenticationToken, Computer.CREATE));
568+
assertTrue(acl.hasPermission(authenticationToken, Computer.CONFIGURE));
569+
assertTrue(acl.hasPermission(authenticationToken, Computer.CONNECT));
570+
}
571+
572+
@Test
573+
public void testAuthenticatedCanNotCreateConnectAndConfigureAgents() {
574+
GithubAuthenticationToken authenticationToken = Mockito.mock(GithubAuthenticationToken.class);
575+
Mockito.when(authenticationToken.isAuthenticated()).thenReturn(true);
576+
Mockito.when(authenticationToken.getName()).thenReturn("authenticated");
577+
GithubRequireOrganizationMembershipACL acl = createACL();
578+
579+
assertFalse(acl.hasPermission(authenticationToken, Computer.CREATE));
580+
assertFalse(acl.hasPermission(authenticationToken, Computer.CONFIGURE));
581+
assertFalse(acl.hasPermission(authenticationToken, Computer.CONNECT));
582+
}
583+
557584
@Test
558585
public void testAnonymousCanViewJobStatusWhenGranted() {
559586
this.allowAnonymousJobStatusPermission = true;

0 commit comments

Comments
 (0)