Skip to content

Commit

Permalink
Allow users without global Job/Build permission configure multibranch…
Browse files Browse the repository at this point in the history
… jobs (#156)

Co-authored-by: Joseph Petersen <[email protected]>
  • Loading branch information
mymarche and jetersen authored Apr 23, 2022
1 parent 3013db8 commit 85cf3a4
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ target
.settings
bin
.DS_Store
.vscode/
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void register(SCMNavigatorOwner owner, GitLabSCMNavigator navigato
if (!server.isManageSystemHooks()) {
return;
}
credentials = server.getCredentials();
credentials = server.getCredentials(owner);
if (credentials == null) {
LOGGER.log(Level.WARNING, "No System credentials added, cannot create system hook");
}
Expand Down Expand Up @@ -71,7 +71,7 @@ public static void register(GitLabSCMSource source,
if (!server.isManageWebHooks()) {
break;
}
credentials = server.getCredentials();
credentials = server.getCredentials(source.getOwner());
if (credentials == null) {
LOGGER.log(Level.WARNING, "No System credentials added, cannot create web hook");
}
Expand Down Expand Up @@ -108,7 +108,7 @@ public static void register(GitLabSCMSource source,
if (!server.isManageSystemHooks()) {
return;
}
credentials = server.getCredentials();
credentials = server.getCredentials(source.getOwner());
if (credentials == null) {
LOGGER.log(Level.WARNING, "No System credentials added, cannot create system hook");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head,
@CheckForNull SCMRevision rev)
throws IOException, InterruptedException {
GitLabSCMSource gitlabScmSource = (GitLabSCMSource) source;
GitLabApi gitLabApi = apiBuilder(gitlabScmSource.getServerName());
GitLabApi gitLabApi = apiBuilder(source.getOwner(), gitlabScmSource.getServerName());
String projectPath = gitlabScmSource.getProjectPath();
return build(head, rev, gitLabApi, projectPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ public void setTraits(@CheckForNull SCMTrait[] traits) {
}
}

private GitLabOwner getGitlabOwner() {
private GitLabOwner getGitlabOwner(SCMNavigatorOwner owner) {
if (gitlabOwner == null) {
getGitlabOwner(apiBuilder(serverName));
getGitlabOwner(apiBuilder(owner, serverName));
}
return gitlabOwner;
}
Expand Down Expand Up @@ -229,7 +229,7 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
GitLabSCMNavigatorContext context = new GitLabSCMNavigatorContext()
.withTraits(traits);
try (GitLabSCMNavigatorRequest request = context.newRequest(this, observer)) {
GitLabApi gitLabApi = apiBuilder(serverName);
GitLabApi gitLabApi = apiBuilder(observer.getContext(), serverName);
getGitlabOwner(gitLabApi);
List<Project> projects;
if (gitlabOwner instanceof GitLabUser) {
Expand Down Expand Up @@ -260,7 +260,7 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
count++;
String projectPathWithNamespace = p.getPathWithNamespace();
String projectOwner = getProjectOwnerFromNamespace(projectPathWithNamespace);
String projectName = getProjectName(request.withProjectNamingStrategy(), p);
String projectName = getProjectName(gitLabApi, request.withProjectNamingStrategy(), p);
getNavigatorProjects().add(projectPathWithNamespace);
if (StringUtils.isEmpty(p.getDefaultBranch())) {
observer.getListener().getLogger()
Expand Down Expand Up @@ -319,7 +319,7 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
}

@NonNull
private String getProjectName(int projectNamingStrategy, Project project) throws URISyntaxException {
private String getProjectName(GitLabApi gitLabApi, int projectNamingStrategy, Project project) throws URISyntaxException {
String fullPath = project.getPathWithNamespace();
String projectName;
switch (projectNamingStrategy) {
Expand All @@ -331,7 +331,7 @@ private String getProjectName(int projectNamingStrategy, Project project) throws
case 2:
// Project name
projectName = project.getNameWithNamespace()
.replace(String.format("%s / ", getGitlabOwner().getFullName()), "");
.replace(String.format("%s / ", getGitlabOwner(gitLabApi).getFullName()), "");
break;
case 3:
// Contextual project path
Expand Down Expand Up @@ -365,7 +365,7 @@ private PersonalAccessToken getWebHookCredentials(SCMSourceOwner owner) {
if (!server.isManageWebHooks()) {
break;
}
credentials = server.getCredentials();
credentials = server.getCredentials(owner);
if (credentials == null) {
LOGGER.log(Level.WARNING, "No System credentials added, cannot create web hook");
}
Expand All @@ -387,7 +387,7 @@ private PersonalAccessToken getWebHookCredentials(SCMSourceOwner owner) {
protected List<Action> retrieveActions(@NonNull SCMNavigatorOwner owner,
SCMNavigatorEvent event,
@NonNull TaskListener listener) throws IOException, InterruptedException {
getGitlabOwner();
getGitlabOwner(owner);
String fullName = gitlabOwner.getFullName();
String webUrl = gitlabOwner.getWebUrl();
String avatarUrl = gitlabOwner.getAvatarUrl();
Expand Down Expand Up @@ -443,14 +443,15 @@ public static class DescriptorImpl extends SCMNavigatorDescriptor implements Ico
@Inject
private GitLabSCMSource.DescriptorImpl delegate;

public static FormValidation doCheckProjectOwner(@QueryParameter String projectOwner,
public static FormValidation doCheckProjectOwner(@AncestorInPath SCMSourceOwner context,
@QueryParameter String projectOwner,
@QueryParameter String serverName) {
if (projectOwner.equals("")) {
return FormValidation.ok();
}
GitLabApi gitLabApi = null;
try {
gitLabApi = apiBuilder(serverName);
gitLabApi = apiBuilder(context, serverName);
GitLabOwner gitLabOwner = GitLabOwner.fetchOwner(gitLabApi, projectOwner);
return FormValidation.ok(projectOwner + " is a valid " + gitLabOwner.getWord());
} catch (IllegalStateException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public String getRemote() {

protected Project getGitlabProject() {
if (gitlabProject == null) {
getGitlabProject(apiBuilder(serverName));
getGitlabProject(apiBuilder(this.getOwner(), serverName));
}
return gitlabProject;
}
Expand All @@ -216,7 +216,7 @@ protected Project getGitlabProject(GitLabApi gitLabApi) {
public HashMap<String, AccessLevel> getMembers() {
HashMap<String, AccessLevel> members = new HashMap<>();
try {
GitLabApi gitLabApi = apiBuilder(serverName);
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
for (Member m : gitLabApi.getProjectApi().getAllMembers(projectPath)) {
members.put(m.getUsername(), m.getAccessLevel());
}
Expand Down Expand Up @@ -251,7 +251,7 @@ public void setTraits(List<SCMSourceTrait> traits) {
protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener listener)
throws IOException, InterruptedException {
try {
GitLabApi gitLabApi = apiBuilder(serverName);
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
getGitlabProject(gitLabApi);
if (head instanceof BranchSCMHead) {
listener.getLogger().format("Querying the current revision of branch %s...%n", head.getName());
Expand Down Expand Up @@ -304,7 +304,7 @@ protected void retrieve(SCMSourceCriteria criteria, @NonNull SCMHeadObserver obs
SCMHeadEvent<?> event,
@NonNull TaskListener listener) throws IOException, InterruptedException {
try {
GitLabApi gitLabApi = apiBuilder(serverName);
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
getGitlabProject(gitLabApi);
setProjectId(gitlabProject.getId());
sshRemote = gitlabProject.getSshUrlToRepo();
Expand Down Expand Up @@ -675,7 +675,7 @@ protected SCMProbe createProbe(@NonNull final SCMHead head, SCMRevision revision
if (builder == null) {
throw new AssertionError();
}
GitLabApi gitLabApi = apiBuilder(serverName);
GitLabApi gitLabApi = apiBuilder(this.getOwner(), serverName);
getGitlabProject(gitLabApi);
final SCMFileSystem fs = builder.build(head, revision, gitLabApi, projectPath);
return new SCMProbe() {
Expand Down Expand Up @@ -807,17 +807,17 @@ context, StandardUsernameCredentials.class, fromUri(getServerUrlFromName(serverN
return result;
}

public long getProjectId(@QueryParameter String projectPath, @QueryParameter String serverName) {
public long getProjectId(@AncestorInPath SCMSourceOwner context, @QueryParameter String projectPath, @QueryParameter String serverName) {
List<GitLabServer> gitLabServers = GitLabServers.get().getServers();
if (gitLabServers.size() == 0) {
return -1;
}
try {
GitLabApi gitLabApi;
if (StringUtils.isBlank(serverName)) {
gitLabApi = apiBuilder(gitLabServers.get(0).getName());
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName());
} else {
gitLabApi = apiBuilder(serverName);
gitLabApi = apiBuilder(context, serverName);
}
if (StringUtils.isNotBlank(projectPath)) {
return gitLabApi.getProjectApi().getProject(projectPath).getId();
Expand All @@ -838,9 +838,9 @@ public ListBoxModel doFillProjectPathItems(@AncestorInPath SCMSourceOwner contex
try {
GitLabApi gitLabApi;
if (serverName.equals("")) {
gitLabApi = apiBuilder(gitLabServers.get(0).getName());
gitLabApi = apiBuilder(context, gitLabServers.get(0).getName());
} else {
gitLabApi = apiBuilder(serverName);
gitLabApi = apiBuilder(context, serverName);
}

if (projectOwner.equals("")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.damnhandy.uri.template.UriTemplateBuilder;
import com.damnhandy.uri.template.impl.Operator;
import hudson.ProxyConfiguration;
import hudson.security.AccessControlled;
import io.jenkins.plugins.gitlabserverconfig.credentials.PersonalAccessToken;
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServer;
import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServers;
Expand All @@ -19,10 +20,10 @@

public class GitLabHelper {

public static GitLabApi apiBuilder(String serverName) {
public static GitLabApi apiBuilder(AccessControlled context, String serverName) {
GitLabServer server = GitLabServers.get().findServer(serverName);
if (server != null) {
PersonalAccessToken credentials = server.getCredentials();
PersonalAccessToken credentials = server.getCredentials(context);
String serverUrl = server.getServerUrl();
if (credentials != null) {
return new GitLabApi(serverUrl, credentials.getToken().getPlainText(), null, getProxyConfig(serverUrl));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private static void logComment(Run<?, ?> build, TaskListener listener) {
String suffix = " - [Details](" + url + ")";
SCMRevision revision = SCMRevisionAction.getRevision(source, build);
try {
GitLabApi gitLabApi = GitLabHelper.apiBuilder(source.getServerName());
GitLabApi gitLabApi = GitLabHelper.apiBuilder(build.getParent(), source.getServerName());
String sudoUsername = sourceContext.getSudoUser();
if (!sudoUsername.isEmpty()) {
gitLabApi.sudo(sudoUsername);
Expand Down Expand Up @@ -319,7 +319,7 @@ private static void sendNotifications(Run<?, ?> build, TaskListener listener) {
}
}
try {
GitLabApi gitLabApi = GitLabHelper.apiBuilder(source.getServerName());
GitLabApi gitLabApi = GitLabHelper.apiBuilder(build.getParent(), source.getServerName());
LOGGER.log(Level.FINE, String.format("Notifiying commit: %s", hash));

if (revision instanceof MergeRequestSCMRevision) {
Expand Down Expand Up @@ -419,7 +419,7 @@ public void onEnterWaiting(final Queue.WaitingItem wi) {

Constants.CommitBuildState state = Constants.CommitBuildState.PENDING;
try {
GitLabApi gitLabApi = GitLabHelper.apiBuilder(source.getServerName());
GitLabApi gitLabApi = GitLabHelper.apiBuilder(job, source.getServerName());
// check are we still the task to set pending
synchronized (resolving) {
if (!nonce.equals(resolving.get(job))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import jenkins.scm.api.SCMSourceOwner;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
Expand All @@ -18,6 +19,7 @@
import org.gitlab4j.api.models.ProjectFilter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.interceptor.RequirePOST;
Expand Down Expand Up @@ -48,7 +50,8 @@ public HttpResponse doServerList() {
}

@RequirePOST
public HttpResponse doProjectList(@QueryParameter String server,
public HttpResponse doProjectList(@AncestorInPath SCMSourceOwner context,
@QueryParameter String server,
@QueryParameter String owner) {
if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) {
return HttpResponses.errorJSON("no permission to get Gitlab server list");
Expand All @@ -60,7 +63,7 @@ public HttpResponse doProjectList(@QueryParameter String server,

JSONArray servers = new JSONArray();

GitLabApi gitLabApi = GitLabHelper.apiBuilder(server);
GitLabApi gitLabApi = GitLabHelper.apiBuilder(context, server);
try {
for (Project project : gitLabApi.getProjectApi().getUserProjects(owner,
new ProjectFilter().withOwned(true))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
import hudson.Util;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.security.ACL;
import hudson.security.AccessControlled;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.Secret;
Expand Down Expand Up @@ -230,16 +233,34 @@ public String getCredentialsId() {
*
* @return {@link PersonalAccessToken}
*/
public PersonalAccessToken getCredentials() {
public PersonalAccessToken getCredentials(AccessControlled context) {
Jenkins jenkins = Jenkins.get();
jenkins.checkPermission(CredentialsProvider.USE_OWN);
return StringUtils.isBlank(credentialsId) ? null : CredentialsMatchers.firstOrNull(
lookupCredentials(
PersonalAccessToken.class,
jenkins,
ACL.SYSTEM,
fromUri(defaultIfBlank(serverUrl, GITLAB_SERVER_URL)).build()
), withId(credentialsId));
if (context == null) {
jenkins.checkPermission(CredentialsProvider.USE_OWN);
return StringUtils.isBlank(credentialsId) ? null : CredentialsMatchers.firstOrNull( lookupCredentials(
PersonalAccessToken.class,
jenkins,
ACL.SYSTEM,
fromUri(defaultIfBlank(serverUrl, GITLAB_SERVER_URL)).build()
), withId(credentialsId));
} else {
context.checkPermission(CredentialsProvider.USE_OWN);
if (context instanceof ItemGroup) {
return StringUtils.isBlank(credentialsId) ? null : CredentialsMatchers.firstOrNull( lookupCredentials(
PersonalAccessToken.class,
(ItemGroup) context,
ACL.SYSTEM,
fromUri(defaultIfBlank(serverUrl, GITLAB_SERVER_URL)).build()
), withId(credentialsId));
} else {
return StringUtils.isBlank(credentialsId) ? null : CredentialsMatchers.firstOrNull( lookupCredentials(
PersonalAccessToken.class,
(Item) context,
ACL.SYSTEM,
fromUri(defaultIfBlank(serverUrl, GITLAB_SERVER_URL)).build()
), withId(credentialsId));
}
}
}

/**
Expand Down

0 comments on commit 85cf3a4

Please sign in to comment.