Skip to content

Commit 21537b5

Browse files
committed
Add support for GroupAccessToken credentials, fix unauthorized API calls
1 parent 40b5f0e commit 21537b5

File tree

19 files changed

+328
-43
lines changed

19 files changed

+328
-43
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ credentials:
343343
scope: SYSTEM
344344
id: "i<3GitLab"
345345
token: "glpat-XfsqZvVtAx5YCph5bq3r" # gitlab personal access token
346+
- gitlabGroupAccessToken:
347+
scope: SYSTEM
348+
id: "i<3GitLab"
349+
token: "glgat-XfsqZvVtAx5YCph5bq3r" # gitlab group access token
346350
347351
unclassified:
348352
gitLabServers:

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMFileSystem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ public SCMFileSystem build(@NonNull Item owner, @NonNull SCM scm, @CheckForNull
8484
public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head, @CheckForNull SCMRevision rev)
8585
throws IOException, InterruptedException {
8686
GitLabSCMSource gitlabScmSource = (GitLabSCMSource) source;
87-
GitLabApi gitLabApi = apiBuilder(source.getOwner(), gitlabScmSource.getServerName());
87+
GitLabApi gitLabApi =
88+
apiBuilder(source.getOwner(), gitlabScmSource.getServerName(), gitlabScmSource.getCredentialsId());
8889
String projectPath = gitlabScmSource.getProjectPath();
8990
return build(head, rev, gitLabApi, projectPath);
9091
}

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMNavigator.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import com.cloudbees.plugins.credentials.CredentialsProvider;
1515
import com.cloudbees.plugins.credentials.common.StandardCredentials;
1616
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
17-
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
1817
import edu.umd.cs.findbugs.annotations.CheckForNull;
1918
import edu.umd.cs.findbugs.annotations.NonNull;
2019
import hudson.Extension;
@@ -198,7 +197,7 @@ public void setTraits(@CheckForNull SCMTrait[] traits) {
198197

199198
private GitLabOwner getGitlabOwner(SCMNavigatorOwner owner) {
200199
if (gitlabOwner == null) {
201-
getGitlabOwner(apiBuilder(owner, serverName));
200+
getGitlabOwner(apiBuilder(owner, serverName, credentialsId));
202201
}
203202
return gitlabOwner;
204203
}
@@ -235,7 +234,7 @@ protected String id() {
235234
public void visitSources(@NonNull final SCMSourceObserver observer) throws IOException, InterruptedException {
236235
GitLabSCMNavigatorContext context = new GitLabSCMNavigatorContext().withTraits(traits);
237236
try (GitLabSCMNavigatorRequest request = context.newRequest(this, observer)) {
238-
GitLabApi gitLabApi = apiBuilder(observer.getContext(), serverName);
237+
GitLabApi gitLabApi = apiBuilder(observer.getContext(), serverName, credentialsId);
239238
getGitlabOwner(gitLabApi);
240239
List<Project> projects;
241240
if (gitlabOwner instanceof GitLabUser) {
@@ -460,14 +459,15 @@ public static class DescriptorImpl extends SCMNavigatorDescriptor implements Ico
460459

461460
public static FormValidation doCheckProjectOwner(
462461
@AncestorInPath SCMSourceOwner context,
462+
@QueryParameter String credentialsId,
463463
@QueryParameter String projectOwner,
464464
@QueryParameter String serverName) {
465465
if (projectOwner.equals("")) {
466466
return FormValidation.ok();
467467
}
468468
GitLabApi gitLabApi = null;
469469
try {
470-
gitLabApi = apiBuilder(context, serverName);
470+
gitLabApi = apiBuilder(context, serverName, credentialsId);
471471
GitLabOwner gitLabOwner = GitLabOwner.fetchOwner(gitLabApi, projectOwner);
472472
return FormValidation.ok(projectOwner + " is a valid " + gitLabOwner.getWord());
473473
} catch (IllegalStateException e) {
@@ -553,9 +553,9 @@ public ListBoxModel doFillCredentialsIdItems(
553553
result.includeMatchingAs(
554554
context instanceof Queue.Task ? ((Queue.Task) context).getDefaultAuthentication() : ACL.SYSTEM,
555555
context,
556-
StandardUsernameCredentials.class,
556+
StandardCredentials.class,
557557
fromUri(getServerUrlFromName(serverName)).build(),
558-
GitClient.CREDENTIALS_MATCHER);
558+
CredentialsMatchers.anyOf(GitClient.CREDENTIALS_MATCHER, GitLabServer.CREDENTIALS_MATCHER));
559559
return result;
560560
}
561561

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMSource.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import com.cloudbees.plugins.credentials.CredentialsMatchers;
1515
import com.cloudbees.plugins.credentials.CredentialsProvider;
16+
import com.cloudbees.plugins.credentials.common.StandardCredentials;
1617
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
1718
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
1819
import edu.umd.cs.findbugs.annotations.NonNull;
@@ -31,6 +32,7 @@
3132
import hudson.util.ListBoxModel;
3233
import io.jenkins.plugins.gitlabbranchsource.helpers.GitLabAvatar;
3334
import io.jenkins.plugins.gitlabbranchsource.helpers.GitLabLink;
35+
import io.jenkins.plugins.gitlabserverconfig.credentials.GroupAccessToken;
3436
import io.jenkins.plugins.gitlabserverconfig.credentials.PersonalAccessToken;
3537
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServer;
3638
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServers;
@@ -203,7 +205,7 @@ public String getRemote() {
203205

204206
protected Project getGitlabProject() {
205207
if (gitlabProject == null) {
206-
getGitlabProject(apiBuilder(this.getOwner(), serverName));
208+
getGitlabProject(apiBuilder(this.getOwner(), serverName, credentialsId));
207209
}
208210
return gitlabProject;
209211
}
@@ -226,7 +228,7 @@ protected Project getGitlabProject(GitLabApi gitLabApi) {
226228
public HashMap<String, AccessLevel> getMembers() {
227229
HashMap<String, AccessLevel> members = new HashMap<>();
228230
try {
229-
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
231+
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName, credentialsId);
230232
for (Member m : gitLabApi.getProjectApi().getAllMembers(projectPath)) {
231233
members.put(m.getUsername(), m.getAccessLevel());
232234
}
@@ -261,7 +263,7 @@ public void setTraits(List<SCMSourceTrait> traits) {
261263
protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener listener)
262264
throws IOException, InterruptedException {
263265
try {
264-
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
266+
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName, credentialsId);
265267
getGitlabProject(gitLabApi);
266268
if (head instanceof BranchSCMHead) {
267269
listener.getLogger().format("Querying the current revision of branch %s...%n", head.getName());
@@ -323,7 +325,7 @@ protected void retrieve(
323325
@NonNull TaskListener listener)
324326
throws IOException, InterruptedException {
325327
try {
326-
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
328+
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName, credentialsId);
327329
getGitlabProject(gitLabApi);
328330
GitLabSCMSourceContext ctx = new GitLabSCMSourceContext(criteria, observer).withTraits(getTraits());
329331
try (GitLabSCMSourceRequest request = ctx.newRequest(this, listener)) {
@@ -728,7 +730,7 @@ protected SCMProbe createProbe(@NonNull final SCMHead head, SCMRevision revision
728730
if (builder == null) {
729731
throw new AssertionError();
730732
}
731-
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
733+
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName, credentialsId);
732734
getGitlabProject(gitLabApi);
733735
final SCMFileSystem fs = builder.build(head, revision, gitLabApi, projectPath);
734736
return new SCMProbe() {
@@ -786,14 +788,19 @@ public void afterSave() {
786788
}
787789
}
788790

789-
public PersonalAccessToken credentials() {
790-
return CredentialsMatchers.firstOrNull(
791-
lookupCredentials(
792-
PersonalAccessToken.class,
793-
getOwner(),
794-
Jenkins.getAuthentication(),
795-
fromUri(getServerUrlFromName(serverName)).build()),
796-
GitLabServer.CREDENTIALS_MATCHER);
791+
public StandardCredentials credentials() {
792+
List<StandardCredentials> list = new ArrayList<>();
793+
list.addAll(lookupCredentials(
794+
PersonalAccessToken.class,
795+
getOwner(),
796+
Jenkins.getAuthentication(),
797+
fromUri(getServerUrlFromName(serverName)).build()));
798+
list.addAll(lookupCredentials(
799+
GroupAccessToken.class,
800+
getOwner(),
801+
Jenkins.getAuthentication(),
802+
fromUri(getServerUrlFromName(serverName)).build()));
803+
return CredentialsMatchers.firstOrNull(list, GitLabServer.CREDENTIALS_MATCHER);
797804
}
798805

799806
@Symbol("gitlab")
@@ -865,13 +872,14 @@ public ListBoxModel doFillCredentialsIdItems(
865872
context,
866873
StandardUsernameCredentials.class,
867874
fromUri(getServerUrlFromName(serverName)).build(),
868-
GitClient.CREDENTIALS_MATCHER);
875+
CredentialsMatchers.anyOf(GitClient.CREDENTIALS_MATCHER, GitLabServer.CREDENTIALS_MATCHER));
869876
return result;
870877
}
871878

872879
public long getProjectId(
873880
@AncestorInPath SCMSourceOwner context,
874881
@QueryParameter String projectPath,
882+
@QueryParameter String credentialsId,
875883
@QueryParameter String serverName) {
876884
List<GitLabServer> gitLabServers = GitLabServers.get().getServers();
877885
if (gitLabServers.size() == 0) {
@@ -880,9 +888,9 @@ public long getProjectId(
880888
try {
881889
GitLabApi gitLabApi;
882890
if (StringUtils.isBlank(serverName)) {
883-
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName());
891+
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName(), credentialsId);
884892
} else {
885-
gitLabApi = apiBuilder(context, serverName);
893+
gitLabApi = apiBuilder(context, serverName, credentialsId);
886894
}
887895
if (StringUtils.isNotBlank(projectPath)) {
888896
return gitLabApi.getProjectApi().getProject(projectPath).getId();
@@ -895,6 +903,7 @@ public long getProjectId(
895903

896904
public ListBoxModel doFillProjectPathItems(
897905
@AncestorInPath SCMSourceOwner context,
906+
@QueryParameter String credentialsId,
898907
@QueryParameter String serverName,
899908
@QueryParameter String projectOwner) {
900909
List<GitLabServer> gitLabServers = GitLabServers.get().getServers();
@@ -905,9 +914,9 @@ public ListBoxModel doFillProjectPathItems(
905914
try {
906915
GitLabApi gitLabApi;
907916
if (serverName.equals("")) {
908-
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName());
917+
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName(), credentialsId);
909918
} else {
910-
gitLabApi = apiBuilder(context, serverName);
919+
gitLabApi = apiBuilder(context, serverName, credentialsId);
911920
}
912921

913922
if (projectOwner.equals("")) {

src/main/java/io/jenkins/plugins/gitlabbranchsource/helpers/GitLabHelper.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
package io.jenkins.plugins.gitlabbranchsource.helpers;
22

3+
import static com.cloudbees.plugins.credentials.CredentialsMatchers.withId;
4+
import static com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials;
5+
import static com.cloudbees.plugins.credentials.domains.URIRequirementBuilder.fromUri;
6+
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
7+
8+
import com.cloudbees.plugins.credentials.CredentialsMatchers;
39
import com.cloudbees.plugins.credentials.common.StandardCredentials;
410
import com.damnhandy.uri.template.UriTemplate;
511
import com.damnhandy.uri.template.UriTemplateBuilder;
612
import com.damnhandy.uri.template.impl.Operator;
713
import hudson.ProxyConfiguration;
14+
import hudson.model.Item;
15+
import hudson.model.ItemGroup;
16+
import hudson.security.ACL;
817
import hudson.security.AccessControlled;
18+
import io.jenkins.plugins.gitlabserverconfig.credentials.GroupAccessToken;
919
import io.jenkins.plugins.gitlabserverconfig.credentials.PersonalAccessToken;
1020
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServer;
1121
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServers;
@@ -15,17 +25,22 @@
1525
import java.util.Map;
1626
import java.util.regex.Pattern;
1727
import jenkins.model.Jenkins;
28+
import org.apache.commons.lang.StringUtils;
1829
import org.eclipse.jgit.annotations.NonNull;
1930
import org.gitlab4j.api.GitLabApi;
2031
import org.gitlab4j.api.ProxyClientConfig;
2132
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
2233

2334
public class GitLabHelper {
2435

25-
public static GitLabApi apiBuilder(AccessControlled context, String serverName) {
36+
public static GitLabApi apiBuilder(AccessControlled context, String serverName, String credentialsId) {
37+
return apiBuilder(context, serverName, getCredential(credentialsId, serverName, context));
38+
}
39+
40+
public static GitLabApi apiBuilder(AccessControlled context, String serverName, StandardCredentials credential) {
2641
GitLabServer server = GitLabServers.get().findServer(serverName);
2742
if (server != null) {
28-
StandardCredentials credentials = server.getCredentials(context);
43+
StandardCredentials credentials = credential != null ? credential : server.getCredentials(context);
2944
String serverUrl = server.getServerUrl();
3045
String privateToken = getPrivateTokenAsPlainText(credentials);
3146
if (privateToken.equals(GitLabServer.EMPTY_TOKEN)) {
@@ -106,6 +121,9 @@ public static String getPrivateTokenAsPlainText(StandardCredentials credentials)
106121
if (credentials instanceof PersonalAccessToken) {
107122
privateToken = ((PersonalAccessToken) credentials).getToken().getPlainText();
108123
}
124+
if (credentials instanceof GroupAccessToken) {
125+
privateToken = ((GroupAccessToken) credentials).getToken().getPlainText();
126+
}
109127
if (credentials instanceof StringCredentials) {
110128
privateToken = ((StringCredentials) credentials).getSecret().getPlainText();
111129
}
@@ -148,4 +166,32 @@ public static UriTemplate commitUriTemplate(String serverNameOrUrl) {
148166
public static String[] splitPath(String path) {
149167
return path.split(Operator.PATH.getSeparator());
150168
}
169+
170+
public static StandardCredentials getCredential(String credentialsId, String serverName, AccessControlled context) {
171+
if (StringUtils.isNotBlank(credentialsId)) {
172+
if (context instanceof ItemGroup) {
173+
return CredentialsMatchers.firstOrNull(
174+
lookupCredentials(
175+
StandardCredentials.class,
176+
(ItemGroup) context,
177+
ACL.SYSTEM,
178+
fromUri(defaultIfBlank(
179+
getServerUrlFromName(serverName), GitLabServer.GITLAB_SERVER_URL))
180+
.build()),
181+
withId(credentialsId));
182+
} else {
183+
return CredentialsMatchers.firstOrNull(
184+
lookupCredentials(
185+
StandardCredentials.class,
186+
(Item) context,
187+
ACL.SYSTEM,
188+
fromUri(defaultIfBlank(
189+
getServerUrlFromName(serverName), GitLabServer.GITLAB_SERVER_URL))
190+
.build()),
191+
withId(credentialsId));
192+
}
193+
}
194+
195+
return null;
196+
}
151197
}

src/main/java/io/jenkins/plugins/gitlabbranchsource/helpers/GitLabPipelineStatusNotifier.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ private static void logComment(Run<?, ?> build, TaskListener listener) {
207207
String suffix = " - [Details](" + url + ")";
208208
SCMRevision revision = SCMRevisionAction.getRevision(source, build);
209209
try {
210-
GitLabApi gitLabApi = GitLabHelper.apiBuilder(build.getParent(), source.getServerName());
210+
GitLabApi gitLabApi =
211+
GitLabHelper.apiBuilder(build.getParent(), source.getServerName(), source.getCredentialsId());
211212
String sudoUsername = sourceContext.getSudoUser();
212213
if (!sudoUsername.isEmpty()) {
213214
gitLabApi.sudo(sudoUsername);
@@ -373,7 +374,8 @@ private static void sendNotifications(Run<?, ?> build, TaskListener listener, Bo
373374
}
374375
}
375376
try {
376-
GitLabApi gitLabApi = GitLabHelper.apiBuilder(build.getParent(), source.getServerName());
377+
GitLabApi gitLabApi =
378+
GitLabHelper.apiBuilder(build.getParent(), source.getServerName(), source.getCredentialsId());
377379
LOGGER.log(Level.FINE, String.format("Notifiying commit: %s", hash));
378380

379381
if (revision instanceof MergeRequestSCMRevision) {
@@ -474,7 +476,8 @@ public void onEnterWaiting(final Queue.WaitingItem wi) {
474476

475477
Constants.CommitBuildState state = Constants.CommitBuildState.PENDING;
476478
try {
477-
GitLabApi gitLabApi = GitLabHelper.apiBuilder(job, source.getServerName());
479+
GitLabApi gitLabApi =
480+
GitLabHelper.apiBuilder(job, source.getServerName(), source.getCredentialsId());
478481
// check are we still the task to set pending
479482
synchronized (resolving) {
480483
if (!nonce.equals(resolving.get(job))) {

src/main/java/io/jenkins/plugins/gitlabserverconfig/action/GitlabAction.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ public HttpResponse doServerList() {
5151

5252
@RequirePOST
5353
public HttpResponse doProjectList(
54-
@AncestorInPath SCMSourceOwner context, @QueryParameter String server, @QueryParameter String owner) {
54+
@AncestorInPath SCMSourceOwner context,
55+
@QueryParameter String server,
56+
@QueryParameter String credentialsId,
57+
@QueryParameter String owner) {
5558
if (!Jenkins.get().hasPermission(Jenkins.MANAGE)) {
5659
return HttpResponses.errorJSON("no permission to get Gitlab server list");
5760
}
@@ -62,7 +65,7 @@ public HttpResponse doProjectList(
6265

6366
JSONArray servers = new JSONArray();
6467

65-
GitLabApi gitLabApi = GitLabHelper.apiBuilder(context, server);
68+
GitLabApi gitLabApi = GitLabHelper.apiBuilder(context, server, credentialsId);
6669
try {
6770
for (Project project :
6871
gitLabApi.getProjectApi().getUserProjects(owner, new ProjectFilter().withOwned(true))) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.jenkins.plugins.gitlabserverconfig.credentials;
2+
3+
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
4+
import edu.umd.cs.findbugs.annotations.NonNull;
5+
import hudson.util.Secret;
6+
7+
public interface GroupAccessToken extends StandardUsernamePasswordCredentials {
8+
9+
/**
10+
* Returns the token.
11+
*
12+
* @return the token.
13+
*/
14+
@NonNull
15+
Secret getToken();
16+
}

0 commit comments

Comments
 (0)