diff --git a/src/main/java/io/permit/sdk/api/ApiClient.java b/src/main/java/io/permit/sdk/api/ApiClient.java index 78d8374..1483bb4 100644 --- a/src/main/java/io/permit/sdk/api/ApiClient.java +++ b/src/main/java/io/permit/sdk/api/ApiClient.java @@ -119,6 +119,10 @@ public class ApiClient implements IDeprecatedApis { */ public final ElementsApi elements; + /** + * The {@code GroupsApi} instance for accessing Permit Groups related API endpoints. + */ + public final GroupsApi groups; /** * Constructs a new instance of the {@code ApiClient} class with the specified configuration. @@ -148,6 +152,7 @@ public ApiClient(PermitConfig config) { this.relationshipTuples = new RelationshipTuplesApi(this.client, this.config); this.conditionSetRules = new ConditionSetRulesApi(this.client, this.config); this.elements = new ElementsApi(this.client, this.config); + this.groups = new GroupsApi(this.client, this.config); } /** diff --git a/src/main/java/io/permit/sdk/api/GroupsApi.java b/src/main/java/io/permit/sdk/api/GroupsApi.java new file mode 100644 index 0000000..48d693b --- /dev/null +++ b/src/main/java/io/permit/sdk/api/GroupsApi.java @@ -0,0 +1,327 @@ +package io.permit.sdk.api; + +import com.google.gson.Gson; +import io.permit.sdk.ApiContextLevel; +import io.permit.sdk.ApiKeyLevel; +import io.permit.sdk.PermitConfig; + +import io.permit.sdk.openapi.models.*; +import okhttp3.*; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.*; + +// This is a partial support for the Groups API, some methods are currently missing. +interface IGroupsApi { + GroupRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError; + GroupRead[] list(int page) throws IOException, PermitApiError, PermitContextError; + GroupRead[] list() throws IOException, PermitApiError, PermitContextError; + GroupRead create(GroupCreate groupData) throws IOException, PermitApiError, PermitContextError; + void delete(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError; + GroupRead get(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError; + GroupRead getByKey(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError; + GroupRead getById(UUID groupInstanceId) throws IOException, PermitApiError, PermitContextError; + GroupRead assignRoleToGroup(String groupInstanceKey, GroupAddRole groupAddRole) throws IOException, PermitApiError, PermitContextError; + GroupRead assignUserToGroup(String userId, String groupInstanceKey, String tenant) throws IOException, PermitApiError, PermitContextError; + void removeRoleFromGroup(String groupInstanceKey, GroupAddRole groupAddRole) throws IOException, PermitApiError, PermitContextError; + void removeUserFromGroup(String userId, String groupInstanceKey, String tenant) throws IOException, PermitApiError, PermitContextError; +} + +public class GroupsApi extends BaseApi implements IGroupsApi { + /** + * Constructs a new GroupsApi instance. + * + * @param client The OkHttpClient instance used for making HTTP requests. + * @param config The PermitConfig instance containing the SDK configuration. + */ + public GroupsApi(OkHttpClient client, PermitConfig config) { + super(client, config, LoggerFactory.getLogger(GroupsApi.class)); + } + + /** + * Constructs the URL for the Groups API. + * + * @param url The URL fragment. + * @return The constructed URL string. + */ + private String getGroupsUrl(String url) { + return buildUrl( + String.format( + "/v2/schema/%s/%s/groups%s", + config.getContext().getProject(), + config.getContext().getEnvironment(), + url + ) + ); + } + + /** + * Retrieves a paginated result of groups. + * + * @param page The page number of the result set to retrieve. + * @param perPage The number of items per page. + * @return An array of {@link GroupRead} objects representing the retrieved groups. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(""); + HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); + Request request = buildRequest( + new Request.Builder() + .url( + urlBuilder + .addQueryParameter("page", Integer.toString(page)) + .addQueryParameter("per_page", Integer.toString(perPage)) + .build() + ) + .get() + ); + + try (Response response = client.newCall(request).execute()) { + String responseString = processResponseBody(response); + return (new Gson()).fromJson(responseString, GroupRead[].class); + } + } + + /** + * Retrieves a paginated result of groups with default pagination. + * + * @param page The page number of the result set to retrieve. + * @return A list of {@link GroupRead} objects representing the retrieved paginated result of groups. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead[] list(int page) throws IOException, PermitApiError, PermitContextError { + return this.list(page, 100); + } + + /** + * Retrieves a paginated result of groups with default pagination. + * + * @return A list of {@link GroupRead} objects representing the retrieved paginated result of groups. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead[] list() throws IOException, PermitApiError, PermitContextError { + return this.list(1); + } + + /** + * Retrieves a group by its group instance key. + * + * @param groupInstanceKey The key of the group. + * @return The {@link GroupRead} object representing the group. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead get(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s", groupInstanceKey)); + Request request = buildRequest( + new Request.Builder() + .url(url) + .get() + ); + + return this.callApiAndParseJson(request, GroupRead.class); + } + + /** + * Retrieves a group by its group instance key. + * + * @param groupInstanceKey The key of the group. + * @return The {@link GroupRead} object representing the group. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead getByKey(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError { + return this.get(groupInstanceKey); + } + + /** + * Retrieves a group by its ID. + * + * @param groupInstanceId The ID of the group. + * @return The {@link GroupRead} object representing the group. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead getById(UUID groupInstanceId) throws IOException, PermitApiError, PermitContextError { + return this.get(groupInstanceId.toString()); + } + + /** + * Creates a new group. + * + * @param groupData The {@link GroupCreate} object representing the group data. + * @return A {@link GroupRead} object representing the created group. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead create(GroupCreate groupData) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(""); + RequestBody jsonBody = getJsonRequestBody(groupData); + + Request request = buildRequest( + new Request.Builder() + .url(url) + .post(jsonBody) + ); + + return this.callApiAndParseJson(request, GroupRead.class); + } + + /** + * Deletes a group with the specified group instance key. + * + * @param groupInstanceKey The key of the group to delete. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public void delete(String groupInstanceKey) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s", groupInstanceKey)); + Request request = buildRequest( + new Request.Builder() + .url(url) + .delete() + ); + + try (Response response = client.newCall(request).execute()) { + processResponseBody(response, false); + } + } + + /** + * Assign a role to the group, all users in this group will now have this role. + * It will create relation between the group and the resource, relationship between the resource instances and derivation from the member role to this role. + * + * @param groupInstanceKey The key of the group to assign the role to. + * @param groupAddRole The {@link GroupAddRole} object containing the assignment data. + * @return The {@link GroupRead} object representing the group after assigning the role. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead assignRoleToGroup(String groupInstanceKey, GroupAddRole groupAddRole) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s/roles", groupInstanceKey)); + RequestBody jsonBody = getJsonRequestBody(groupAddRole); + + Request request = buildRequest( + new Request.Builder() + .url(url) + .post(jsonBody) + ); + + return this.callApiAndParseJson(request, GroupRead.class); + } + + /** + * Assign a user to the group. + * + * @param userId The id of the user to assign to the group. + * @param groupInstanceKey The key of the group to assign the user to. + * @param tenant The tenant key or id that the user belongs to. + * @return The {@link GroupRead} object representing the group after assigning the user. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public GroupRead assignUserToGroup(String userId, String groupInstanceKey, String tenant) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s/users/%s", groupInstanceKey, userId)); + RequestBody jsonBody = getJsonRequestBody(new GroupAssignUser(tenant)); + + Request request = buildRequest( + new Request.Builder() + .url(url) + .put(jsonBody) + ); + + return this.callApiAndParseJson(request, GroupRead.class); + } + + /** + * Remove a role from the group, all users in this group will lose this role. + * + * @param groupInstanceKey The key of the group to remove the role from. + * @param groupAddRole The {@link GroupAddRole} object containing the assignment data. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public void removeRoleFromGroup(String groupInstanceKey, GroupAddRole groupAddRole) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s/roles", groupInstanceKey)); + RequestBody jsonBody = getJsonRequestBody(groupAddRole); + + Request request = buildRequest( + new Request.Builder() + .url(url) + .delete(jsonBody) + ); + + try (Response response = client.newCall(request).execute()) { + processResponseBody(response, false); + } + } + + /** + * Remove a user from the group. + * + * @param userId The id of the user to remove from the group. + * @param groupInstanceKey The key of the group to remove the user from. + * @param tenant The tenant key or id that the user belongs to. + * @throws IOException If an I/O error occurs during the HTTP request. + * @throws PermitApiError If the Permit API returns a response with an error status code. + * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. + */ + @Override + public void removeUserFromGroup(String userId, String groupInstanceKey, String tenant) throws IOException, PermitApiError, PermitContextError { + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); + String url = getGroupsUrl(String.format("/%s/users/%s", groupInstanceKey, userId)); + RequestBody jsonBody = getJsonRequestBody(new GroupAssignUser(tenant)); + + Request request = buildRequest( + new Request.Builder() + .url(url) + .delete(jsonBody) + ); + + try (Response response = client.newCall(request).execute()) { + processResponseBody(response, false); + } + } +} diff --git a/src/main/java/io/permit/sdk/api/RelationshipTuplesApi.java b/src/main/java/io/permit/sdk/api/RelationshipTuplesApi.java index 161d7d7..cf196b2 100644 --- a/src/main/java/io/permit/sdk/api/RelationshipTuplesApi.java +++ b/src/main/java/io/permit/sdk/api/RelationshipTuplesApi.java @@ -114,7 +114,7 @@ public RelationshipTupleRead[] list(String subject, String relation, String obje * @param object The object of the relationship (a resource instance key). * @param page The page number of the results. * @return An array of RelationshipTupleRead objects representing the relationship tuples. - * @throws IOException If an I/Oerror occurs during the HTTP request. + * @throws IOException If an I/O error occurs during the HTTP request. * @throws PermitApiError If the Permit API returns a response with an error status code. * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ @@ -129,7 +129,7 @@ public RelationshipTupleRead[] list(String subject, String relation, String obje * @param relation The relation between the two resource instances. * @param object The object of the relationship (a resource instance key). * @return An array of RelationshipTupleRead objects representing the relationship tuples. - * @throws IOException If an I/Oerror occurs during the HTTP request. + * @throws IOException If an I/O error occurs during the HTTP request. * @throws PermitApiError If the Permit API returns a response with an error status code. * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ @@ -141,7 +141,7 @@ public RelationshipTupleRead[] list(String subject, String relation, String obje * Lists all relationship tuples with the default pagination parameters. * * @return An array of RelationshipTupleRead objects representing the relationship tuples. - * @throws IOException If an I/Oerror occurs during the HTTP request. + * @throws IOException If an I/O error occurs during the HTTP request. * @throws PermitApiError If the Permit API returns a response with an error status code. * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ diff --git a/src/main/java/io/permit/sdk/api/ResourceInstancesApi.java b/src/main/java/io/permit/sdk/api/ResourceInstancesApi.java index 36e8f0f..619e5e4 100644 --- a/src/main/java/io/permit/sdk/api/ResourceInstancesApi.java +++ b/src/main/java/io/permit/sdk/api/ResourceInstancesApi.java @@ -146,6 +146,7 @@ public ResourceInstanceRead get(String instanceKey) throws IOException, PermitAp /** * Retrieves a resource instance by its key. + * This is an alias for the {@link #get} method. * * @param instanceKey The key of the resource instance. * @return A ResourceInstanceRead object representing the retrieved resource instance. diff --git a/src/main/java/io/permit/sdk/api/ResourceRelationsApi.java b/src/main/java/io/permit/sdk/api/ResourceRelationsApi.java index 08b864b..a863287 100644 --- a/src/main/java/io/permit/sdk/api/ResourceRelationsApi.java +++ b/src/main/java/io/permit/sdk/api/ResourceRelationsApi.java @@ -172,7 +172,7 @@ public RelationRead getById(UUID resourceId, UUID relationId) throws IOException /** * Creates a new relation under the specified resource. - * Since resource respresents a type, the relation itself represents a type and not a value. + * Since resource represents a type, the relation itself represents a type and not a value. * * @param resourceKey The key of the resource. * @param relationData The {@link RelationCreate} object containing the data for the new resource relation. diff --git a/src/main/java/io/permit/sdk/api/UsersApi.java b/src/main/java/io/permit/sdk/api/UsersApi.java index 2c55cb7..9110960 100644 --- a/src/main/java/io/permit/sdk/api/UsersApi.java +++ b/src/main/java/io/permit/sdk/api/UsersApi.java @@ -135,7 +135,7 @@ public PaginatedResultUserRead list() throws IOException, PermitApiError, Permit /** * Retrieves a user by its key. * - * @param userKey The key of theuser. + * @param userKey The key of the user. * @return A UserRead object representing the retrieved user. * @throws IOException If an I/O error occurs during the HTTP request. * @throws PermitApiError If the Permit API returns a response with an error status code. diff --git a/src/main/java/io/permit/sdk/openapi/models/GroupAddRole.java b/src/main/java/io/permit/sdk/openapi/models/GroupAddRole.java new file mode 100644 index 0000000..eab3080 --- /dev/null +++ b/src/main/java/io/permit/sdk/openapi/models/GroupAddRole.java @@ -0,0 +1,113 @@ +/* + * Permit.io API + * Authorization as a service + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package io.permit.sdk.openapi.models; + +import javax.annotation.Generated; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + + +/** + * GroupAddRole + *

+ * + * + */ +@Generated("jsonschema2pojo") +public class GroupAddRole { + /** + * Role + *

+ * The role key or id that will be assigned to the group. + * (Required) + * + */ + @SerializedName("role") + @Expose + public String role; + /** + * Resource + *

+ * The resource key or id that the role belongs to. + * (Required) + * + */ + @SerializedName("resource") + @Expose + public String resource; + /** + * ResourceInstance + *

+ * The resource instance key or id that the role belongs to. + * (Required) + * + */ + @SerializedName("resource_instance") + @Expose + public String resourceInstance; + /** + * Tenant + *

+ * The tenant key or id that the role belongs to. + * (Required) + * + */ + @SerializedName("tenant") + @Expose + public String tenant; + + /** + * No args constructor for use in serialization + * + */ + public GroupAddRole() { + } + + /** + * Constructs a new GroupAddRole with all required identifiers. + * + * @param role the role key or id to assign to the group + * @param resourceInstance the resource instance key or id that the role belongs to + * @param resource the resource key or id that the role belongs to + * @param tenant the tenant key or id that the role belongs to + */ + public GroupAddRole(java.lang.String role, java.lang.String resourceInstance, java.lang.String resource, java.lang.String tenant) { + super(); + this.role = role; + this.resourceInstance = resourceInstance; + this.resource = resource; + this.tenant = tenant; + } + + public GroupAddRole withRole(java.lang.String role) { + this.role = role; + return this; + } + + public GroupAddRole withResourceInstanceKey(java.lang.String resourceInstance) { + this.resourceInstance = resourceInstance; + return this; + } + + public GroupAddRole withResource(java.lang.String resource) { + this.resource = resource; + return this; + } + + public GroupAddRole withTenant(java.lang.String tenant) { + this.tenant = tenant; + return this; + } +} + diff --git a/src/main/java/io/permit/sdk/openapi/models/GroupAssignUser.java b/src/main/java/io/permit/sdk/openapi/models/GroupAssignUser.java new file mode 100644 index 0000000..23d5717 --- /dev/null +++ b/src/main/java/io/permit/sdk/openapi/models/GroupAssignUser.java @@ -0,0 +1,52 @@ +/* + * Permit.io API + * Authorization as a service + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package io.permit.sdk.openapi.models; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * GroupAssignUser + *

+ * + * + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-11-26T18:29:37.439030+07:00[Asia/Ho_Chi_Minh]", comments = "Generator version: 7.17.0") +public class GroupAssignUser { + /** + * Tenant + *

+ * the tenant key or id that the user belongs to. + * (Required) + */ + @SerializedName("tenant") + @Expose + public String tenant; + + /** + * + + * @param tenant + */ + public GroupAssignUser(java.lang.String tenant) { + super(); + this.tenant = tenant; + } + + public GroupAssignUser withTenant(java.lang.String tenant) { + this.tenant = tenant; + return this; + } +} + diff --git a/src/main/java/io/permit/sdk/openapi/models/GroupCreate.java b/src/main/java/io/permit/sdk/openapi/models/GroupCreate.java new file mode 100644 index 0000000..a8090f2 --- /dev/null +++ b/src/main/java/io/permit/sdk/openapi/models/GroupCreate.java @@ -0,0 +1,94 @@ +/* + * Permit.io API + * Authorization as a service + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package io.permit.sdk.openapi.models; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import javax.annotation.Generated; + +/** + * GroupCreate + *

+ * + * + */ +@Generated("jsonschema2pojo") +public class GroupCreate { + /** + * Group Resource Type Key + *

+ * The key of the resource type that the group belongs to. + * + */ + @SerializedName("group_resource_type_key") + @Expose + public java.lang.String groupResourceTypeKey = "group"; + + /** + * Group Instance Key + *

+ * Either the unique id of the resource instance that that the group belongs to, or the URL-friendly key of the (i.e: file:my_file) + * (Required) + * + */ + @SerializedName("group_instance_key") + @Expose + public java.lang.String groupInstanceKey; + + /** + * Group Tenant + *

+ * The tenant key or id that the group belongs to. + * (Required) + * + */ + @SerializedName("group_tenant") + @Expose + public java.lang.String groupTenant; + + /** + * No args constructor for use in serialization + * + */ + public GroupCreate() { + } + + /** + * + * @param groupInstanceKey + * @param groupTenant + */ + public GroupCreate(java.lang.String groupInstanceKey, java.lang.String groupTenant) { + super(); + this.groupInstanceKey = groupInstanceKey; + this.groupTenant = groupTenant; + } + + public GroupCreate withGroupInstanceKey(java.lang.String groupInstanceKey) { + this.groupInstanceKey = groupInstanceKey; + return this; + } + + public GroupCreate withGroupTenant(java.lang.String groupTenant) { + this.groupTenant = groupTenant; + return this; + } + + public GroupCreate withGroupResourceTypeKey(java.lang.String groupResourceTypeKey) { + this.groupResourceTypeKey = groupResourceTypeKey; + return this; + } +} + diff --git a/src/main/java/io/permit/sdk/openapi/models/GroupRead.java b/src/main/java/io/permit/sdk/openapi/models/GroupRead.java new file mode 100644 index 0000000..92a4e47 --- /dev/null +++ b/src/main/java/io/permit/sdk/openapi/models/GroupRead.java @@ -0,0 +1,128 @@ +/* + * Permit.io API + * Authorization as a service + * + * The version of the OpenAPI document: 2.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package io.permit.sdk.openapi.models; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import javax.annotation.Generated; + +import java.util.ArrayList; +import java.util.List; + + +/** + * GroupRead + *

+ * + * + */ +@Generated("jsonschema2pojo") +public class GroupRead { + /** + * Assigned Roles + *

+ * List of roles that are assigned to this group + * + */ + @SerializedName("assigned_roles") + @Expose + public List assignedRoles = new ArrayList<>(); + /** + * Users + *

+ * List of user ids that are assigned to this group + * + */ + @SerializedName("users") + @Expose + public List users = new ArrayList<>(); + /** + * GroupResourceTypeKey + *

+ * The key of the resource type that the group belongs to. + * + */ + @SerializedName("group_resource_type_key") + @Expose + public String groupResourceTypeKey = "group"; + /** + * GroupInstanceKey + *

+ * Either the unique id of the resource instance that that the group belongs to, or the URL-friendly key of the (i.e: file:my_file) + * (Required) + * + */ + @SerializedName("group_instance_key") + @Expose + public String groupInstanceKey; + /** + * Tenant + *

+ * The tenant key or id that the group belongs to. + * (Required) + * + */ + @SerializedName("group_tenant") + @Expose + public String groupTenant; + + /** + * No args constructor for use in serialization + * + */ + public GroupRead() { + } + + /** + * + * @param groupTenant + * @param groupInstanceKey + */ + public GroupRead(java.lang.String groupInstanceKey, java.lang.String groupTenant) { + super(); + this.groupTenant = groupTenant; + this.groupInstanceKey = groupInstanceKey; + } + + public GroupRead withAssignedRoles(List assignedRoles) { + this.assignedRoles = assignedRoles; + return this; + } + + public GroupRead withUsers(List users) { + this.users = users; + return this; + } + + public GroupRead withGroupResourceTypeKey(java.lang.String groupResourceTypeKey) { + this.groupResourceTypeKey = groupResourceTypeKey; + return this; + } + + public GroupRead withGroupInstanceKey(java.lang.String groupInstanceKey) { + this.groupInstanceKey = groupInstanceKey; + return this; + } + + public GroupRead withGroupTenant(java.lang.String groupTenant) { + this.groupTenant = groupTenant; + return this; + } + + @Override + public String toString() { + return String.format("{%s:%s, %s, %s}", this.groupResourceTypeKey, this.groupInstanceKey, this.assignedRoles, this.users); + } +} + diff --git a/src/test/java/io/permit/sdk/endpoints/GroupsApiE2ETest.java b/src/test/java/io/permit/sdk/endpoints/GroupsApiE2ETest.java new file mode 100644 index 0000000..fea72f3 --- /dev/null +++ b/src/test/java/io/permit/sdk/endpoints/GroupsApiE2ETest.java @@ -0,0 +1,245 @@ +package io.permit.sdk.endpoints; + +import com.google.gson.internal.LinkedTreeMap; +import io.permit.sdk.Permit; +import io.permit.sdk.PermitE2ETestBase; +import io.permit.sdk.api.PermitApiError; +import io.permit.sdk.api.PermitContextError; +import io.permit.sdk.openapi.models.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +public class GroupsApiE2ETest extends PermitE2ETestBase { + private static final String TEAM_KEY = "teams"; + private static final String MARKETING_KEY = "marketing"; + private static final String GROUP_KEY = TEAM_KEY + ":" + MARKETING_KEY; + private static final String DEFAULT_TENANT = "default"; + private static GroupCreate marketingData; + + private static ResourceCreate socialMediaData; + private static ResourceInstanceCreate trainingVideoData; + private static ResourceRoleCreate editorRole; + + private static UserCreate bobData; + private static GroupAddRole groupRoleData; + + @BeforeAll + static void setup() { + // resource actions + HashMap actions = new HashMap<>(); + actions.put("create", new ActionBlockEditable()); + actions.put("read", new ActionBlockEditable().withName("Read").withDescription("Read Action")); + actions.put("update", new ActionBlockEditable()); + actions.put("delete", new ActionBlockEditable()); + + marketingData = new GroupCreate(MARKETING_KEY, DEFAULT_TENANT).withGroupResourceTypeKey(TEAM_KEY); + + socialMediaData = new ResourceCreate("social_media", "social media", actions); + trainingVideoData = new ResourceInstanceCreate("training_video", socialMediaData.key).withTenant(DEFAULT_TENANT); + editorRole = new ResourceRoleCreate("editor", "editor"); + + bobData = new UserCreate("bob"); + groupRoleData = new GroupAddRole(editorRole.key, trainingVideoData.key, socialMediaData.key, DEFAULT_TENANT); + } + + void cleanup() { + Permit permit = new Permit(this.config); + logger.info("cleaning"); + try { + try { + permit.api.resourceRoles.delete(socialMediaData.key, editorRole.key); + } catch (PermitApiError e) { + logger.info(String.format("SKIPPING delete of role %s on resource instance %s", editorRole.key, trainingVideoData.key)); + } + try { + permit.api.resourceInstances.delete(trainingVideoData.resource + ":" + trainingVideoData.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource instance: " + trainingVideoData.key); + } + try { + permit.api.users.delete(bobData.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of user: " + bobData.key); + } + try { + permit.api.groups.delete(GROUP_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of group: " + GROUP_KEY); + } + try { + permit.api.resourceRoles.delete(TEAM_KEY, "member"); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource role: " + TEAM_KEY + " member"); + } + try { + permit.api.resources.delete(socialMediaData.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + socialMediaData.key); + } + try { + permit.api.resources.delete(TEAM_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + TEAM_KEY); + } + try { + permit.api.resourceRelations.delete(socialMediaData.key, TEAM_KEY + "_group_" + editorRole.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource relation: " + TEAM_KEY + "_group_" + editorRole.key); + } + try { + permit.api.groups.removeRoleFromGroup(GROUP_KEY, groupRoleData); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource relation: " + TEAM_KEY + "_group_" + editorRole.key); + } + } catch (PermitContextError e) { + fail("clean up got error: " + e); + } catch (IOException e) { + fail("clean up got IOexception: " + e); + } + } + + @Test + void testGroupsApi() { + Permit permit = new Permit(this.config); + try { + logger.info("check original groups length"); + int originalLength = permit.api.groups.list().length; + + GroupRead marketingGroup = permit.api.groups.create(marketingData); + assertNotNull(marketingGroup); + assertNotNull(marketingGroup.groupResourceTypeKey); + assertEquals(marketingGroup.groupResourceTypeKey, marketingData.groupResourceTypeKey); + assertEquals(marketingGroup.groupTenant, marketingData.groupTenant); + assertEquals(marketingGroup.groupInstanceKey, marketingData.groupInstanceKey); + boolean foundMember = false; + for (String role : marketingGroup.assignedRoles) { + if (role.contains("member")) { + foundMember = true; + break; + } + } + assertTrue(foundMember); + + logger.info("verify number of items increased by 1"); + GroupRead[] groups = permit.api.groups.list(); + assertEquals(groups.length, originalLength + 1); + + logger.info("verify can find new group in the new list"); + assertTrue(Arrays.stream(groups).map(r -> r.groupInstanceKey).collect(Collectors.toList()).toString().contains(marketingData.groupInstanceKey)); + + logger.info("get non existing group -> 404"); + PermitApiError notFoundError = assertThrows(PermitApiError.class, () -> { + permit.api.groups.get("group"); + }); + assertEquals("Got error status code: 404", notFoundError.getMessage()); + assertEquals(404, notFoundError.getResponseCode()); + LinkedTreeMap error = notFoundError.getErrorObject(); + assertEquals("NOT_FOUND", error.get("error_code")); + assertTrue(error.get("message").toString().startsWith("The requested data could not be found")); + + logger.info("create existing group -> 409"); + PermitApiError duplicateError = assertThrows(PermitApiError.class, () -> { + permit.api.groups.create(marketingData); + }); + assertEquals(409, duplicateError.getResponseCode()); + + + // test assign user + logger.info("Adding user to group"); + UserRead bob = permit.api.users.create(bobData); + GroupRead afterAddingUser = permit.api.groups.assignUserToGroup(bobData.key, GROUP_KEY, DEFAULT_TENANT); + assertTrue(afterAddingUser.users.contains(bob.id)); + assertEquals(1, afterAddingUser.users.size()); + + logger.info("Adding user already in group"); + GroupRead afterAddingUserAgain = permit.api.groups.assignUserToGroup(bobData.key, GROUP_KEY, DEFAULT_TENANT); + assertEquals(afterAddingUserAgain.users.size(), afterAddingUser.users.size()); + logger.info("Removing user from group"); + permit.api.groups.removeUserFromGroup(bobData.key, GROUP_KEY, DEFAULT_TENANT); + GroupRead afterRemovingUser = permit.api.groups.get(GROUP_KEY); + assertEquals(0, afterRemovingUser.users.size()); + + // test assign role + logger.info("Adding role to group"); + + try { + permit.api.resources.create(socialMediaData); + } catch (PermitApiError e) { + logger.info("SKIPPING creating resource: " + socialMediaData.key); + } + try { + permit.api.resourceInstances.create(trainingVideoData); + } catch (PermitApiError e) { + logger.info("SKIPPING creating resource instances: " + trainingVideoData.key); + } + try { + permit.api.resourceRoles.create(socialMediaData.key, editorRole); + } catch (PermitApiError e) { + logger.info("SKIPPING creating resource role: " + socialMediaData.key + editorRole.key); + } + + GroupRead afterAddingRole = permit.api.groups.assignRoleToGroup(GROUP_KEY, groupRoleData); + boolean foundRole = false; + boolean foundResource = false; + boolean foundResourceInstance = false; + for (String role : afterAddingRole.assignedRoles) { + if (role.contains(groupRoleData.role)) + foundRole = true; + if (role.contains(groupRoleData.resource)) + foundResource = true; + if (role.contains(groupRoleData.resourceInstance)) + foundResourceInstance = true; + } + assertTrue(foundRole); + assertTrue(foundResource); + assertTrue(foundResourceInstance); + assertEquals(2, afterAddingRole.assignedRoles.size()); + + logger.info("Removing role from group"); + permit.api.groups.removeRoleFromGroup(GROUP_KEY, groupRoleData); + GroupRead afterRemovingRole = permit.api.groups.get(GROUP_KEY); + for (String role : afterRemovingRole.assignedRoles) { + if (!role.contains(groupRoleData.role)) + foundRole = false; + if (!role.contains(groupRoleData.resource)) + foundResource = false; + if (!role.contains(groupRoleData.resourceInstance)) + foundResourceInstance = false; + } + assertFalse(foundRole); + assertFalse(foundResource); + assertFalse(foundResourceInstance); + assertEquals(1, afterRemovingRole.assignedRoles.size()); + + // delete group + logger.info("Delete group..."); + try { + permit.api.groups.delete(GROUP_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + + logger.info("Verify that again we have the initial number of groups"); + GroupRead[] groupsAfterDelete = permit.api.groups.list(); + assertEquals(groupsAfterDelete.length, originalLength); + + logger.info("Verify deleted groups cannot be deleted again"); + PermitApiError exception = assertThrows(PermitApiError.class, () -> { + permit.api.groups.delete(GROUP_KEY); + }); + assertEquals(404, exception.getResponseCode()); + + } catch (IOException | PermitApiError | PermitContextError e) { + fail("testGroupsApi got error: " + e); + } finally { + cleanup(); + } + } +} diff --git a/src/test/java/io/permit/sdk/endpoints/ResourcesApiE2ETest.java b/src/test/java/io/permit/sdk/endpoints/ResourcesApiE2ETest.java index 71e613b..1dd9289 100644 --- a/src/test/java/io/permit/sdk/endpoints/ResourcesApiE2ETest.java +++ b/src/test/java/io/permit/sdk/endpoints/ResourcesApiE2ETest.java @@ -85,7 +85,7 @@ void testResourcesApi() { Permit permit = new Permit(this.config); Gson gson = new Gson(); - // roles lifecycle + // Resource lifecycle. try { logger.info("check original resource length"); int originalLength = permit.api.resources.list().length; @@ -111,7 +111,7 @@ void testResourcesApi() { logger.info("verify can find new resource in the new list"); assertTrue(Arrays.stream(resources).map(r -> r.key).collect(Collectors.toList()).contains(documentData.key)); - logger.info("get non existing role -> 404"); + logger.info("get non existing resource -> 404"); PermitApiError notFoundError = assertThrows(PermitApiError.class, () -> { permit.api.resources.get("group"); });