Skip to content

Commit

Permalink
added new permission check: get user permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
asafc committed Oct 15, 2023
1 parent 395a49d commit 9fee5b5
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 5 deletions.
5 changes: 5 additions & 0 deletions src/main/java/io/permit/sdk/Permit.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,9 @@ public List<TenantDetails> checkInAllTenants(User user, String action, Resource
public List<TenantDetails> checkInAllTenants(User user, String action, Resource resource) throws IOException {
return this.enforcer.checkInAllTenants(user, action, resource);
}

@Override
public UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws IOException {
return this.enforcer.getUserPermissions(input);
}
}
59 changes: 59 additions & 0 deletions src/main/java/io/permit/sdk/enforcement/Enforcer.java
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,65 @@ public List<TenantDetails> checkInAllTenants(User user, String action, Resource
return checkInAllTenants(user, action, resource, new Context());
}

@Override
public UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws IOException {
// request body
Gson gson = new Gson();
String requestBody = gson.toJson(input);
RequestBody body = RequestBody.create(requestBody, MediaType.parse("application/json"));

// create the request
String url = String.format("%s/user-permissions", this.config.getPdpAddress());
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", String.format("Bearer %s", this.config.getToken()))
.addHeader("X-Permit-SDK-Version", String.format("java:%s", this.config.version))
.build();

try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
String errorMessage = String.format(
"Error in permit.getUserPermissions(%s, %s, %s, %s): got unexpected status code %d",
input.user.toString(),
input.tenants.toString(),
input.resource_types.toString(),
input.resources.toString(),
response.code()
);
logger.error(errorMessage);
throw new IOException(errorMessage);
}
ResponseBody responseBody = response.body();
if (responseBody == null) {
String errorMessage = String.format(
"Error in permit.getUserPermissions(%s, %s, %s, %s): got empty response",
input.user.toString(),
input.tenants.toString(),
input.resource_types.toString(),
input.resources.toString()
);
logger.error(errorMessage);
throw new IOException(errorMessage);
}
String responseString = responseBody.string();
UserPermissions result = gson.fromJson(responseString, UserPermissions.class);
if (this.config.isDebugMode()) {
logger.info(String.format(
"permit.getUserPermissions(%s, %s, %s, %s) => returned %d permissions on %d objects",
input.user.toString(),
input.tenants != null ? input.tenants.toString() : "null",
input.resource_types != null ? input.resource_types.toString() : "null",
input.resources != null ? input.resources.toString() : "null",
result.values().stream().map(obj -> obj.permissions.size()).reduce(0, Integer::sum),
result.keySet().size()
));
}
return result;
}
}

@Override
public boolean checkUrl(User user, String httpMethod, String url, String tenant) throws IOException {
return this.checkUrl(user, httpMethod, url, tenant, new Context());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.permit.sdk.enforcement;

import io.permit.sdk.util.Context;

import java.util.ArrayList;
import java.util.List;

public final class GetUserPermissionsQuery {
public final User user;
public final List<String> tenants;
public final List<String> resource_types;
public final List<String> resources;
public final Context context;

/**
* input to get user permissions api
*
* @param user the user we'd like to get a list of permissions for.
* @param tenants filter only permissions granted on specific tenants.
* @param resource_types filter permissions based on resource type.
* @param resources filter permissions based on resource instance key.
* @param context The context for the authorization check.
*/
public GetUserPermissionsQuery(User user, List<String> tenants, List<String> resource_types, List<String> resources, Context context) {
this.user = user;
this.tenants = tenants;
this.resource_types = resource_types;
this.resources = resources;
this.context = context;
}

public GetUserPermissionsQuery(User user, List<String> tenants, List<String> resource_types, List<String> resources) {
this(user, tenants, resource_types, resources, new Context());
}

public GetUserPermissionsQuery(User user, List<String> tenants, List<String> resource_types) {
this(user, tenants, resource_types, null);
}

public GetUserPermissionsQuery(User user, List<String> tenants) {
this(user, tenants, null);
}

public GetUserPermissionsQuery(User user) {
this(user, null);
}
}
9 changes: 9 additions & 0 deletions src/main/java/io/permit/sdk/enforcement/IEnforcerApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,13 @@ public interface IEnforcerApi {
* @throws IOException if an error occurs while sending the authorization request to the PDP.
*/
List<TenantDetails> checkInAllTenants(User user, String action, Resource resource) throws IOException;

/**
* list all the permissions granted to a user (by default in all tenants and for all objects).
*
* @param input input to get user permissions api
* @return A UserPermissions object, that contains all the permissions granted to the user.
* @throws IOException if an error occurs while sending the authorization request to the PDP.
*/
UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws IOException;
}
19 changes: 19 additions & 0 deletions src/main/java/io/permit/sdk/enforcement/ObjectPermissions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.permit.sdk.enforcement;

import java.util.List;

/**
* The {@code ObjectPermissions} class represents a single object (tenant or resource instance) that the queried user can access.
*/
public class ObjectPermissions {

public final TenantDetails tenant;
public final ResourceDetails resource;
public final List<String> permissions;

public ObjectPermissions(TenantDetails tenant, ResourceDetails resource, List<String> permissions) {
this.tenant = tenant;
this.resource = resource;
this.permissions = permissions;
}
}
16 changes: 16 additions & 0 deletions src/main/java/io/permit/sdk/enforcement/ResourceDetails.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.permit.sdk.enforcement;

import io.permit.sdk.util.Context;

import java.util.HashMap;

/**
* The {@code ResourceDetails} class represents a single resource instance information fetched from the PDP (key and attributes).
*/
public final class ResourceDetails extends TenantDetails {
public final String type;
public ResourceDetails(String type, String key, HashMap<String, Object> attributes) {
super(key, attributes);
this.type = type;
}
}
2 changes: 1 addition & 1 deletion src/main/java/io/permit/sdk/enforcement/TenantDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* The {@code TenantDetails} class represents a single tenant information fetched from the PDP (key and attributes).
*/
public final class TenantDetails {
public class TenantDetails {
public final String key;
public final HashMap<String, Object> attributes;
public TenantDetails(String key, HashMap<String, Object> attributes) {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/io/permit/sdk/enforcement/UserPermissions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.permit.sdk.enforcement;

import java.util.HashMap;

/**
* The {@code UserPermissions} class represents all the objects a user can access.
*/
final public class UserPermissions extends HashMap<String, ObjectPermissions> {}
22 changes: 18 additions & 4 deletions src/test/java/io/permit/sdk/e2e/RbacE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import io.permit.sdk.api.PermitContextError;
import io.permit.sdk.Permit;
import io.permit.sdk.api.models.CreateOrUpdateResult;
import io.permit.sdk.enforcement.CheckQuery;
import io.permit.sdk.enforcement.Resource;
import io.permit.sdk.enforcement.TenantDetails;
import io.permit.sdk.enforcement.User;
import io.permit.sdk.enforcement.*;
import io.permit.sdk.openapi.models.*;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
Expand All @@ -20,6 +17,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;

Expand All @@ -32,6 +30,8 @@
public class RbacE2ETest extends PermitE2ETestBase {
private final Logger logger = LoggerFactory.getLogger(RbacE2ETest.class);

private static final String TENANT_RESOURCE_KEY = "__tenant";

@Test
void testPermissionCheckRBAC() {
// init the client
Expand Down Expand Up @@ -244,6 +244,20 @@ void testPermissionCheckRBAC() {
assertEquals(allowedTenants2.get(0).key, tenant2.key);
assertEquals(((String)allowedTenants2.get(0).attributes.get("unit")), "one");

logger.info("testing 'get user permissions' on user 'elon'");
UserPermissions permissions = permit.getUserPermissions(
new GetUserPermissionsQuery(
User.fromString("auth0|elon")
)
);
assertEquals(permissions.keySet().size(), 2); // elon has access to 2 tenants
String tenantObjectKey = String.format("%s:%s", TENANT_RESOURCE_KEY, tenant.key);
String tenant2ObjectKey = String.format("%s:%s", TENANT_RESOURCE_KEY, tenant2.key);
assertTrue(permissions.containsKey(tenantObjectKey));
assertTrue(permissions.containsKey(tenant2ObjectKey));
assertTrue(permissions.get(tenantObjectKey).permissions.contains("document:read"));
assertTrue(permissions.get(tenant2ObjectKey).permissions.contains("document:create"));

// change the user role
permit.api.users.assignRole(user.key, admin.key, tenant.key);
permit.api.users.unassignRole(user.key, viewer.key, tenant.key);
Expand Down

0 comments on commit 9fee5b5

Please sign in to comment.