11package io .permit .sdk ;
22
3+ import io .permit .sdk .api .PermitContextChangeError ;
4+
35/**
46 * The {@code PermitContext} class represents the context for Permit API calls.
5- *
6- * A context can be: the entire workspace, a specific project, or a specific environment.
7- * Most API methods require an environment scope (e.g: in order to create a role you
8- * need to know in which environment to place it), but some methods can work in higher
9- * scopes (for example: creating a project can be done with a workspace-level scope).
7+ *
8+ * Since the Permit API hierarchy is deeply nested, it is less convenient to specify
9+ * the full object hierarchy in every request.
10+ *
11+ * For example, in order to list roles, the user needs to specify the (id or key) of the:
12+ * - the org
13+ * - the project
14+ * - then environment
15+ * in which the roles are located under.
16+ *
17+ * Instead, the SDK can "remember" the current context and "auto-complete" the details
18+ * from that context.
19+ *
20+ * We then get this kind of experience:
21+ * <pre>{@code
22+ * permit.api.roles.list();
23+ * }</pre>
24+ *
25+ * We can only run this function if the current context already knows the org, project,
26+ * and environment that we want to run under, and that is why in this example the api
27+ * method assumes we are running under an {@link ApiContextLevel#ENVIRONMENT} context.
1028 */
1129public class PermitContext {
12- private final ApiKeyLevel apiKeyLevel ;
13- private final String org ;
14- private final String project ;
15- private final String environment ;
30+ private ApiKeyLevel apiKeyLevel ;
31+ private String permittedOrganization ;
32+ private String permittedProject ;
33+ private String permittedEnviroment ;
34+
35+ private ApiContextLevel contextLevel ;
36+ private String org ;
37+ private String project ;
38+ private String environment ;
1639
1740 /**
1841 * Constructs a new instance of the {@code PermitContext} class with the specified builder.
1942 *
2043 * @param builder The builder used to construct the PermitContext.
2144 */
2245 public PermitContext (Builder builder ) {
23- this .apiKeyLevel = builder .apiKeyLevel ;
46+ this .saveApiKeyAccessibleScope (builder .org , builder .project , builder .environment );
47+ this .contextLevel = builder .contextLevel ;
2448 this .org = builder .org ;
2549 this .project = builder .project ;
2650 this .environment = builder .environment ;
2751 }
2852
53+ public PermitContext () {
54+ // access level
55+ this .apiKeyLevel = ApiKeyLevel .WAIT_FOR_INIT ;
56+ this .permittedOrganization = null ;
57+ this .permittedProject = null ;
58+ this .permittedEnviroment = null ;
59+
60+ // known context
61+ this .contextLevel = ApiContextLevel .WAIT_FOR_INIT ;
62+ this .org = null ;
63+ this .project = null ;
64+ this .environment = null ;
65+ }
66+
67+ private void saveApiKeyAccessibleScope (String org , String project , String environment ) {
68+ // Do not call this method directly!
69+ permittedOrganization = org ; // cannot be null
70+
71+ if (project != null && environment != null ) {
72+ permittedProject = project ;
73+ permittedEnviroment = environment ;
74+ apiKeyLevel = ApiKeyLevel .ENVIRONMENT_LEVEL_API_KEY ;
75+ } else if (project != null ) {
76+ permittedProject = project ;
77+ permittedEnviroment = null ;
78+ apiKeyLevel = ApiKeyLevel .PROJECT_LEVEL_API_KEY ;
79+ } else {
80+ permittedProject = null ;
81+ permittedEnviroment = null ;
82+ apiKeyLevel = ApiKeyLevel .ORGANIZATION_LEVEL_API_KEY ;
83+ }
84+ }
85+
2986 /**
30- * Returns the API key level associated with the Permit context .
87+ * Returns the access level of the API key used by the SDK .
3188 *
32- * @return The API key level.
89+ * @deprecated replaced with {@link PermitContext#getPermittedAccessLevel}
90+ * @return The API key access level.
3391 */
3492 public ApiKeyLevel getApiKeyLevel () {
3593 return apiKeyLevel ;
3694 }
3795
96+ /**
97+ * Returns the access level of the API key used by the SDK.
98+ *
99+ * @return The API key access level.
100+ */
101+ public ApiKeyLevel getPermittedAccessLevel () {
102+ return apiKeyLevel ;
103+ }
104+
105+ /**
106+ * Returns the current SDK context level.
107+ *
108+ * @return the context level.
109+ */
110+ public ApiContextLevel getContextLevel () {
111+ return contextLevel ;
112+ }
113+
38114 /**
39115 * Returns the organization (workspace) associated with the Permit context.
40116 *
@@ -62,11 +138,86 @@ public String getEnvironment() {
62138 return environment ;
63139 }
64140
141+ /**
142+ * Sets the current context of the SDK to a specific organization.
143+ *
144+ * @param org The organization uuid.
145+ * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions.
146+ */
147+ public void setOrganizationLevelContext (String org ) throws PermitContextChangeError {
148+ verifyCanAccessOrg (org );
149+ this .contextLevel = ApiContextLevel .ORGANIZATION ;
150+ this .org = org ;
151+ this .project = null ;
152+ this .environment = null ;
153+ }
154+
155+ /**
156+ * Sets the current context of the SDK to a specific project within an organization.
157+ *
158+ * @param org The organization uuid.
159+ * @param project The project uuid.
160+ * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions.
161+ */
162+ public void setProjectLevelContext (String org , String project ) throws PermitContextChangeError {
163+ verifyCanAccessProject (org , project );
164+ this .contextLevel = ApiContextLevel .PROJECT ;
165+ this .org = org ;
166+ this .project = project ;
167+ this .environment = null ;
168+ }
169+
170+ /**
171+ * Sets the current context of the SDK to a specific environment within an organization and project.
172+ *
173+ * @param org The organization uuid.
174+ * @param project The project uuid.
175+ * @param environment The environment uuid.
176+ * @throws PermitContextChangeError If the SDK context cannot be set due to insufficient API Key permissions.
177+ */
178+ public void setEnvironmentLevelContext (String org , String project , String environment ) throws PermitContextChangeError {
179+ verifyCanAccessEnvironment (org , project , environment );
180+ this .contextLevel = ApiContextLevel .ENVIRONMENT ;
181+ this .org = org ;
182+ this .project = project ;
183+ this .environment = environment ;
184+ }
185+
186+ private void verifyCanAccessOrg (String org ) throws PermitContextChangeError {
187+ if (!org .equals (permittedOrganization )) {
188+ throw new PermitContextChangeError (
189+ "You cannot set an SDK context with org '" + org +
190+ "' due to insufficient API Key permissions"
191+ );
192+ }
193+ }
194+
195+ private void verifyCanAccessProject (String org , String project ) throws PermitContextChangeError {
196+ verifyCanAccessOrg (org );
197+ if (permittedProject != null && !project .equals (permittedProject )) {
198+ throw new PermitContextChangeError (
199+ "You cannot set an SDK context with project '" + project +
200+ "' due to insufficient API Key permissions"
201+ );
202+ }
203+ }
204+
205+ private void verifyCanAccessEnvironment (String org , String project , String environment ) throws PermitContextChangeError {
206+ verifyCanAccessProject (org , project );
207+ if (permittedEnviroment != null && !environment .equals (permittedEnviroment )) {
208+ throw new PermitContextChangeError (
209+ "You cannot set an SDK context with environment '" + environment +
210+ "' due to insufficient API Key permissions"
211+ );
212+ }
213+ }
214+
65215 /**
66216 * The {@code Builder} class provides a builder interface for constructing {@code PermitContext} objects.
67217 */
68218 public static class Builder {
69- private ApiKeyLevel apiKeyLevel ;
219+
220+ private ApiContextLevel contextLevel ;
70221 private String org ;
71222 private String project ;
72223 private String environment ;
@@ -78,7 +229,7 @@ public static class Builder {
78229 * context will be stored in the SDK configuration for future API calls.
79230 */
80231 public Builder () {
81- this .apiKeyLevel = ApiKeyLevel .WAIT_FOR_INIT ;
232+ this .contextLevel = ApiContextLevel .WAIT_FOR_INIT ;
82233 this .org = null ;
83234 this .project = null ;
84235 this .environment = null ;
@@ -93,10 +244,10 @@ public Builder() {
93244 * @return The updated {@code Builder} object.
94245 */
95246 public Builder withOrganization (String org ) {
247+ this .contextLevel = ApiContextLevel .ORGANIZATION ;
96248 this .org = org ;
97249 this .project = null ;
98250 this .environment = null ;
99- this .apiKeyLevel = ApiKeyLevel .ORGANIZATION_LEVEL_API_KEY ;
100251 return this ;
101252 }
102253
@@ -110,10 +261,10 @@ public Builder withOrganization(String org) {
110261 * @return The updated {@code Builder} object.
111262 */
112263 public Builder withProject (String org , String project ) {
264+ this .contextLevel = ApiContextLevel .PROJECT ;
113265 this .org = org ;
114266 this .project = project ;
115267 this .environment = null ;
116- this .apiKeyLevel = ApiKeyLevel .PROJECT_LEVEL_API_KEY ;
117268 return this ;
118269 }
119270
@@ -127,10 +278,10 @@ public Builder withProject(String org, String project) {
127278 * @return The updated {@code Builder} object.
128279 */
129280 public Builder withEnvironment (String org , String project , String environment ) {
281+ this .contextLevel = ApiContextLevel .ENVIRONMENT ;
130282 this .org = org ;
131283 this .project = project ;
132284 this .environment = environment ;
133- this .apiKeyLevel = ApiKeyLevel .ENVIRONMENT_LEVEL_API_KEY ;
134285 return this ;
135286 }
136287
0 commit comments