Skip to content

Commit 941b584

Browse files
authored
Merge pull request #29 from permitio/gidi/per-11143-add-check-against-opa-directly-to-java-sdk
Add new ability to get user permissions via opa directly
2 parents 48b4ed2 + a66bf1b commit 941b584

File tree

9 files changed

+179
-28
lines changed

9 files changed

+179
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ build
1010

1111
# Ignore stg schemas
1212
stg-schemas/
13+
bin

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ repositories {
3636

3737
java {
3838
toolchain {
39-
languageVersion = JavaLanguageVersion.of(8)
39+
languageVersion = JavaLanguageVersion.of(8)
4040
}
4141
// sources are required by maven central in order to accept the package
4242
withSourcesJar()

src/main/java/io/permit/sdk/Permit.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
package io.permit.sdk;
22

3+
import java.io.IOException;
4+
import java.util.List;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
39
import com.google.gson.Gson;
410
import com.google.gson.GsonBuilder;
11+
512
import io.permit.sdk.api.ApiClient;
613
import io.permit.sdk.api.ElementsApi;
714
import io.permit.sdk.api.PermitApiError;
8-
import io.permit.sdk.enforcement.*;
15+
import io.permit.sdk.enforcement.CheckQuery;
16+
import io.permit.sdk.enforcement.Enforcer;
17+
import io.permit.sdk.enforcement.GetUserPermissionsQuery;
18+
import io.permit.sdk.enforcement.IEnforcerApi;
19+
import io.permit.sdk.enforcement.Resource;
20+
import io.permit.sdk.enforcement.TenantDetails;
21+
import io.permit.sdk.enforcement.User;
22+
import io.permit.sdk.enforcement.UserPermissions;
923
import io.permit.sdk.util.Context;
1024

11-
import org.slf4j.Logger;
12-
import org.slf4j.LoggerFactory;
13-
14-
import java.io.IOException;
15-
import java.util.List;
16-
1725
/**
1826
* The {@code Permit} class represents the main entry point for interacting with the Permit.io SDK.
1927
*
@@ -159,6 +167,11 @@ public UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws
159167
return this.enforcer.getUserPermissions(input);
160168
}
161169

170+
@Override
171+
public UserPermissions getUserPermissionsFromOPA(GetUserPermissionsQuery input) throws IOException, PermitApiError {
172+
return this.enforcer.getUserPermissionsFromOPA(input);
173+
}
174+
162175
@Override
163176
public List<TenantDetails> getUserTenants(User user, Context context) throws IOException, PermitApiError {
164177
return this.enforcer.getUserTenants(user, context);

src/main/java/io/permit/sdk/PermitConfig.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class PermitConfig {
99
// main config vars
1010
private final String token;
1111
private final String pdp;
12+
private final String opa;
1213
private final String apiUrl;
1314
private final Boolean debugMode;
1415

@@ -32,6 +33,7 @@ public class PermitConfig {
3233
private PermitConfig(Builder builder) {
3334
this.token = builder.token;
3435
this.pdp = builder.pdp;
36+
this.opa = builder.opa;
3537
this.apiUrl = builder.apiUrl;
3638
this.debugMode = builder.debugMode;
3739
this.logLevel = builder.logLevel;
@@ -75,6 +77,15 @@ public String getPdpAddress() {
7577
return pdp;
7678
}
7779

80+
/**
81+
* Returns the URL of the OPA Inside Policy Decision Point (PDP) used to evaluate authorization queries (i.e: permission checks).
82+
*
83+
* @return The OPA URL.
84+
*/
85+
public String getOpaAddress() {
86+
return opa;
87+
}
88+
7889
/**
7990
* Returns whether the Permit SDK is in debug mode.
8091
*
@@ -194,6 +205,7 @@ public static class Builder {
194205
// main config vars
195206
private String token;
196207
private String pdp = "http://localhost:7766";
208+
private String opa = "http://localhost:8181";
197209
private String apiUrl = "https://api.permit.io";
198210
private Boolean debugMode = false;
199211

@@ -234,6 +246,17 @@ public Builder withPdpAddress(String pdp) {
234246
return this;
235247
}
236248

249+
/**
250+
* Configures the Policy Decision Point (PDP) address.
251+
*
252+
* @param opa The PDP address to be set.
253+
* @return The updated {@code Builder} object.
254+
*/
255+
public Builder withOpaAddress(String opa) {
256+
this.opa = opa;
257+
return this;
258+
}
259+
237260
/**
238261
* Configures the URL of the Permit REST API.
239262
*

src/main/java/io/permit/sdk/enforcement/Enforcer.java

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
package io.permit.sdk.enforcement;
22

3-
import com.google.common.primitives.Booleans;
4-
import com.google.gson.Gson;
5-
import io.permit.sdk.PermitConfig;
6-
import io.permit.sdk.api.HttpLoggingInterceptor;
7-
import io.permit.sdk.api.PermitApiError;
8-
import io.permit.sdk.openapi.models.ConditionSetRuleRead;
9-
import io.permit.sdk.util.Context;
10-
import io.permit.sdk.util.ContextStore;
11-
123
import java.io.IOException;
134
import java.util.ArrayList;
145
import java.util.Arrays;
156
import java.util.HashMap;
167
import java.util.List;
8+
import java.util.Map;
179
import java.util.stream.Collectors;
1810

11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
14+
import com.google.common.primitives.Booleans;
15+
import com.google.gson.Gson;
16+
17+
import io.permit.sdk.PermitConfig;
18+
import io.permit.sdk.api.HttpLoggingInterceptor;
19+
import io.permit.sdk.api.PermitApiError;
20+
import io.permit.sdk.util.Context;
21+
import io.permit.sdk.util.ContextStore;
1922
import okhttp3.MediaType;
2023
import okhttp3.OkHttpClient;
2124
import okhttp3.Request;
2225
import okhttp3.RequestBody;
2326
import okhttp3.Response;
2427
import okhttp3.ResponseBody;
25-
import org.slf4j.Logger;
26-
import org.slf4j.LoggerFactory;
2728

2829
/**
2930
* The {@code EnforcerInput} class represents the input data for the Permit PDP enforcement API.
@@ -448,6 +449,63 @@ public UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws
448449
return result;
449450
}
450451

452+
453+
@Override
454+
public UserPermissions getUserPermissionsFromOPA(GetUserPermissionsQuery input) throws IOException, PermitApiError {
455+
// request body
456+
Gson gson = new Gson();
457+
458+
// Inner map for the nested JSON
459+
Map<String, Object> innerMap = new HashMap<>();
460+
innerMap.put("user", input.user);
461+
innerMap.put("tenants", input.tenants);
462+
innerMap.put("resource_types", input.resource_types);
463+
innerMap.put("resources", input.resources);
464+
innerMap.put("context", input.context);
465+
466+
// Outer map wrapping the inner map
467+
Map<String, Object> outerMap = new HashMap<>();
468+
outerMap.put("input", innerMap);
469+
470+
// Serialize to JSON
471+
String requestBody = gson.toJson(outerMap);
472+
473+
RequestBody body = RequestBody.create(requestBody, MediaType.parse("application/json"));
474+
String PERMISSIONS_PATH = "permit/user_permissions/permissions";
475+
String url = String.format("%s/v1/data/%s", this.config.getOpaAddress(), PERMISSIONS_PATH);
476+
Request request = new Request.Builder()
477+
.url(url)
478+
.post(body)
479+
.addHeader("Content-Type", "application/json")
480+
.addHeader("Authorization", String.format("Bearer %s", this.config.getToken()))
481+
.addHeader("X-Permit-SDK-Version", String.format("java:%s", this.config.version))
482+
.build();
483+
484+
String requestRepr = String.format(
485+
"permit.getUserPermissions(%s, %s, %s, %s)",
486+
input.user.toString(),
487+
input.tenants != null ? input.tenants.toString() : "null",
488+
input.resource_types != null ? input.resource_types.toString() : "null",
489+
input.resources != null ? input.resources.toString() : "null"
490+
);
491+
492+
UserPermissionsOpa result = this.callApiAndParseJson(request, requestRepr, UserPermissionsOpa.class);
493+
494+
UserPermissions userPermissions = new UserPermissions();
495+
userPermissions.putAll(result.getResult());
496+
497+
if (this.config.isDebugMode()) {
498+
logger.info(String.format(
499+
"%s => returned %d permissions on %d objects",
500+
requestRepr,
501+
userPermissions.values().stream().map(obj -> obj.permissions.size()).reduce(0, Integer::sum),
502+
userPermissions.keySet().size()
503+
));
504+
}
505+
506+
return userPermissions;
507+
}
508+
451509
private List<TenantDetails> getUserTenants(GetUserTenantsQuery input) throws IOException, PermitApiError {
452510
// request body
453511
Gson gson = new Gson();

src/main/java/io/permit/sdk/enforcement/IEnforcerApi.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package io.permit.sdk.enforcement;
22

3-
import io.permit.sdk.api.PermitApiError;
4-
import io.permit.sdk.util.Context;
5-
63
import java.io.IOException;
74
import java.util.List;
85

6+
import io.permit.sdk.api.PermitApiError;
7+
import io.permit.sdk.util.Context;
8+
99
public interface IEnforcerApi {
1010
/**
1111
* Checks if a `user` is authorized to perform an `action` on a `resource` within the specified context.
@@ -112,6 +112,16 @@ public interface IEnforcerApi {
112112
*/
113113
UserPermissions getUserPermissions(GetUserPermissionsQuery input) throws IOException, PermitApiError;
114114

115+
/**
116+
* list all the permissions granted to a user (by default in all tenants and for all objects).
117+
*
118+
* @param input input to get user permissions api
119+
* @return A UserPermissions object, that contains all the permissions granted to the user.
120+
* @throws PermitApiError if an error occurs while sending the authorization request to the PDP.
121+
* @throws IOException if could not read the content of the returned http response.
122+
*/
123+
UserPermissions getUserPermissionsFromOPA(GetUserPermissionsQuery input) throws IOException, PermitApiError;
124+
115125
/**
116126
* list all the tenants the user is associated with.
117127
*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.permit.sdk.enforcement;
2+
3+
import java.util.HashMap;
4+
5+
/**
6+
* The {@code UserPermissionsOPA} class represents all the objects a user can access.
7+
*/
8+
final public class UserPermissionsOpa {
9+
private String decisionId;
10+
private HashMap<String, ObjectPermissions> result;
11+
12+
// Getters and setters
13+
public String getDecisionId() {
14+
return decisionId;
15+
}
16+
17+
public void setDecisionId(String decisionId) {
18+
this.decisionId = decisionId;
19+
}
20+
21+
public HashMap<String, ObjectPermissions> getResult() {
22+
return result;
23+
}
24+
25+
public void setResult(HashMap<String, ObjectPermissions> result) {
26+
this.result = result;
27+
}
28+
}

src/test/java/io/permit/sdk/PermitE2ETestBase.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
package io.permit.sdk;
22

3-
import okhttp3.HttpUrl;
4-
import org.slf4j.Logger;
5-
import org.slf4j.LoggerFactory;
6-
73
import java.io.IOException;
84
import java.net.InetSocketAddress;
95
import java.net.Socket;
106

7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import okhttp3.HttpUrl;
11+
1112
public abstract class PermitE2ETestBase {
1213
protected final static Logger logger = LoggerFactory.getLogger(PermitE2ETestBase.class);
1314
protected final PermitConfig config;
15+
protected final PermitConfig opaConfig;
1416
protected boolean skipTests = false;
1517
private final static int connectionTimeout = 10; // 3 seconds to give up on sidecar / API
1618

1719
public PermitE2ETestBase() {
1820
final String token = System.getenv().getOrDefault("PDP_API_KEY", "");
1921
final String pdpAddress = System.getenv().getOrDefault("PDP_URL", "http://localhost:7766");
20-
final String pdpControlPlane = System.getenv().getOrDefault("PDP_CONTROL_PLANE", "http://localhost:8000");
22+
final String opaAddress = System.getenv().getOrDefault("OPA_URL", "http://localhost:8181");
23+
final String pdpControlPlane = System.getenv().getOrDefault("PDP_CONTROL_PLANE", "https://api.permit.io");
2124

2225
this.config = new PermitConfig.Builder(token)
2326
.withApiUrl(pdpControlPlane)
2427
.withPdpAddress(pdpAddress)
2528
.withDebugMode(true)
2629
.build();
2730

31+
32+
this.opaConfig = new PermitConfig.Builder(token)
33+
.withApiUrl(pdpControlPlane)
34+
.withOpaAddress(opaAddress)
35+
.withDebugMode(true)
36+
.build();
37+
2838
HttpUrl apiUrl = HttpUrl.parse(config.getApiUrl());
2939
HttpUrl pdpUrl = HttpUrl.parse(config.getPdpAddress());
3040

src/test/java/io/permit/sdk/e2e/RbacE2ETest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class RbacE2ETest extends PermitE2ETestBase {
3636
void testPermissionCheckRBAC() {
3737
// init the client
3838
Permit permit = new Permit(this.config);
39-
39+
Permit permitOpa = new Permit(this.opaConfig);
4040
try {
4141
// resource actions
4242
HashMap<String, ActionBlockEditable> actions = new HashMap<>();
@@ -250,7 +250,15 @@ void testPermissionCheckRBAC() {
250250
User.fromString("auth0|elon")
251251
)
252252
);
253+
254+
UserPermissions permissions_2 = permitOpa.getUserPermissionsFromOPA(
255+
new GetUserPermissionsQuery(
256+
User.fromString("auth0|elon")
257+
)
258+
);
259+
253260
assertEquals(permissions.keySet().size(), 2); // elon has access to 2 tenants
261+
assertEquals(permissions_2.keySet().size(), 2); // elon has access to 2 tenants
254262
String tenantObjectKey = String.format("%s:%s", TENANT_RESOURCE_KEY, tenant.key);
255263
String tenant2ObjectKey = String.format("%s:%s", TENANT_RESOURCE_KEY, tenant2.key);
256264
assertTrue(permissions.containsKey(tenantObjectKey));

0 commit comments

Comments
 (0)