Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new API GET methods #69

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion docs/rest-api.adoc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
= REST API methods
:toc:

The plugin provides REST APIs for modifying the roles. All of these methods
The plugin provides REST APIs for modifying and getting information on the roles. All of these methods
require the user invoking them to have the `Jenkins.ADMINISTER` permission.

== API methods for adding a role
Expand Down Expand Up @@ -178,6 +178,86 @@ Deletes an agent role identified by its name. Requires POST to
curl -X POST -d 'roleName=foo' http://localhost:8080/folder-auth/deleteAgentRole
----

== API Methods for getting information regarding a role

=== `getAgentRole`
Gets information of an agent role. Requires the parameter `name`.
[source,bash]
----
curl -X GET https://localhost:8080/folder-auth/getAgentRole?name=matrix
----
returns
[source, json]
----
{
"name": "matrix",
"sids": [
"alice",
"bob"
],
"agents": [
"smith",
"jackson",
"johnson",
"thompson"
],
"permissions": [
"hudson.model.Computer.Configure",
"hudson.model.Computer.Create"
]
}

----

=== `getFolderRole`
Gets information of a folder role. Requires the parameter `name`.
[source,bash]
----
curl -X GET https://localhost:8080/folder-auth/getFolderRole?name=folderReadOnly
----
returns
[source, json]
----
{
"name": "folderReadOnly",
"sids": [
"alice",
"bob"
],
"folders": [
"folder1",
"folder2"
],
"permissions": [
"hudson.model.Item.Discover",
"hudson.model.Item.Read"
]
}
----

=== `getGlobalRole`
Gets information of a global role. Requires the parameter `name`.
[source,bash]
----
curl -X GET https://localhost:8080/folder-auth/getFolderRole?name=admin
----
returns
[source, bash]
----
{
"name": "admin",
"sids": [
"bob"
],
"permissions": [
"hudson.model.Hudson.Administer",
"hudson.model.Item.Read",
"hudson.model.View.Configure",
"hudson.model.View.Delete",
"hudson.model.Computer.Delete"
]
}
----
== Logging in to Jenkins

When using cURL to invoke the API, you need to login as a user with the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package io.jenkins.plugins.folderauth;

import hudson.security.AuthorizationStrategy;
import io.jenkins.plugins.folderauth.roles.AbstractRole;
import io.jenkins.plugins.folderauth.roles.AgentRole;
import io.jenkins.plugins.folderauth.roles.FolderRole;
import io.jenkins.plugins.folderauth.roles.GlobalRole;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collector;

/**
* Public-facing methods for modifying {@link FolderBasedAuthorizationStrategy}.
Expand Down Expand Up @@ -302,4 +305,69 @@ public static void removeSidFromAgentRole(String sid, String roleName) {
return new FolderBasedAuthorizationStrategy(strategy.getGlobalRoles(), strategy.getFolderRoles(), agentRoles);
});
}

/**
* Gets an {@link AgentRole}
* @param name Name of the agent role
* @return The {@link AgentRole} object
*/
@Nullable
public static AgentRole getAgentRole(String name) {
return (AgentRole) getRole(name, "agentRole");
}

/**
* Gets an {@link FolderRole} and all its associated information
* @param name Name of the global role
* @return The {@link FolderRole} object
*/
@Nullable
public static FolderRole getFolderRole(String name) {
return (FolderRole) getRole(name, "folderRole");
}

/**
* Gets an {@link GlobalRole} and all its associated information
* @param name Name of the global role
* @return The {@link GlobalRole} object
*/
@Nullable
public static GlobalRole getGlobalRole(String name) {
return (GlobalRole) getRole(name, "globalRole");
}

/**
* Gets a role
* @param name Name of the role
* @param roleType Type of the role - one of agentRole, folderRole or globalRole
* @return The role object
*/
public static AbstractRole getRole(String name, String roleType) {
Jenkins jenkins = Jenkins.get();
FolderBasedAuthorizationStrategy strategy;
try {
strategy = (FolderBasedAuthorizationStrategy) jenkins.getAuthorizationStrategy();
} catch (ClassCastException error) {
throw new IllegalStateException(Messages.FolderBasedAuthorizationStrategy_NotCurrentStrategy());
}
Set<? extends AbstractRole> roles;
switch (roleType) {
case "agentRole":
roles = new HashSet<>(strategy.getAgentRoles());
break;
case "folderRole":
roles = new HashSet<>(strategy.getFolderRoles());
break;
case "globalRole":
roles = new HashSet<>(strategy.getGlobalRoles());
break;
default:
throw new IllegalArgumentException("Expected agentRole, folderRole or globalRole but received: "
+ roleType);
}
Optional<? extends AbstractRole> found = roles.stream().filter(r -> r.getName().equals(name)).findAny();
return found.orElse(null);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import io.jenkins.plugins.folderauth.misc.FolderRoleCreationRequest;
import io.jenkins.plugins.folderauth.misc.GlobalRoleCreationRequest;
import io.jenkins.plugins.folderauth.misc.PermissionWrapper;
import io.jenkins.plugins.folderauth.roles.AbstractRole;
import io.jenkins.plugins.folderauth.roles.AgentRole;
import io.jenkins.plugins.folderauth.roles.FolderRole;
import io.jenkins.plugins.folderauth.roles.GlobalRole;
import jenkins.model.Jenkins;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.QueryParameter;
Expand All @@ -39,6 +41,7 @@
import javax.annotation.ParametersAreNonnullByDefault;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -443,4 +446,132 @@ public void doRemoveSidFromAgentRole(@QueryParameter(required = true) String rol
FolderAuthorizationStrategyAPI.removeSidFromAgentRole(sid, roleName);
redirect();
}

/**
* API Method to get an {@link AgentRole}
* Example: {@code curl -X GET 'http://localhost:8080/jenkins/folder-auth/getAgentRole?name=agentSmithRole}
*
* @param name name of the role (single, no list)
* @return Json object containing info on the role
*/
@GET
@Restricted(NoExternalUse.class)
public JSONObject doGetAgentRole(@QueryParameter(required = true) String name) {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
AgentRole role = FolderAuthorizationStrategyAPI.getAgentRole(name);
if (role != null) {
JSONObject responseJson = new JSONObject();
responseJson.put("name", role.getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to let json-lib handle converting the AbstractRole objects to JSONObjects using JSONObject#fromObject?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use JSONObject#fromObject, the role class must be of type string (json formatted), map, etc. The current class doesn't so it'll require a refactor for the class to extend either of these classes it to work. I'll keep it as is? Or we can

responseJson.put("agents", role.getAgents());
responseJson.put("sids", role.getSids());
responseJson.put("permissions", getPermissionsFromRole(role));
return responseJson;
} else {
return null;
}
}

/**
* API Method to get a {@link FolderRole}
* Example: {@code curl -X GET 'http://localhost:8080/jenkins/folder-auth/getFolderRole?name=folderRole1'}
*
* @param name name of the role (single, no list)
* @return Json object containing info on the role
*/
@GET
@Restricted(NoExternalUse.class)
public JSONObject doGetFolderRole(@QueryParameter(required = true) String name) {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
FolderRole role = FolderAuthorizationStrategyAPI.getFolderRole(name);
if (role != null) {
JSONObject responseJson = new JSONObject();
responseJson.put("name", role.getName());
responseJson.put("folders", role.getFolderNames());
responseJson.put("sids", role.getSids());
responseJson.put("permissions", getPermissionsFromRole(role));
return responseJson;
} else {
return null;
}
}

/**
* API Method to get a {@link GlobalRole}
* Example: {@code curl -X GET 'http://localhost:8080/jenkins/folder-auth/getGlobalRole?name=admin'}
*
* @param name name of the role (single, no list)
* @return Json object containing info on the role
*/
@GET
@Restricted(NoExternalUse.class)
public JSONObject doGetGlobalRole(@QueryParameter(required = true) String name) {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
GlobalRole role = FolderAuthorizationStrategyAPI.getGlobalRole(name);
if (role != null) {
JSONObject responseJson = new JSONObject();
responseJson.put("name", role.getName());
responseJson.put("sids", role.getSids());
responseJson.put("permissions", getPermissionsFromRole(role));
return responseJson;
} else {
return null;
}
}

private Set<String> getPermissionsFromRole(AbstractRole role) {

SortedSet<PermissionWrapper> permissionWrappers = role.getPermissions();
Set<String> permissions = permissionWrappers.stream().map(permissionWrapper -> {
Permission permission = permissionWrapper.getPermission();
return permission.getId();
}).collect(Collectors.toSet());
return permissions;
}

/**
* API method to get the names of all roles that a user is assigned to
*
* @param sid User id of the Jenkins user
* @return Json object containing info on all the roles that the user is assigned to
*/
@GET
@Restricted(NoExternalUse.class)
public JSONObject doGetAssignedRoles(@QueryParameter(required = true) String sid) {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
// Find out how to get all roles
AuthorizationStrategy strategy = Jenkins.get().getAuthorizationStrategy();
if (!(strategy instanceof FolderBasedAuthorizationStrategy)) {
throw new IllegalStateException(Messages.FolderBasedAuthorizationStrategy_NotCurrentStrategy());
}
Set<AgentRole> agentRoles = ((FolderBasedAuthorizationStrategy) strategy).getAgentRoles();
Set<FolderRole> folderRoles = ((FolderBasedAuthorizationStrategy) strategy).getFolderRoles();
Set<GlobalRole> globalRoles = ((FolderBasedAuthorizationStrategy) strategy).getGlobalRoles();

Set<String> assignedAgentRoleNames = getAssignedRoleNames(agentRoles, sid);
Set<String> assignedFolderRoleNames = getAssignedRoleNames(folderRoles, sid);
Set<String> assignedGlobalRoleNames = getAssignedRoleNames(globalRoles, sid);

// Writing output
JSONObject responseJson = new JSONObject();
responseJson.put("agentRoles", assignedAgentRoleNames);
responseJson.put("folderRoles", assignedFolderRoleNames);
responseJson.put("globalRoles", assignedGlobalRoleNames);
return responseJson;
}

/**
* Util method that gets the names of the roles that a user is assigned to
*
* @param roles The set of roles that are available on the Jenkins controller
* @param sid User id of the Jenkins user
* @return The names of the roles that the user is assigned to
*/
private Set<String> getAssignedRoleNames(Set<? extends AbstractRole> roles, String sid) {
return roles.stream()
.filter(role -> {
Set<String> sids = role.getSids();
return sids.contains(sid);
}).map(AbstractRole::getName)
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
${%currentGlobalRoles}
</h2>
<div>
<input type="text" placeholder="${%filterPlaceholder}" class="filter" id="globalRoleFilter"/>
<input type="text" placeholder="${%filterPlaceholder}" class="filter" id="globalRoleFilter" onchange="doFilter('global')"/>
<div class="role-container" id="globalRoleContainer">
<j:forEach items="${it.globalRoles}" var="globalRole" indexVar="index">
<div class="role" roleName="${globalRole.name}">
Expand Down Expand Up @@ -107,7 +107,7 @@
${%currentFolderRoles}
</h2>
<div>
<input class="filter" type="text" id="folderRoleFilter" placeholder="${%filterPlaceholder}"/>
<input class="filter" type="text" id="folderRoleFilter" placeholder="${%filterPlaceholder}" onchange="doFilter('folder')"/>
<div class="role-container" id="folderRoleContainer">
<j:forEach items="${folderRoles}" var="folderRole" indexVar="index">
<div class="role" roleName="${folderRole.name}">
Expand Down Expand Up @@ -217,7 +217,7 @@
${%currentAgentRoles}
</h2>
<div>
<input class="filter" type="text" id="agentRoleFilter" placeholder="${%filterPlaceholder}"/>
<input class="filter" type="text" id="agentRoleFilter" placeholder="${%filterPlaceholder}" onchange="doFilter('agent')"/>
<div class="role-container" id="agentRoleContainer">
<j:forEach items="${it.agentRoles}" var="agentRole" indexVar="index">
<div class="role" roleName="${agentRole.name}">
Expand Down
6 changes: 3 additions & 3 deletions src/main/webapp/js/addrole.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const addGlobalRole = () => {
return;
}

sendPostRequest(`${rootURL}/folder-auth/addGlobalRole`, response);
sendPostRequest(rootURL + "/folder-auth/addGlobalRole", response);
AbhyudayaSharma marked this conversation as resolved.
Show resolved Hide resolved
};

// noinspection JSUnusedGlobalSymbols
Expand Down Expand Up @@ -51,7 +51,7 @@ const addFolderRole = () => {
return;
}

sendPostRequest(`${rootURL}/folder-auth/addFolderRole`, response);
sendPostRequest(rootURL + "/folder-auth/addFolderRole", response);
};

// noinspection JSUnusedGlobalSymbols
Expand Down Expand Up @@ -81,7 +81,7 @@ const addAgentRole = () => {
return;
}

sendPostRequest(`${rootURL}/folder-auth/addAgentRole`, response);
sendPostRequest(rootURL + "/folder-auth/addAgentRole", response);
};

/**
Expand Down
Loading