diff --git a/src/main/java/io/permit/sdk/ApiContextLevel.java b/src/main/java/io/permit/sdk/ApiContextLevel.java new file mode 100644 index 0000000..c95155d --- /dev/null +++ b/src/main/java/io/permit/sdk/ApiContextLevel.java @@ -0,0 +1,18 @@ +package io.permit.sdk; + +public enum ApiContextLevel { + WAIT_FOR_INIT(0), + ORGANIZATION(1), + PROJECT(2), + ENVIRONMENT(3); + + private final int value; + + ApiContextLevel(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} \ No newline at end of file diff --git a/src/main/java/io/permit/sdk/ApiKeyLevel.java b/src/main/java/io/permit/sdk/ApiKeyLevel.java index 2e6f047..5a40a85 100644 --- a/src/main/java/io/permit/sdk/ApiKeyLevel.java +++ b/src/main/java/io/permit/sdk/ApiKeyLevel.java @@ -1,14 +1,27 @@ package io.permit.sdk; /** - * The {@code ApiKeyLevel} enum represents the different levels (or scopes) of API keys in the Permit SDK. - * These levels determine the scope of permissions granted by the API key: is the API granting permission + * The {@code ApiKeyLevel} enum represents the granted access level of an API key used by the Permit SDK. + * The access level determine the scope of permissions granted by the API key: is the API granting permission * to the entire workspace (i.e: organization), to a specific project within the workspace, or to a specific * project and environment within the workspace. + * + * NOTE: Access levels are enforced on the backend using the API key (you cannot override this value). + * this enum is intended as a read-only representation to help the user understand his access level from code. */ public enum ApiKeyLevel { - WAIT_FOR_INIT, - ORGANIZATION_LEVEL_API_KEY, - PROJECT_LEVEL_API_KEY, - ENVIRONMENT_LEVEL_API_KEY, + WAIT_FOR_INIT(0), + ORGANIZATION_LEVEL_API_KEY(1), + PROJECT_LEVEL_API_KEY(2), + ENVIRONMENT_LEVEL_API_KEY(3); + + private final int value; + + ApiKeyLevel(int value) { + this.value = value; + } + + public int getValue() { + return value; + } } diff --git a/src/main/java/io/permit/sdk/PermitConfig.java b/src/main/java/io/permit/sdk/PermitConfig.java index d02c22a..adbd4ed 100644 --- a/src/main/java/io/permit/sdk/PermitConfig.java +++ b/src/main/java/io/permit/sdk/PermitConfig.java @@ -26,6 +26,8 @@ public class PermitConfig { private final String defaultTenant; private final Boolean useDefaultTenantIfEmpty; private PermitContext context; + public final String version; + private final static String defaultVersion = "1.3.1-rc"; private PermitConfig(Builder builder) { this.token = builder.token; @@ -41,6 +43,8 @@ private PermitConfig(Builder builder) { this.defaultTenant = builder.defaultTenant; this.useDefaultTenantIfEmpty = builder.useDefaultTenantIfEmpty; this.context = builder.context; + String runtimeVersion = Permit.class.getPackage().getImplementationVersion(); + this.version = (runtimeVersion == null) ? defaultVersion : runtimeVersion; } /** diff --git a/src/main/java/io/permit/sdk/PermitContext.java b/src/main/java/io/permit/sdk/PermitContext.java index 6fd6162..2a43175 100644 --- a/src/main/java/io/permit/sdk/PermitContext.java +++ b/src/main/java/io/permit/sdk/PermitContext.java @@ -1,18 +1,41 @@ package io.permit.sdk; +import io.permit.sdk.api.PermitContextChangeError; + /** * The {@code PermitContext} class represents the context for Permit API calls. - * - * A context can be: the entire workspace, a specific project, or a specific environment. - * Most API methods require an environment scope (e.g: in order to create a role you - * need to know in which environment to place it), but some methods can work in higher - * scopes (for example: creating a project can be done with a workspace-level scope). + * + * Since the Permit API hierarchy is deeply nested, it is less convenient to specify + * the full object hierarchy in every request. + * + * For example, in order to list roles, the user needs to specify the (id or key) of the: + * - the org + * - the project + * - then environment + * in which the roles are located under. + * + * Instead, the SDK can "remember" the current context and "auto-complete" the details + * from that context. + * + * We then get this kind of experience: + *
{@code
+ * permit.api.roles.list();
+ * }
+ * + * We can only run this function if the current context already knows the org, project, + * and environment that we want to run under, and that is why in this example the api + * method assumes we are running under an {@link ApiContextLevel#ENVIRONMENT} context. */ public class PermitContext { - private final ApiKeyLevel apiKeyLevel; - private final String org; - private final String project; - private final String environment; + private ApiKeyLevel apiKeyLevel; + private String permittedOrganization; + private String permittedProject; + private String permittedEnviroment; + + private ApiContextLevel contextLevel; + private String org; + private String project; + private String environment; /** * Constructs a new instance of the {@code PermitContext} class with the specified builder. @@ -20,21 +43,74 @@ public class PermitContext { * @param builder The builder used to construct the PermitContext. */ public PermitContext(Builder builder) { - this.apiKeyLevel = builder.apiKeyLevel; + this.saveApiKeyAccessibleScope(builder.org, builder.project, builder.environment); + this.contextLevel = builder.contextLevel; this.org = builder.org; this.project = builder.project; this.environment = builder.environment; } + public PermitContext() { + // access level + this.apiKeyLevel = ApiKeyLevel.WAIT_FOR_INIT; + this.permittedOrganization = null; + this.permittedProject = null; + this.permittedEnviroment = null; + + // known context + this.contextLevel = ApiContextLevel.WAIT_FOR_INIT; + this.org = null; + this.project = null; + this.environment = null; + } + + private void saveApiKeyAccessibleScope(String org, String project, String environment) { + // Do not call this method directly! + permittedOrganization = org; // cannot be null + + if (project != null && environment != null) { + permittedProject = project; + permittedEnviroment = environment; + apiKeyLevel = ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY; + } else if (project != null) { + permittedProject = project; + permittedEnviroment = null; + apiKeyLevel = ApiKeyLevel.PROJECT_LEVEL_API_KEY; + } else { + permittedProject = null; + permittedEnviroment = null; + apiKeyLevel = ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY; + } + } + /** - * Returns the API key level associated with the Permit context. + * Returns the access level of the API key used by the SDK. * - * @return The API key level. + * @deprecated replaced with {@link PermitContext#getPermittedAccessLevel} + * @return The API key access level. */ public ApiKeyLevel getApiKeyLevel() { return apiKeyLevel; } + /** + * Returns the access level of the API key used by the SDK. + * + * @return The API key access level. + */ + public ApiKeyLevel getPermittedAccessLevel() { + return apiKeyLevel; + } + + /** + * Returns the current SDK context level. + * + * @return the context level. + */ + public ApiContextLevel getContextLevel() { + return contextLevel; + } + /** * Returns the organization (workspace) associated with the Permit context. * @@ -62,11 +138,86 @@ public String getEnvironment() { return environment; } + /** + * Sets the current context of the SDK to a specific organization. + * + * @param org The organization uuid. + * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions. + */ + public void setOrganizationLevelContext(String org) throws PermitContextChangeError { + verifyCanAccessOrg(org); + this.contextLevel = ApiContextLevel.ORGANIZATION; + this.org = org; + this.project = null; + this.environment = null; + } + + /** + * Sets the current context of the SDK to a specific project within an organization. + * + * @param org The organization uuid. + * @param project The project uuid. + * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions. + */ + public void setProjectLevelContext(String org, String project) throws PermitContextChangeError { + verifyCanAccessProject(org, project); + this.contextLevel = ApiContextLevel.PROJECT; + this.org = org; + this.project = project; + this.environment = null; + } + + /** + * Sets the current context of the SDK to a specific environment within an organization and project. + * + * @param org The organization uuid. + * @param project The project uuid. + * @param environment The environment uuid. + * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions. + */ + public void setEnvironmentLevelContext(String org, String project, String environment) throws PermitContextChangeError { + verifyCanAccessEnvironment(org, project, environment); + this.contextLevel = ApiContextLevel.ENVIRONMENT; + this.org = org; + this.project = project; + this.environment = environment; + } + + private void verifyCanAccessOrg(String org) throws PermitContextChangeError { + if (!org.equals(permittedOrganization)) { + throw new PermitContextChangeError( + "You cannot set an SDK context with org '" + org + + "' due to insufficient API Key permissions" + ); + } + } + + private void verifyCanAccessProject(String org, String project) throws PermitContextChangeError { + verifyCanAccessOrg(org); + if (permittedProject != null && !project.equals(permittedProject)) { + throw new PermitContextChangeError( + "You cannot set an SDK context with project '" + project + + "' due to insufficient API Key permissions" + ); + } + } + + private void verifyCanAccessEnvironment(String org, String project, String environment) throws PermitContextChangeError { + verifyCanAccessProject(org, project); + if (permittedEnviroment != null && !environment.equals(permittedEnviroment)) { + throw new PermitContextChangeError( + "You cannot set an SDK context with environment '" + environment + + "' due to insufficient API Key permissions" + ); + } + } + /** * The {@code Builder} class provides a builder interface for constructing {@code PermitContext} objects. */ public static class Builder { - private ApiKeyLevel apiKeyLevel; + + private ApiContextLevel contextLevel; private String org; private String project; private String environment; @@ -78,7 +229,7 @@ public static class Builder { * context will be stored in the SDK configuration for future API calls. */ public Builder() { - this.apiKeyLevel = ApiKeyLevel.WAIT_FOR_INIT; + this.contextLevel = ApiContextLevel.WAIT_FOR_INIT; this.org = null; this.project = null; this.environment = null; @@ -93,10 +244,10 @@ public Builder() { * @return The updated {@code Builder} object. */ public Builder withOrganization(String org) { + this.contextLevel = ApiContextLevel.ORGANIZATION; this.org = org; this.project = null; this.environment = null; - this.apiKeyLevel = ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY; return this; } @@ -110,10 +261,10 @@ public Builder withOrganization(String org) { * @return The updated {@code Builder} object. */ public Builder withProject(String org, String project) { + this.contextLevel = ApiContextLevel.PROJECT; this.org = org; this.project = project; this.environment = null; - this.apiKeyLevel = ApiKeyLevel.PROJECT_LEVEL_API_KEY; return this; } @@ -127,10 +278,10 @@ public Builder withProject(String org, String project) { * @return The updated {@code Builder} object. */ public Builder withEnvironment(String org, String project, String environment) { + this.contextLevel = ApiContextLevel.ENVIRONMENT; this.org = org; this.project = project; this.environment = environment; - this.apiKeyLevel = ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY; return this; } diff --git a/src/main/java/io/permit/sdk/api/BaseApi.java b/src/main/java/io/permit/sdk/api/BaseApi.java index 3258305..8f23b62 100644 --- a/src/main/java/io/permit/sdk/api/BaseApi.java +++ b/src/main/java/io/permit/sdk/api/BaseApi.java @@ -2,16 +2,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import io.permit.sdk.ApiContextLevel; import io.permit.sdk.ApiKeyLevel; import io.permit.sdk.PermitConfig; import io.permit.sdk.PermitContext; import io.permit.sdk.openapi.models.APIKeyScopeRead; -import io.permit.sdk.openapi.models.RoleCreate; -import io.permit.sdk.openapi.models.RoleRead; import okhttp3.*; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; @@ -31,6 +29,7 @@ protected BaseApi(OkHttpClient client, PermitConfig config, Logger logger) { this.headers = new Headers.Builder() .add("Content-Type", "application/json") .add("Authorization", String.format("Bearer %s", this.config.getToken())) + .add("X-Permit-SDK-Version", String.format("java:%s", this.config.version)) .build(); } @@ -138,30 +137,39 @@ private void setContextFromApiKey() throws IOException, PermitContextError { } } - protected void ensureContext(ApiKeyLevel callLevel) throws PermitContextError, IOException { + protected void ensureAccessLevel(ApiKeyLevel requiredAccessLevel) throws PermitContextError, IOException { // set context if not already set - if (this.config.getContext().getApiKeyLevel() == ApiKeyLevel.WAIT_FOR_INIT) { + // Should only happen once in the lifetime of the SDK + if (config.getContext().getContextLevel() == ApiContextLevel.WAIT_FOR_INIT || + config.getContext().getPermittedAccessLevel() == ApiKeyLevel.WAIT_FOR_INIT) { setContextFromApiKey(); } - // verify context matches requested call level - if (callLevel == ApiKeyLevel.PROJECT_LEVEL_API_KEY && this.config.getContext().getProject() == null) { - throw new PermitContextError( - "You're trying to use an SDK method that's specific to a project," + - "but you haven't set the current project in your client's context yet," + - "or you are using an organization level API key." + - "Please set the context to a specific" + - "project using `permit.set_context()` method." - ); + if (requiredAccessLevel != config.getContext().getPermittedAccessLevel()) { + if (requiredAccessLevel.getValue() < config.getContext().getPermittedAccessLevel().getValue()) { + throw new PermitContextError( + "You're trying to use an SDK method that requires an API Key with access level: " + + requiredAccessLevel + ", however the SDK is running with an API key with level " + + config.getContext().getPermittedAccessLevel() + "." + ); + } + } + } + + + protected void ensureContext(ApiContextLevel requiredContext) throws PermitContextError, IOException { + // set context if not already set + // Should only happen once in the lifetime of the SDK + if (config.getContext().getContextLevel() == ApiContextLevel.WAIT_FOR_INIT || + config.getContext().getPermittedAccessLevel() == ApiKeyLevel.WAIT_FOR_INIT) { + setContextFromApiKey(); } - if (callLevel == ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY && this.config.getContext().getEnvironment() == null) { + if (config.getContext().getContextLevel().getValue() < requiredContext.getValue()) { throw new PermitContextError( - "You're trying to use an SDK method that's specific to an environment," + - "but you haven't set the current environment in your client's context yet," + - "or you are using an organization/project level API key." + - "Please set the context to a specific" + - "environment using `permit.set_context()` method." + "You're trying to use an SDK method that requires an API context of " + requiredContext + + ", however the SDK is running in a less specific context level: " + + config.getContext().getContextLevel() + "." ); } } diff --git a/src/main/java/io/permit/sdk/api/ConditionSetRulesApi.java b/src/main/java/io/permit/sdk/api/ConditionSetRulesApi.java index f830525..1287705 100644 --- a/src/main/java/io/permit/sdk/api/ConditionSetRulesApi.java +++ b/src/main/java/io/permit/sdk/api/ConditionSetRulesApi.java @@ -1,6 +1,8 @@ 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.*; @@ -57,6 +59,16 @@ interface IConditionSetRulesApi { */ ConditionSetRuleRead[] list(String userSetKey, String permissionKey, String resourceSetKey) throws IOException, PermitApiError, PermitContextError; + /** + * Retrieves all the condition set rules (no filters) with default pagination + * + * @return An array of {@link ConditionSetRuleRead} objects. + * @throws IOException If an I/O error occurs while sending the 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. + */ + ConditionSetRuleRead[] list() throws IOException, PermitApiError, PermitContextError; + /** * Creates a new condition set rule. * @@ -126,7 +138,8 @@ private String getConditionSetRulesUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRuleRead[] list(String userSetKey, String permissionKey, String resourceSetKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetRulesUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); if (userSetKey != null) { @@ -188,6 +201,19 @@ public ConditionSetRuleRead[] list(String userSetKey, String permissionKey, Stri return this.list(userSetKey, permissionKey, resourceSetKey, 1); } + /** + * Retrieves all the condition set rules (no filters) with default pagination + * + * @return An array of {@link ConditionSetRuleRead} objects. + * @throws IOException If an I/O error occurs while sending the 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 ConditionSetRuleRead[] list() throws IOException, PermitApiError, PermitContextError { + return this.list(null, null, null); + } + /** * Creates a new condition set rule. * @@ -198,7 +224,8 @@ public ConditionSetRuleRead[] list(String userSetKey, String permissionKey, Stri * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRuleRead create(ConditionSetRuleCreate rule) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetRulesUrl(""); RequestBody jsonBody = getJsonRequestBody(rule); @@ -208,7 +235,8 @@ public ConditionSetRuleRead create(ConditionSetRuleCreate rule) throws IOExcepti .post(jsonBody) ); - return this.callApiAndParseJson(request, ConditionSetRuleRead.class); + ConditionSetRuleRead[] createdRuleArray = this.callApiAndParseJson(request, ConditionSetRuleRead[].class); + return createdRuleArray[0]; } /** @@ -220,7 +248,8 @@ public ConditionSetRuleRead create(ConditionSetRuleCreate rule) throws IOExcepti * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(ConditionSetRuleRemove rule) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetRulesUrl(""); RequestBody jsonBody = getJsonRequestBody(rule); diff --git a/src/main/java/io/permit/sdk/api/ConditionSetsApi.java b/src/main/java/io/permit/sdk/api/ConditionSetsApi.java index a537c62..1de98ed 100644 --- a/src/main/java/io/permit/sdk/api/ConditionSetsApi.java +++ b/src/main/java/io/permit/sdk/api/ConditionSetsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -66,7 +67,8 @@ private String getConditionSetsUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetsUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -121,7 +123,8 @@ public ConditionSetRead[] list() throws IOException, PermitApiError, PermitConte * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRead get(String conditionSetKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetsUrl(String.format("/%s", conditionSetKey)); Request request = buildRequest( new Request.Builder() @@ -168,7 +171,8 @@ public ConditionSetRead getById(UUID conditionSetId) throws IOException, PermitA * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRead create(ConditionSetCreate conditionSetData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetsUrl(""); RequestBody jsonBody = getJsonRequestBody(conditionSetData); @@ -192,7 +196,8 @@ public ConditionSetRead create(ConditionSetCreate conditionSetData) throws IOExc * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ConditionSetRead update(String conditionSetKey, ConditionSetUpdate conditionSetData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetsUrl(String.format("/%s", conditionSetKey)); RequestBody jsonBody = getJsonRequestBody(conditionSetData); @@ -214,7 +219,8 @@ public ConditionSetRead update(String conditionSetKey, ConditionSetUpdate condit * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String conditionSetKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getConditionSetsUrl(String.format("/%s", conditionSetKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/ElementsApi.java b/src/main/java/io/permit/sdk/api/ElementsApi.java index f233b79..27d1bd6 100644 --- a/src/main/java/io/permit/sdk/api/ElementsApi.java +++ b/src/main/java/io/permit/sdk/api/ElementsApi.java @@ -1,6 +1,7 @@ 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.api.models.*; @@ -34,7 +35,8 @@ public ElementsApi(OkHttpClient client, PermitConfig config) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EmbeddedLoginRequestOutput loginAs(String userKey, String tenantKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = buildUrl("/v2/auth/elements_login_as"); RequestBody jsonBody = getJsonRequestBody(new UserLoginRequestInput(userKey, tenantKey)); diff --git a/src/main/java/io/permit/sdk/api/EnvironmentsApi.java b/src/main/java/io/permit/sdk/api/EnvironmentsApi.java index d017471..34b383f 100644 --- a/src/main/java/io/permit/sdk/api/EnvironmentsApi.java +++ b/src/main/java/io/permit/sdk/api/EnvironmentsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -69,7 +70,8 @@ private String getEnvironmentsUrl(String projectKey, String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EnvironmentRead[] list(String projectKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey, ""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -127,7 +129,8 @@ public EnvironmentRead[] list(String projectKey) throws IOException, PermitApiEr * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EnvironmentRead get(String projectKey, String environmentKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey, String.format("/%s", environmentKey)); Request request = buildRequest( new Request.Builder() @@ -178,7 +181,8 @@ public EnvironmentRead getById(UUID projectId, UUID environmentId) throws IOExce * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EnvironmentRead create(String projectKey, EnvironmentCreate environmentData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey,""); RequestBody jsonBody = getJsonRequestBody(environmentData); @@ -203,7 +207,8 @@ public EnvironmentRead create(String projectKey, EnvironmentCreate environmentDa * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EnvironmentRead update(String projectKey, String environmentKey, EnvironmentUpdate environmentData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey, String.format("/%s", environmentKey)); RequestBody jsonBody = getJsonRequestBody(environmentData); @@ -233,7 +238,8 @@ public EnvironmentRead update(String projectKey, String environmentKey, Environm * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public EnvironmentRead copy(String projectKey, String environmentKey, EnvironmentCopy copyParams) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey, String.format("/%s/copy", environmentKey)); RequestBody jsonBody = getJsonRequestBody(copyParams); @@ -256,7 +262,8 @@ public EnvironmentRead copy(String projectKey, String environmentKey, Environmen * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String projectKey, String environmentKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getEnvironmentsUrl(projectKey, String.format("/%s", environmentKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/PermitContextChangeError.java b/src/main/java/io/permit/sdk/api/PermitContextChangeError.java new file mode 100644 index 0000000..15d1ab1 --- /dev/null +++ b/src/main/java/io/permit/sdk/api/PermitContextChangeError.java @@ -0,0 +1,13 @@ +package io.permit.sdk.api; + +/** + * The {@code PermitContextChangeError} will be thrown when the user is trying to set the + * SDK context to an object that the current API Key cannot access (and if allowed, + * such API calls will result in a 401 Unauthorized response). Instead, the SDK throws + * this exception. + */ +public class PermitContextChangeError extends Exception { + public PermitContextChangeError(String message) { + super(message); + } +} diff --git a/src/main/java/io/permit/sdk/api/PermitContextError.java b/src/main/java/io/permit/sdk/api/PermitContextError.java index 778c34a..7fe9530 100644 --- a/src/main/java/io/permit/sdk/api/PermitContextError.java +++ b/src/main/java/io/permit/sdk/api/PermitContextError.java @@ -1,5 +1,12 @@ package io.permit.sdk.api; +/** + * The {@code PermitContextError} class represents an error that occurs when an API method + * is called with insufficient context (not knowing in what environment, project or + * organization the API call is being made). + * Part of the input for each API method is provided implicitly via the SDK context. + * If the context is missing some data required for a method - the api call will fail. + */ public class PermitContextError extends Exception { public PermitContextError(String message) { super(message); diff --git a/src/main/java/io/permit/sdk/api/ProjectsApi.java b/src/main/java/io/permit/sdk/api/ProjectsApi.java index b1fe436..1b00c9f 100644 --- a/src/main/java/io/permit/sdk/api/ProjectsApi.java +++ b/src/main/java/io/permit/sdk/api/ProjectsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -66,7 +67,8 @@ private String getProjectsUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ProjectRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getProjectsUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -121,7 +123,8 @@ public ProjectRead[] list() throws IOException, PermitApiError, PermitContextErr * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ProjectRead get(String projectKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getProjectsUrl(String.format("/%s", projectKey)); Request request = buildRequest( new Request.Builder() @@ -169,7 +172,8 @@ public ProjectRead getById(UUID projectId) throws IOException, PermitApiError, P * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ProjectRead create(ProjectCreate projectData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getProjectsUrl(""); RequestBody jsonBody = getJsonRequestBody(projectData); @@ -193,7 +197,8 @@ public ProjectRead create(ProjectCreate projectData) throws IOException, PermitA * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ProjectRead update(String projectKey, ProjectUpdate projectData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getProjectsUrl(String.format("/%s", projectKey)); RequestBody jsonBody = getJsonRequestBody(projectData); @@ -215,7 +220,8 @@ public ProjectRead update(String projectKey, ProjectUpdate projectData) throws I * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String projectKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ORGANIZATION_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.PROJECT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ORGANIZATION); String url = getProjectsUrl(String.format("/%s", projectKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/ResourceActionGroupsApi.java b/src/main/java/io/permit/sdk/api/ResourceActionGroupsApi.java index 6f615e6..4445947 100644 --- a/src/main/java/io/permit/sdk/api/ResourceActionGroupsApi.java +++ b/src/main/java/io/permit/sdk/api/ResourceActionGroupsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -69,7 +70,8 @@ private String getResourceActionGroupsUrl(String resourceKey, String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionGroupRead[] list(String resourceKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionGroupsUrl(resourceKey, ""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -127,7 +129,8 @@ public ResourceActionGroupRead[] list(String resourceKey) throws IOException, Pe * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionGroupRead get(String resourceKey, String groupKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionGroupsUrl(resourceKey, String.format("/%s", groupKey)); Request request = buildRequest( new Request.Builder() @@ -178,7 +181,8 @@ public ResourceActionGroupRead getById(UUID resourceId, UUID groupId) throws IOE * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionGroupRead create(String resourceKey, ResourceActionGroupCreate groupData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionGroupsUrl(resourceKey,""); RequestBody jsonBody = getJsonRequestBody(groupData); @@ -201,7 +205,8 @@ public ResourceActionGroupRead create(String resourceKey, ResourceActionGroupCre * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String resourceKey, String groupKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionGroupsUrl(resourceKey, String.format("/%s", groupKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/ResourceActionsApi.java b/src/main/java/io/permit/sdk/api/ResourceActionsApi.java index 95f2c53..9202b7b 100644 --- a/src/main/java/io/permit/sdk/api/ResourceActionsApi.java +++ b/src/main/java/io/permit/sdk/api/ResourceActionsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -70,7 +71,8 @@ private String getResourceActionsUrl(String resourceKey, String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionRead[] list(String resourceKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionsUrl(resourceKey, ""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -128,7 +130,8 @@ public ResourceActionRead[] list(String resourceKey) throws IOException, PermitA * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionRead get(String resourceKey, String actionKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionsUrl(resourceKey, String.format("/%s", actionKey)); Request request = buildRequest( new Request.Builder() @@ -179,7 +182,8 @@ public ResourceActionRead getById(UUID resourceId, UUID actionId) throws IOExcep * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionRead create(String resourceKey, ResourceActionCreate actionData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionsUrl(resourceKey,""); RequestBody jsonBody = getJsonRequestBody(actionData); @@ -204,7 +208,8 @@ public ResourceActionRead create(String resourceKey, ResourceActionCreate action * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceActionRead update(String resourceKey, String actionKey, ResourceActionUpdate actionData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionsUrl(resourceKey, String.format("/%s", actionKey)); RequestBody jsonBody = getJsonRequestBody(actionData); @@ -227,7 +232,8 @@ public ResourceActionRead update(String resourceKey, String actionKey, ResourceA * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String resourceKey, String actionKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceActionsUrl(resourceKey, String.format("/%s", actionKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/ResourceAttributesApi.java b/src/main/java/io/permit/sdk/api/ResourceAttributesApi.java index 4e67634..6bebdd4 100644 --- a/src/main/java/io/permit/sdk/api/ResourceAttributesApi.java +++ b/src/main/java/io/permit/sdk/api/ResourceAttributesApi.java @@ -1,6 +1,7 @@ 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.*; @@ -74,7 +75,8 @@ private String getResourceAttributesUrl(String resourceKey, String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceAttributeRead[] list(String resourceKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceAttributesUrl(resourceKey, ""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -132,7 +134,8 @@ public ResourceAttributeRead[] list(String resourceKey) throws IOException, Perm * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceAttributeRead get(String resourceKey, String attributeKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceAttributesUrl(resourceKey, String.format("/%s", attributeKey)); Request request = buildRequest( new Request.Builder() @@ -184,7 +187,8 @@ public ResourceAttributeRead getById(UUID resourceId, UUID attributeId) throws I * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceAttributeRead create(String resourceKey, ResourceAttributeCreate attributeData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceAttributesUrl(resourceKey,""); RequestBody jsonBody = getJsonRequestBody(attributeData); @@ -209,7 +213,8 @@ public ResourceAttributeRead create(String resourceKey, ResourceAttributeCreate * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceAttributeRead update(String resourceKey, String attributeKey, ResourceAttributeUpdate attributeData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceAttributesUrl(resourceKey, String.format("/%s", attributeKey)); RequestBody jsonBody = getJsonRequestBody(attributeData); @@ -232,7 +237,8 @@ public ResourceAttributeRead update(String resourceKey, String attributeKey, Res * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String resourceKey, String attributeKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourceAttributesUrl(resourceKey, String.format("/%s", attributeKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/ResourcesApi.java b/src/main/java/io/permit/sdk/api/ResourcesApi.java index 0152193..eec3c30 100644 --- a/src/main/java/io/permit/sdk/api/ResourcesApi.java +++ b/src/main/java/io/permit/sdk/api/ResourcesApi.java @@ -1,6 +1,7 @@ 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.*; @@ -68,7 +69,8 @@ private String getResourcesUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -123,7 +125,8 @@ public ResourceRead[] list() throws IOException, PermitApiError, PermitContextEr * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceRead get(String resourceKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(String.format("/%s", resourceKey)); Request request = buildRequest( new Request.Builder() @@ -171,7 +174,8 @@ public ResourceRead getById(UUID resourceId) throws IOException, PermitApiError, * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceRead create(ResourceCreate resourceData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(""); RequestBody jsonBody = getJsonRequestBody(resourceData); @@ -195,7 +199,8 @@ public ResourceRead create(ResourceCreate resourceData) throws IOException, Perm * @throws PermitContextError * If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceRead replace(String resourceKey, ResourceReplace resourceData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(String.format("/%s", resourceKey)); RequestBody jsonBody = getJsonRequestBody(resourceData); @@ -219,7 +224,8 @@ public ResourceRead replace(String resourceKey, ResourceReplace resourceData) th * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public ResourceRead update(String resourceKey, ResourceUpdate resourceData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(String.format("/%s", resourceKey)); RequestBody jsonBody = getJsonRequestBody(resourceData); @@ -241,7 +247,8 @@ public ResourceRead update(String resourceKey, ResourceUpdate resourceData) thro * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String resourceKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getResourcesUrl(String.format("/%s", resourceKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/RoleAssignmentsApi.java b/src/main/java/io/permit/sdk/api/RoleAssignmentsApi.java index 22825f6..8976da5 100644 --- a/src/main/java/io/permit/sdk/api/RoleAssignmentsApi.java +++ b/src/main/java/io/permit/sdk/api/RoleAssignmentsApi.java @@ -1,6 +1,7 @@ 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.*; @@ -66,7 +67,8 @@ private String getRoleAssignmentsUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleAssignmentRead[] list(String userKey, String tenantKey, String roleKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRoleAssignmentsUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); if (userKey != null) { @@ -139,7 +141,8 @@ public RoleAssignmentRead[] list(String userKey, String tenantKey, String roleKe * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleAssignmentRead assign(RoleAssignmentCreate assignment) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRoleAssignmentsUrl(""); RequestBody jsonBody = getJsonRequestBody(assignment); @@ -164,7 +167,8 @@ public RoleAssignmentRead assign(RoleAssignmentCreate assignment) throws IOExcep * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void unassign(RoleAssignmentRemove unassignment) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRoleAssignmentsUrl(""); RequestBody jsonBody = getJsonRequestBody(unassignment); @@ -190,7 +194,8 @@ public void unassign(RoleAssignmentRemove unassignment) throws IOException, Perm * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public BulkRoleAssignmentReport bulkAssign(List assignments) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRoleAssignmentsUrl("/bulk"); RequestBody jsonBody = getJsonRequestBody(assignments); @@ -214,7 +219,8 @@ public BulkRoleAssignmentReport bulkAssign(List assignment * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public BulkRoleUnassignmentReport bulkUnassign(List unassignments) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRoleAssignmentsUrl("/bulk"); RequestBody jsonBody = getJsonRequestBody(unassignments); diff --git a/src/main/java/io/permit/sdk/api/RolesApi.java b/src/main/java/io/permit/sdk/api/RolesApi.java index 0b81e68..f840f5e 100644 --- a/src/main/java/io/permit/sdk/api/RolesApi.java +++ b/src/main/java/io/permit/sdk/api/RolesApi.java @@ -1,6 +1,7 @@ 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.*; @@ -68,7 +69,8 @@ private String getRolesUrl(String url) { * @throws PermitContextError If the configured SDK context {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -123,7 +125,8 @@ public RoleRead[] list() throws IOException, PermitApiError, PermitContextError * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead get(String roleKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(String.format("/%s", roleKey)); Request request = buildRequest( new Request.Builder() @@ -171,7 +174,8 @@ public RoleRead getById(UUID roleId) throws IOException, PermitApiError, PermitC * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead create(RoleCreate roleData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(""); RequestBody jsonBody = getJsonRequestBody(roleData); @@ -195,7 +199,8 @@ public RoleRead create(RoleCreate roleData) throws IOException, PermitApiError, * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead update(String roleKey, RoleUpdate roleData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(String.format("/%s", roleKey)); RequestBody jsonBody = getJsonRequestBody(roleData); @@ -217,7 +222,8 @@ public RoleRead update(String roleKey, RoleUpdate roleData) throws IOException, * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String roleKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(String.format("/%s", roleKey)); Request request = buildRequest( new Request.Builder() @@ -241,7 +247,8 @@ public void delete(String roleKey) throws IOException, PermitApiError, PermitCon * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead assignPermissions(String roleKey, ArrayList permissions) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(String.format("/%s/permissions", roleKey)); RequestBody jsonBody = getJsonRequestBody(new AddRolePermissions(permissions)); @@ -265,7 +272,8 @@ public RoleRead assignPermissions(String roleKey, ArrayList permissions) * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleRead removePermissions(String roleKey, ArrayList permissions) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getRolesUrl(String.format("/%s/permissions", roleKey)); RequestBody jsonBody = getJsonRequestBody(new RemoveRolePermissions(permissions)); diff --git a/src/main/java/io/permit/sdk/api/TenantsApi.java b/src/main/java/io/permit/sdk/api/TenantsApi.java index 22de999..7f1b5c6 100644 --- a/src/main/java/io/permit/sdk/api/TenantsApi.java +++ b/src/main/java/io/permit/sdk/api/TenantsApi.java @@ -1,6 +1,7 @@ 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.api.models.CreateOrUpdateResult; @@ -69,7 +70,8 @@ private String getTenantsUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public TenantRead[] list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -126,7 +128,8 @@ public TenantRead[] list() throws IOException, PermitApiError, PermitContextErro * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public PaginatedResultUserRead listTenantUsers(String tenantKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(String.format("/%s/users", tenantKey)); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -180,7 +183,8 @@ public PaginatedResultUserRead listTenantUsers(String tenantKey) throws IOExcept * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public TenantRead get(String tenantKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(String.format("/%s", tenantKey)); Request request = buildRequest( new Request.Builder() @@ -227,7 +231,8 @@ public TenantRead getById(UUID tenantId) throws IOException, PermitApiError, Per * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public TenantRead create(TenantCreate tenantData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(""); RequestBody jsonBody = getJsonRequestBody(tenantData); @@ -251,7 +256,8 @@ public TenantRead create(TenantCreate tenantData) throws IOException, PermitApiE * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public TenantRead update(String tenantKey, TenantUpdate tenantData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(String.format("/%s", tenantKey)); RequestBody jsonBody = getJsonRequestBody(tenantData); @@ -273,7 +279,8 @@ public TenantRead update(String tenantKey, TenantUpdate tenantData) throws IOExc * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String tenantKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getTenantsUrl(String.format("/%s", tenantKey)); Request request = buildRequest( new Request.Builder() diff --git a/src/main/java/io/permit/sdk/api/UsersApi.java b/src/main/java/io/permit/sdk/api/UsersApi.java index 2a423f0..740a16d 100644 --- a/src/main/java/io/permit/sdk/api/UsersApi.java +++ b/src/main/java/io/permit/sdk/api/UsersApi.java @@ -1,6 +1,7 @@ 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.api.models.CreateOrUpdateResult; @@ -76,7 +77,8 @@ private String getUsersUrl(String url) { * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public PaginatedResultUserRead list(int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(""); HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder(); Request request = buildRequest( @@ -131,7 +133,8 @@ public PaginatedResultUserRead list() throws IOException, PermitApiError, Permit * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public UserRead get(String userKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s", userKey)); Request request = buildRequest( new Request.Builder() @@ -178,7 +181,8 @@ public UserRead getById(UUID userId) throws IOException, PermitApiError, PermitC * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public UserRead create(UserCreate userData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(""); RequestBody jsonBody = getJsonRequestBody(userData); @@ -202,7 +206,8 @@ public UserRead create(UserCreate userData) throws IOException, PermitApiError, * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public UserRead update(String userKey, UserUpdate userData) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s", userKey)); RequestBody jsonBody = getJsonRequestBody(userData); @@ -233,7 +238,8 @@ public CreateOrUpdateResult sync(UserCreate userData) throws IOExcepti ); } - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s", userData.key)); // TODO: fix url to PUT /v2/.../users RequestBody jsonBody = getJsonRequestBody(userData); @@ -288,7 +294,8 @@ public CreateOrUpdateResult sync(User user) throws IOException, Permit * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void delete(String userKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s", userKey)); Request request = buildRequest( new Request.Builder() @@ -313,7 +320,8 @@ public void delete(String userKey) throws IOException, PermitApiError, PermitCon * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleAssignmentRead assignRole(String userKey, String roleKey, String tenantKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s/roles", userKey)); RequestBody jsonBody = getJsonRequestBody(new UserRoleCreate(roleKey, tenantKey)); @@ -337,7 +345,8 @@ public RoleAssignmentRead assignRole(String userKey, String roleKey, String tena * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public void unassignRole(String userKey, String roleKey, String tenantKey) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = getUsersUrl(String.format("/%s/roles", userKey)); RequestBody jsonBody = getJsonRequestBody(new UserRoleRemove(roleKey, tenantKey)); @@ -365,7 +374,8 @@ public void unassignRole(String userKey, String roleKey, String tenantKey) throw * @throws PermitContextError If the configured {@link io.permit.sdk.PermitContext} does not match the required endpoint context. */ public RoleAssignmentRead[] getAssignedRoles(@NotNull String userKey, String tenantKey, int page, int perPage) throws IOException, PermitApiError, PermitContextError { - ensureContext(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureAccessLevel(ApiKeyLevel.ENVIRONMENT_LEVEL_API_KEY); + ensureContext(ApiContextLevel.ENVIRONMENT); String url = buildUrl( String.format( "/v2/facts/%s/%s/role_assignments", diff --git a/src/main/java/io/permit/sdk/enforcement/Enforcer.java b/src/main/java/io/permit/sdk/enforcement/Enforcer.java index 44b1562..87d0324 100644 --- a/src/main/java/io/permit/sdk/enforcement/Enforcer.java +++ b/src/main/java/io/permit/sdk/enforcement/Enforcer.java @@ -117,6 +117,7 @@ public boolean check(User user, String action, Resource resource, Context contex .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()) { diff --git a/src/test/java/io/permit/sdk/RolesApiE2ETest.java b/src/test/java/io/permit/sdk/RolesApiE2ETest.java deleted file mode 100644 index 5ee295c..0000000 --- a/src/test/java/io/permit/sdk/RolesApiE2ETest.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.permit.sdk; - -import com.google.gson.Gson; -import com.google.gson.internal.LinkedTreeMap; -import io.permit.sdk.api.PermitApiError; -import io.permit.sdk.api.PermitContextError; -import io.permit.sdk.openapi.models.RoleCreate; -import io.permit.sdk.openapi.models.RoleRead; -import io.permit.sdk.openapi.models.RoleUpdate; -import org.junit.jupiter.api.Test; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * this e2e test should run against a clean permit environment. - * if the environment contains any objects the test will fail. - * eventually we want to create an environment programmatically - * and then extract the api key and start the test. - */ -public class RolesApiE2ETest extends PermitE2ETestBase { - @Test - void testRolesApi() { - // init the client - Permit permit = new Permit(this.config); - Gson gson = new Gson(); - - // roles lifecycle - try { - // list - RoleRead[] emptyRoles = permit.api.roles.list(); - assertEquals(emptyRoles.length, 0); - - // create - RoleRead admin = permit.api.roles.create( - new RoleCreate("admin","Admin").withDescription("an admin role") - ); - assertNotNull(admin); - assertEquals(admin.key, "admin"); - assertEquals(admin.name, "Admin"); - assertEquals(admin.description, "an admin role"); - - - RoleRead viewer = permit.api.roles.create( - new RoleCreate("viewer","Viewer").withDescription("an viewer role") - ); - assertNotNull(viewer); - assertEquals(viewer.key, "viewer"); - assertEquals(viewer.name, "Viewer"); - assertEquals(viewer.description, "an viewer role"); - - RoleRead[] roles = permit.api.roles.list(); - assertEquals(roles.length, 2); - assertEquals(roles[0].key, "admin"); - assertEquals(roles[0].name, "Admin"); - assertEquals(roles[1].key, "viewer"); - assertEquals(roles[1].name, "Viewer"); - - // get - RoleRead role = permit.api.roles.get("admin"); - assertNotNull(role); - assertEquals(role.key, "admin"); - assertEquals(role.name, "Admin"); - - // get 404 no such role - PermitApiError notFoundError = assertThrows(PermitApiError.class, () -> { - permit.api.roles.get("editor"); - }); - assertEquals(notFoundError.getMessage(), "Got error status code: 404"); - assertEquals(notFoundError.getResponseCode(), 404); - LinkedTreeMap error = notFoundError.getErrorObject(); - assertEquals(error.get("error_code"), "NOT_FOUND"); - assertTrue(error.get("message").toString().startsWith("The requested data could not be found")); - - // delete - try { - permit.api.roles.delete("admin"); - } catch (PermitApiError e) { - fail("got error: " + e); - } - - roles = permit.api.roles.list(); - assertEquals(roles.length, 1); - assertEquals(roles[0].key, "viewer"); - assertEquals(roles[0].name, "Viewer"); - assertEquals(roles[0].description, "an viewer role"); - - // update - permit.api.roles.update("viewer", new RoleUpdate().withDescription("new description")); - - roles = permit.api.roles.list(); - assertEquals(roles.length, 1); - assertEquals(roles[0].key, "viewer"); - assertEquals(roles[0].name, "Viewer"); - assertEquals(roles[0].description, "new description"); - - // delete - try { - permit.api.roles.delete("viewer"); - } catch (PermitApiError e) { - fail("got error: " + e); - } - - roles = permit.api.roles.list(); - assertEquals(roles.length, 0); - - // we already deleted this - PermitApiError exception = assertThrows(PermitApiError.class, () -> { - permit.api.roles.delete("viewer"); - }); - assertEquals(exception.getResponseCode(), 404); - } catch (IOException | PermitApiError | PermitContextError e) { - fail("got error: " + e); - } - } -} diff --git a/src/test/java/io/permit/sdk/PermissionCheckE2ETest.java b/src/test/java/io/permit/sdk/e2e/RbacE2ETest.java similarity index 95% rename from src/test/java/io/permit/sdk/PermissionCheckE2ETest.java rename to src/test/java/io/permit/sdk/e2e/RbacE2ETest.java index 8f8771e..57c380a 100644 --- a/src/test/java/io/permit/sdk/PermissionCheckE2ETest.java +++ b/src/test/java/io/permit/sdk/e2e/RbacE2ETest.java @@ -1,10 +1,9 @@ -package io.permit.sdk; +package io.permit.sdk.e2e; -import com.google.gson.Gson; -import com.google.gson.internal.LinkedTreeMap; +import io.permit.sdk.PermitE2ETestBase; import io.permit.sdk.api.PermitApiError; import io.permit.sdk.api.PermitContextError; -import io.permit.sdk.api.UsersApi; +import io.permit.sdk.Permit; import io.permit.sdk.api.models.CreateOrUpdateResult; import io.permit.sdk.enforcement.Resource; import io.permit.sdk.enforcement.User; @@ -26,8 +25,8 @@ * eventually we want to create an environment programmatically * and then extract the api key and start the test. */ -public class PermissionCheckE2ETest extends PermitE2ETestBase { - private final Logger logger = LoggerFactory.getLogger(PermissionCheckE2ETest.class); +public class RbacE2ETest extends PermitE2ETestBase { + private final Logger logger = LoggerFactory.getLogger(RbacE2ETest.class); @Test void testPermissionCheckRBAC() { @@ -135,7 +134,7 @@ void testPermissionCheckRBAC() { .build(); CreateOrUpdateResult result = permit.api.users.sync(userInput); UserRead user = result.getResult(); - assertTrue(result.wasCreated()); + // assertTrue(result.wasCreated()); assertEquals(user.key, "auth0|elon"); assertEquals(user.email, "elonmusk@tesla.com"); assertEquals(user.firstName, "Elon"); @@ -153,13 +152,14 @@ void testPermissionCheckRBAC() { assertEquals(ra.role, viewer.key); assertEquals(ra.tenant, tenant.key); - logger.info("sleeping 2 seconds before permit.check() to make sure all writes propagated from cloud to PDP"); - Thread.sleep(2000); + logger.info("sleeping 20 seconds before permit.check() to make sure all writes propagated from cloud to PDP"); + Thread.sleep(20000); // positive permission check (will be true because elon is a viewer, and a viewer can read a document) logger.info("testing positive permission check"); HashMap resourceAttrs = new HashMap(); resourceAttrs.put("sdfa", new ArrayList(Arrays.asList("sdf","sdf"))); + assertTrue(permit.check( User.fromString("auth0|elon"), "read", diff --git a/src/test/java/io/permit/sdk/endpoints/ConditionSetsE2ETest.java b/src/test/java/io/permit/sdk/endpoints/ConditionSetsE2ETest.java new file mode 100644 index 0000000..fe98541 --- /dev/null +++ b/src/test/java/io/permit/sdk/endpoints/ConditionSetsE2ETest.java @@ -0,0 +1,243 @@ +package io.permit.sdk.endpoints; + +import com.google.gson.Gson; +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.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + + +public class ConditionSetsE2ETest extends PermitE2ETestBase { + private static final String DOCUMENT_KEY = "document"; + private static final String USER_RESOURCE_KEY = "__user"; + + private static final String USERSET_KEY = "users_over_thirty"; + + private static final String RESOURCESET_KEY = "private_docs"; + private static ResourceCreate documentData; + private static ConditionSetCreate usersetData; + private static ConditionSetCreate resourcesetData; + private static ConditionSetRuleCreate ruleData; + + private static HashMap getUsersetConditions() { + HashMap ageCondition = new HashMap() {{ + put("greater-than", 30); + }}; + + HashMap> attributeRef = new HashMap<>(); + attributeRef.put("user.age", ageCondition); + + List>> andConditions = new ArrayList<>(); + andConditions.add(attributeRef); + + HashMap conditions = new HashMap<>(); + conditions.put("allOf", andConditions); + + return conditions; + } + + private static HashMap getResourcesetConditions() { + HashMap privateCondition = new HashMap() {{ + put("equals", false); + }}; + + HashMap> attributeRef = new HashMap<>(); + attributeRef.put("resource.private", privateCondition); + + List>> andConditions = new ArrayList<>(); + andConditions.add(attributeRef); + + HashMap conditions = new HashMap<>(); + conditions.put("allOf", andConditions); + + return conditions; + } + + @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()); + actions.put("sign", new ActionBlockEditable()); + + // resource attributes + HashMap attributes = new HashMap<>(); + AttributeBlockEditable privateAttr = new AttributeBlockEditable() + .withType(AttributeType.BOOL) + .withDescription("whether the document is private"); + attributes.put("private", privateAttr); + + // create document resource + documentData = (( + new ResourceCreate("document", "Document", actions) + ) + .withUrn("prn:gdrive:document") + .withDescription("google drive document") + .withAttributes(attributes) + ); + + // condition sets data + usersetData = (( + new ConditionSetCreate(USERSET_KEY, "Users over 30") + ) + .withType(ConditionSetType.USERSET) + .withConditions(getUsersetConditions()) + ); + + resourcesetData = (( + new ConditionSetCreate(RESOURCESET_KEY, "Private Docs") + ) + .withType(ConditionSetType.RESOURCESET) + .withConditions(getResourcesetConditions()) + ); + + ruleData = new ConditionSetRuleCreate(USERSET_KEY, DOCUMENT_KEY + ":sign", RESOURCESET_KEY); + } + + void cleanup() { + Permit permit = new Permit(this.config); + try { + try { + permit.api.conditionSets.delete(USERSET_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of user set: " + USERSET_KEY); + } + try { + permit.api.conditionSets.delete(RESOURCESET_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource set: " + RESOURCESET_KEY); + } + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + DOCUMENT_KEY); + } + } catch (PermitContextError e) { + fail("got error: " + e); + } catch (IOException e) { + fail("got error: " + e); + } + } + + @Test + void testConditionSetsApi() { + // init the client + Permit permit = new Permit(this.config); + Gson gson = new Gson(); + + // roles lifecycle + try { + logger.info("create document with actions"); + ResourceRead document = permit.api.resources.create(documentData); + assertNotNull(document); + assertNotNull(document.id); + assertEquals(document.key, documentData.key); + assertEquals(document.name, documentData.name); + assertEquals(document.description, documentData.description); + assertEquals(document.urn, documentData.urn); + assertEquals(document.actions.size(), 5); + assertEquals(document.attributes.size(), 1); + assertTrue(document.actions.containsKey("create")); + assertTrue(document.actions.containsKey("read")); + assertTrue(document.actions.containsKey("update")); + assertTrue(document.actions.containsKey("delete")); + assertTrue(document.actions.containsKey("sign")); + assertTrue(document.attributes.containsKey("private")); + + logger.info("verify can find new resource in the new list"); + ResourceRead[] resources = permit.api.resources.list(); + assertTrue(Arrays.stream(resources).map(r -> r.key).collect(Collectors.toList()).contains(documentData.key)); + + logger.info("Create User.age attribute"); + try { + permit.api.resourceAttributes.create( + USER_RESOURCE_KEY, + new ResourceAttributeCreate("age", AttributeType.NUMBER) + ); + } catch (PermitApiError e) { + if (e.getResponseCode() != 409) { + fail("got error while creating User.age attribute: " + e); + } + } + + logger.info("Create condition sets"); + ConditionSetRead userset = permit.api.conditionSets.create(usersetData); + assertNotNull(userset); + assertNotNull(userset.id); + assertEquals(userset.key, usersetData.key); + assertEquals(userset.name, usersetData.name); + assertEquals(userset.description, usersetData.description); + + ConditionSetRead resourceset = permit.api.conditionSets.create(resourcesetData.withResourceId(document.id)); + assertNotNull(resourceset); + assertNotNull(resourceset.id); + assertEquals(resourceset.key, resourcesetData.key); + assertEquals(resourceset.name, resourcesetData.name); + assertEquals(resourceset.description, resourcesetData.description); + + logger.info("Getting condition set list"); + ConditionSetRead[] conditionSets = permit.api.conditionSets.list(); + assertTrue(Arrays.stream(conditionSets).map(c -> c.key).collect(Collectors.toList()).contains(USERSET_KEY)); + assertTrue(Arrays.stream(conditionSets).map(c -> c.key).collect(Collectors.toList()).contains(RESOURCESET_KEY)); + + logger.info("Create condition set rules"); + ConditionSetRuleRead rule = permit.api.conditionSetRules.create(ruleData); + assertNotNull(rule); + assertNotNull(rule.id); + assertEquals(rule.userSet, USERSET_KEY); + assertEquals(rule.resourceSet, RESOURCESET_KEY); + assertEquals(rule.permission, DOCUMENT_KEY + ":sign"); + + logger.info("Getting condition set rules list"); + ConditionSetRuleRead[] rules = permit.api.conditionSetRules.list(); + assertEquals(rules.length, 1); + + logger.info("Delete objects..."); + try { + permit.api.conditionSetRules.delete( + new ConditionSetRuleRemove( + rule.userSet, + rule.permission, + rule.resourceSet + ) + ); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.conditionSets.delete(USERSET_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.conditionSets.delete(RESOURCESET_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + + } catch (IOException | PermitApiError | PermitContextError e) { + fail("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 new file mode 100644 index 0000000..71e613b --- /dev/null +++ b/src/test/java/io/permit/sdk/endpoints/ResourcesApiE2ETest.java @@ -0,0 +1,193 @@ +package io.permit.sdk.endpoints; + +import com.google.gson.Gson; +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 ResourcesApiE2ETest extends PermitE2ETestBase { + private static final String DOCUMENT_KEY = "document"; + private static final String FOLDER_KEY = "folder"; + private static ResourceCreate documentData; + private static ResourceCreate folderData; + private static ResourceCreate duplicateData; + + @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()); + + // create document resource + documentData = (( + new ResourceCreate("document", "Document", actions) + ) + .withUrn("prn:gdrive:document") + .withDescription("google drive document") + ); + + // create folder resource + folderData = (( + new ResourceCreate("folder", "Folder", new HashMap<>()) + ) + .withUrn("prn:gdrive:folder") + .withDescription("google drive folder") + ); + + duplicateData = (( + new ResourceCreate("document", "Document2", actions) + ) + .withUrn("prn:gdrive:document2") + .withDescription("google drive document2") + ); + } + + void cleanup() { + Permit permit = new Permit(this.config); + try { + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + DOCUMENT_KEY); + } + try { + permit.api.resources.delete(FOLDER_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + FOLDER_KEY); + } + } catch (PermitContextError e) { + fail("got error: " + e); + } catch (IOException e) { + fail("got error: " + e); + } + } + + @Test + void testResourcesApi() { + // init the client + Permit permit = new Permit(this.config); + Gson gson = new Gson(); + + // roles lifecycle + try { + logger.info("check original resource length"); + int originalLength = permit.api.resources.list().length; + + logger.info("create document with actions"); + ResourceRead document = permit.api.resources.create(documentData); + assertNotNull(document); + assertNotNull(document.id); + assertEquals(document.key, documentData.key); + assertEquals(document.name, documentData.name); + assertEquals(document.description, documentData.description); + assertEquals(document.urn, documentData.urn); + assertEquals(document.actions.size(), 4); + assertTrue(document.actions.containsKey("create")); + assertTrue(document.actions.containsKey("read")); + assertTrue(document.actions.containsKey("update")); + assertTrue(document.actions.containsKey("delete")); + + logger.info("verify number of items increased by 1"); + ResourceRead[] resources = permit.api.resources.list(); + assertEquals(resources.length, originalLength + 1); + + 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"); + PermitApiError notFoundError = assertThrows(PermitApiError.class, () -> { + permit.api.resources.get("group"); + }); + assertEquals(notFoundError.getMessage(), "Got error status code: 404"); + assertEquals(notFoundError.getResponseCode(), 404); + LinkedTreeMap error = notFoundError.getErrorObject(); + assertEquals(error.get("error_code"), "NOT_FOUND"); + assertTrue(error.get("message").toString().startsWith("The requested data could not be found")); + + logger.info("create existing resource -> 409"); + PermitApiError duplicateError = assertThrows(PermitApiError.class, () -> { + permit.api.resources.create(duplicateData); + }); + assertEquals(duplicateError.getResponseCode(), 409); + + logger.info("create empty resource"); + ResourceRead folder = permit.api.resources.create(folderData); + assertNotNull(folder); + assertEquals(folder.key, folderData.key); + assertEquals(folder.name, folderData.name); + assertEquals(folder.description, folderData.description); + assertNotNull(folder.actions); + assertEquals(folder.actions.size(), 0); + + logger.info("verify number of items increased by 1"); + ResourceRead[] resources2 = permit.api.resources.list(); + assertEquals(resources2.length, originalLength + 2); + + logger.info("Update actions"); + permit.api.resources.update( + folder.key, + new ResourceUpdate() + .withDescription("wat") + .withActions( + new HashMap() {{ + put("pick", new ActionBlockEditable()); + }} + ) + ); + + logger.info("get after update"); + ResourceRead updatedFolder = permit.api.resources.get(folderData.key); + assertNotNull(updatedFolder); + assertEquals(updatedFolder.key, folderData.key); + assertEquals(updatedFolder.name, folderData.name); + assertEquals(updatedFolder.description, "wat"); + assertNotNull(updatedFolder.actions); + assertEquals(updatedFolder.actions.size(), 1); + assertTrue(updatedFolder.actions.containsKey("pick")); + + logger.info("Delete objects..."); + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.resources.delete(FOLDER_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + + logger.info("Verify that again we have the initial number of resources"); + ResourceRead[] resources3 = permit.api.resources.list(); + assertEquals(resources3.length, originalLength); + + logger.info("Verify deleted resource cannot be deleted again"); + PermitApiError exception = assertThrows(PermitApiError.class, () -> { + permit.api.roles.delete(FOLDER_KEY); + }); + assertEquals(exception.getResponseCode(), 404); + } catch (IOException | PermitApiError | PermitContextError e) { + fail("got error: " + e); + } + finally { + cleanup(); + } + } +} diff --git a/src/test/java/io/permit/sdk/endpoints/RolesApiE2ETest.java b/src/test/java/io/permit/sdk/endpoints/RolesApiE2ETest.java new file mode 100644 index 0000000..2c95631 --- /dev/null +++ b/src/test/java/io/permit/sdk/endpoints/RolesApiE2ETest.java @@ -0,0 +1,228 @@ +package io.permit.sdk.endpoints; + +import com.google.gson.Gson; +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.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * this e2e test should run against a clean permit environment. + * if the environment contains any objects the test will fail. + * eventually we want to create an environment programmatically + * and then extract the api key and start the test. + */ +public class RolesApiE2ETest extends PermitE2ETestBase { + private static final String DOCUMENT_KEY = "document"; + private static final String ADMIN_KEY = "testadmin"; + private static final String EMPTY_ROLE_KEY = "emptyrole"; + private static ResourceCreate documentData; + private static RoleCreate adminData; + private static RoleCreate duplicateRoleData; + private static RoleCreate emptyRoleData; + + @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()); + + // create document resource + documentData = (( + new ResourceCreate("document", "Document", actions) + ) + .withUrn("prn:gdrive:document") + .withDescription("google drive document") + ); + + adminData = new RoleCreate(ADMIN_KEY, "Admin") + .withDescription("a test role") + // Assuming there is a method to add permissions + .withPermissions(Arrays.asList( + String.format("%s:create", DOCUMENT_KEY), + String.format("%s:read", DOCUMENT_KEY) + )); + + duplicateRoleData = new RoleCreate(ADMIN_KEY, "Admin2").withDescription("a test duplicate role"); + + emptyRoleData = new RoleCreate(EMPTY_ROLE_KEY, "Empty").withDescription("empty role"); + } + + void cleanup() { + Permit permit = new Permit(this.config); + try { + try { + permit.api.roles.delete(adminData.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of role: " + adminData.key); + } + try { + permit.api.roles.delete(emptyRoleData.key); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of role: " + emptyRoleData.key); + } + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + logger.info("SKIPPING delete of resource: " + DOCUMENT_KEY); + } + } catch (PermitContextError e) { + fail("got error: " + e); + } catch (IOException e) { + fail("got error: " + e); + } + } + + @Test + void testRolesApi() { + // init the client + Permit permit = new Permit(this.config); + Gson gson = new Gson(); + + // roles lifecycle + try { + logger.info("check original roles length"); + int lenRolesOriginal = permit.api.roles.list().length; + + logger.info("create document with permissions"); + permit.api.resources.create(documentData); + + logger.info("create role with permissions"); + RoleRead admin = permit.api.roles.create(adminData); + assertNotNull(admin); + assertEquals(admin.key, adminData.key); + assertEquals(admin.name, adminData.name); + assertEquals(admin.description, adminData.description); + assertNotNull(admin.permissions); + assertTrue(admin.permissions.contains(DOCUMENT_KEY + ":create")); + assertTrue(admin.permissions.contains(DOCUMENT_KEY + ":read")); + + logger.info("verify number of roles increased by 1"); + RoleRead[] roles = permit.api.roles.list(); + assertEquals(roles.length, lenRolesOriginal + 1); + + logger.info("verify can find new role in the new list"); + assertTrue(Arrays.stream(roles).map(r -> r.key).collect(Collectors.toList()).contains(admin.key)); + + logger.info("get non existing role -> 404"); + PermitApiError notFoundError = assertThrows(PermitApiError.class, () -> { + permit.api.roles.get("editor"); + }); + assertEquals(notFoundError.getMessage(), "Got error status code: 404"); + assertEquals(notFoundError.getResponseCode(), 404); + LinkedTreeMap error = notFoundError.getErrorObject(); + assertEquals(error.get("error_code"), "NOT_FOUND"); + assertTrue(error.get("message").toString().startsWith("The requested data could not be found")); + + logger.info("create existing role -> 409"); + PermitApiError duplicateError = assertThrows(PermitApiError.class, () -> { + permit.api.roles.create(duplicateRoleData); + }); + assertEquals(duplicateError.getResponseCode(), 409); + + logger.info("create empty role"); + RoleRead emptyRole = permit.api.roles.create(emptyRoleData); + assertNotNull(emptyRole); + assertEquals(emptyRole.key, emptyRoleData.key); + assertEquals(emptyRole.name, emptyRoleData.name); + assertEquals(emptyRole.description, emptyRoleData.description); + assertNotNull(emptyRole.permissions); + assertEquals(emptyRole.permissions.size(), 0); + + logger.info("verify number of roles increased by 1"); + RoleRead[] roles2 = permit.api.roles.list(); + assertEquals(roles2.length, lenRolesOriginal + 2); + + logger.info("assign permissions to roles"); + RoleRead assignedEmpty = permit.api.roles.assignPermissions( + emptyRole.key, + new ArrayList<>(Arrays.asList(DOCUMENT_KEY + ":delete")) + ); + + logger.info("Ensure permissions are assigned as expected"); + assertNotNull(assignedEmpty); + assertEquals(assignedEmpty.key, emptyRole.key); + assertEquals(assignedEmpty.permissions.size(), 1); + assertTrue(assignedEmpty.permissions.contains(DOCUMENT_KEY + ":delete")); + + logger.info("Remove permissions from role"); + permit.api.roles.removePermissions( + admin.key, + new ArrayList<>(Arrays.asList(DOCUMENT_KEY + ":create")) + ); + + logger.info("Get admin role"); + RoleRead updatedAdmin = permit.api.roles.get(adminData.key); + assertNotNull(updatedAdmin); + assertEquals(updatedAdmin.key, adminData.key); + assertEquals(updatedAdmin.name, adminData.name); + assertNotNull(updatedAdmin.permissions); + assertFalse(updatedAdmin.permissions.contains(DOCUMENT_KEY + ":create")); + assertTrue(updatedAdmin.permissions.contains(DOCUMENT_KEY + ":read")); + + logger.info("Update admin role"); + permit.api.roles.update( + admin.key, + new RoleUpdate().withDescription("wat") + ); + + logger.info("admin changed again"); + updatedAdmin = permit.api.roles.get(adminData.key); + assertNotNull(updatedAdmin); + assertEquals(updatedAdmin.key, adminData.key); + assertEquals(updatedAdmin.name, adminData.name); + assertEquals(updatedAdmin.description, "wat"); + assertNotNull(updatedAdmin.permissions); + assertFalse(updatedAdmin.permissions.contains(DOCUMENT_KEY + ":create")); + assertTrue(updatedAdmin.permissions.contains(DOCUMENT_KEY + ":read")); + + logger.info("Delete objects..."); + try { + permit.api.roles.delete(adminData.key); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.roles.delete(emptyRoleData.key); + } catch (PermitApiError e) { + fail("got error: " + e); + } + try { + permit.api.resources.delete(DOCUMENT_KEY); + } catch (PermitApiError e) { + fail("got error: " + e); + } + + logger.info("Verify that again we have the initial number of roles"); + roles = permit.api.roles.list(); + assertEquals(roles.length, lenRolesOriginal); + + logger.info("Verify deleted role cannot be deleted again"); + PermitApiError exception = assertThrows(PermitApiError.class, () -> { + permit.api.roles.delete(emptyRole.key); + }); + assertEquals(exception.getResponseCode(), 404); + } catch (IOException | PermitApiError | PermitContextError e) { + fail("got error: " + e); + } + finally { + cleanup(); + } + } +}