Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/cerbos/cerbos-sdk-java

Java SDK for interacting with the Cerbos PDP.
https://github.com/cerbos/cerbos-sdk-java

access-control cerbos policy security

Last synced: about 18 hours ago
JSON representation

Java SDK for interacting with the Cerbos PDP.

Awesome Lists containing this project

README

        

Cerbos Java SDK
===============

![Maven Central](https://img.shields.io/maven-central/v/dev.cerbos/cerbos-sdk-java?style=for-the-badge&versionPrefix=0.)

Java client library for the [Cerbos](https://github.com/cerbos/cerbos) open source access control solution. This library
includes RPC clients for accessing the Cerbos PDP and test utilities for testing your code locally
using [Testcontainers](https://www.testcontainers.org).

Find out more about Cerbos at https://cerbos.dev and read the documentation at https://docs.cerbos.dev.

Installation
-------------

Artifacts are available from Maven Central.

**Example: Gradle (Kotlin DSL)**

```kotlin
dependencies {
implementation("dev.cerbos:cerbos-sdk-java:0.+")
implementation("io.grpc:grpc-core:1.+")
}

repositories {
mavenCentral()
}
```

Examples
--------

> [!NOTE]
> Connecting to Unix domain sockets using this SDK is only supported on Linux, which is a limitation inherited from the underlying [`grpc-java`](https://github.com/grpc/grpc-java) library.

### Creating a client without TLS

```java
CerbosBlockingClient client=new CerbosClientBuilder("localhost:3593").withPlaintext().buildBlockingClient();
```

### Check a single principal and resource

```java
CheckResult result=client.check(
Principal.newInstance("john","employee")
.withPolicyVersion("20210210")
.withAttribute("department",stringValue("marketing"))
.withAttribute("geography",stringValue("GB")),
Resource.newInstance("leave_request","xx125")
.withPolicyVersion("20210210")
.withAttribute("department",stringValue("marketing"))
.withAttribute("geography",stringValue("GB"))
.withAttribute("owner",stringValue("john")),
"view:public","approve");

if(result.isAllowed("approve")){ // returns true if `approve` action is allowed
...
}
```

### Check a batch

```java
CheckResourcesResult result=client.batch(
Principal.newInstance("john","employee")
.withPolicyVersion("20210210")
.withAttribute("department",stringValue("marketing"))
.withAttribute("geography",stringValue("GB"))
)
.addResources(
ResourceAction.newInstance("leave_request","XX125")
.withPolicyVersion("20210210")
.withAttributes(
Map.of(
"department", stringValue("marketing"),
"geography", stringValue("GB"),
"owner", stringValue("john")
)
)
.withActions("view:public","approve","defer"),
ResourceAction.newInstance("leave_request","XX225")
.withPolicyVersion("20210210")
.withAttributes(
Map.of(
"department", stringValue("marketing"),
"geography", stringValue("GB"),
"owner", stringValue("martha")
)
)
.withActions("view:public","approve"),
ResourceAction.newInstance("leave_request","XX325")
.withPolicyVersion("20210210")
.withAttributes(
Map.of(
"department", stringValue("marketing"),
"geography", stringValue("US"),
"owner", stringValue("peggy")
)
)
.withActions("view:public","approve")
)
.check();

result.find("XX125").map(r->r.isAllowed("view:public")).orElse(false);
```

### Create a query plan

```java
PlanResourcesResult result = client.plan(
Principal.newInstance("maggie","manager")
.withAttribute("department",stringValue("marketing"))
.withAttribute("geography",stringValue("GB"))
.withAttribute("team",stringValue("design")),
Resource.newInstance("leave_request").withPolicyVersion("20210210"),
"approve"
);

if(result.isAlwaysAllowed()) {
return true;
} else if(result.isAlwaysDenied()) {
return false;
} else {
return executeQuery(result.getCondition());
}
```

### Test with [Testcontainers](https://www.testcontainers.org)

```java
@Container
private static final CerbosContainer cerbosContainer=new CerbosContainer()
.withClasspathResourceMapping("policies","/policies",BindMode.READ_ONLY)
.withLogConsumer(new Slf4jLogConsumer(LOG));

@BeforeAll
private void initClient() throws CerbosClientBuilder.InvalidClientConfigurationException{
String target=cerbosContainer.getTarget();
this.client=new CerbosClientBuilder(target).withPlaintext().buildBlockingClient();
}
```

### Accessing the Admin API

```java
// Username and password can be specified using CERBOS_USER and CERBOS_PASSWORD environment variables as well
CerbosBlockingAdminClient adminClient = new CerbosClientBuilder(target).withPlaintext().buildBlockingAdminClient("username", "password");

adminClient.addOrUpdatePolicy().with(new FileReader(fileObjectContainingPolicyJSON)).addOrUpdate();
```

See `CerbosBlockingAdminClientTest` test class for more examples of Admin API usage including how to convert YAML policies to the JSON format required by the API.

## Common issues

`java.lang.IllegalArgumentException: cannot find a NameResolver for ...`:
The gRPC library relies on Java SPI to register name resolvers and client-side load balancing strategies for clients. The defaults are defined in the `io.grpc:grpc-core` library. Some packaging methods could overwrite or strip out the `META-INF/services` directory, which would cause the above exception on Cerbos client initialisation. If that's the case, eithertry to recreate the [default service bindings](https://github.com/grpc/grpc-java/tree/master/core/src/main/resources/META-INF/services) in your own jar OR explicitly register the services as follows:

```java
import io.grpc.LoadBalancerRegistry;
import io.grpc.NameResolverRegistry;

public class Cerbos {
public static void main(String[] args) throws CerbosClientBuilder.InvalidClientConfigurationException {
LoadBalancerRegistry.getDefaultRegistry().register(new io.grpc.internal.PickFirstLoadBalancerProvider());
NameResolverRegistry.getDefaultRegistry().register(new io.grpc.internal.DnsNameResolverProvider());
CerbosBlockingClient client = new CerbosClientBuilder("dns:///cerbos.my-ns.svc.cluster.local:3593").withInsecure().buildBlockingClient();
...
}
}
```