Skip to content

Commit

Permalink
Merge pull request #4 from permitio/asaf/per-3421-v2-java-sdk
Browse files Browse the repository at this point in the history
Java SDK V2
  • Loading branch information
Asaf Cohen authored Feb 20, 2023
2 parents 86daffb + 23a470c commit 68f0830
Show file tree
Hide file tree
Showing 186 changed files with 14,334 additions and 675 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@

# Ignore Gradle build output directory
build

# Ignore stg schemas
stg-schemas/
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.PHONY: help

.DEFAULT_GOAL := help

# ENVIRONMENT?=dev

## generate openapi models
generate-openapi:
openapi-generator generate -i https://api.permit.io/v2/openapi.json -g java -o generated/ -c openapi-config.json

clean-openapi:
rm -rf generated/

## generate open api models from json schema
generate-jsonschema:
openapi2jsonschema https://api.permit.io/v2/openapi.json -o schemas/

140 changes: 138 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,140 @@
# Permit.io client for Java
# Java SDK for Permit.io

Java client library for the Permit.io full-stack permissions platform.
Java SDK for interacting with the Permit.io full-stack permissions platform.

## Overview

This guide will walk you through the steps of installing the Permit.io Java SDK and integrating it into your code.

## Installation

For [Maven](https://maven.apache.org/) projects, use:
```xml
<dependency>
<groupId>io.permit</groupId>
<artifactId>permit-sdk-java</artifactId>
<version>1.0.0-RC</version>
</dependency>
```

For [Gradle](https://gradle.org/) projects, configure `permit-sdk-java` as a dependency in your `build.gradle` file:
```groovy
dependencies {
// ...
implementation 'io.permit:permit-sdk-java:1.0.0-RC'
}
```

## Usage

### Initializing the SDK
To init the SDK, you need to create a new Permit client with the API key you got from the Permit.io dashboard.

First we will create a new `PermitConfig` object so we can pass it to the Permit client.

Second, we will create a new `Permit` client with the `PermitConfig` object we created.

```java
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;

// This line initializes the SDK and connects your Java app
// to the Permit.io PDP container you've set up in the previous step.
Permit permit = new Permit(
new PermitConfig.Builder("[YOUR_API_KEY]")
// in production, you might need to change this url to fit your deployment
.withPdpAddress("http://localhost:7766")
// optionally, if you wish to get more debug messages to your log, set this to true
.withDebugMode(false)
.build()
);
```

### Checking permissions
To check permissions using our `permit.check()` method, you will have to create User and Resource models as input to the permission check.
The models are located in ``

Follow the example below:

```java
import io.permit.sdk.enforcement.Resource;
import io.permit.sdk.enforcement.User;
import io.permit.sdk.Permit;

boolean permitted = permit.check(
// building the user object using User.fromString()
// the user key (this is the unique identifier of the user in the permission system).
User.fromString("[USER KEY]"),
// the action key (string)
"create",
// the resource object, can be initialized from string if the "default" tenant is used.
Resource.fromString("document")
);

if (permitted) {
System.out.println("User is PERMITTED to create a document in the 'default' tenant");
} else {
System.out.println("User is NOT PERMITTED to create a document in the 'default' tenant");
}
```

A more complicated example (passing attributes on the user object, using an explicit tenant in the resource):
```java
import io.permit.sdk.enforcement.Resource;
import io.permit.sdk.enforcement.User;
import java.util.HashMap;


HashMap<String, Object> userAttributes = new HashMap<>();
userAttributes.put("age", Integer.valueOf(20));
userAttributes.put("favorite_color", "yellow");

boolean permitted = permit.check(
// building the user object using the User.Builder class
new User.Builder("[USER KEY]").withAttributes(userAttributes).build(),
// the action key (string)
"create",
// building the resource object using the Resource.Builder in order to pass an explicit tenant key: "awesome-inc"
new Resource.Builder("document").withTenant("awesome-inc").build()
);

if (permitted) {
System.out.println("User is PERMITTED to create a document in the 'awesome-inc' tenant");
} else {
System.out.println("User is NOT PERMITTED to create a document in the 'awesome-inc' tenant");
}
```

### Syncing users
When the user first logins, and after you check if he authenticated successfully (i.e: **by checking the JWT access token**) -
you need to declare the user in the permission system so you can run `permit.check()` on that user.

To declare (or "sync") a user in the Permit.io API, use the `permit.api.users.sync()` method.

Follow the example below:
```java
import io.permit.sdk.api.models.CreateOrUpdateResult;
import io.permit.sdk.enforcement.User;

HashMap<String, Object> userAttributes = new HashMap<>();
userAttributes.put("age", Integer.valueOf(50));
userAttributes.put("fav_color", "red");

CreateOrUpdateResult<UserRead> result = permit.api.users.sync(
(new User.Builder("auth0|elon"))
.withEmail("elonmusk@tesla.com")
.withFirstName("Elon")
.withLastName("Musk")
.withAttributes(userAttributes)
.build()
);
UserRead user = result.getResult();
assertTrue(result.wasCreated());
```

Most params to UserCreates are optional, and only the unique user key is needed. This is valid:

```java
CreateOrUpdateResult<UserRead> result = permit.api.users.sync(new UserCreate("[USER KEY]"));
```
97 changes: 93 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ plugins {
id 'com.palantir.git-version' version '0.13.0'
// auto release to maven central (skip sonatype manual nexus release process)
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
// translate json schemas to java classes
id "org.jsonschema2pojo" version "1.1.3"
}

// It is important to set the group and the version to the root project
Expand All @@ -41,20 +43,107 @@ java {

// package dependencies
dependencies {
// swagger
implementation 'io.swagger:swagger-annotations:1.6.5'

// http client
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'

// json serialization and deserialization
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'io.gsonfire:gson-fire:1.8.5'

// openapi annotations
implementation 'javax.ws.rs:jsr311-api:1.1.1'
implementation 'javax.ws.rs:javax.ws.rs-api:2.1.1'
implementation 'org.openapitools:jackson-databind-nullable:0.2.3'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
implementation "jakarta.annotation:jakarta.annotation-api:1.3.5"

// logger
implementation 'ch.qos.logback:logback-classic:1.2.10'
implementation 'ch.qos.logback:logback-core:1.2.10'
implementation 'org.slf4j:slf4j-api:1.7.33'



// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'

// These dependencies are used internally, and not exposed to consumers on their own compile classpath.
// google standard java library
implementation 'com.google.guava:guava:30.1.1-jre'
// json serialization and deserialization
implementation 'com.google.code.gson:gson:2.8.9'
// http client
implementation 'com.squareup.okhttp3:okhttp:4.9.3'


}

jsonSchema2Pojo {
// Location of the JSON Schema file(s). This may refer to a single file or a directory of files.
source = files("schemas/")

// Target directory for generated Java source files. The plugin will add this directory to the
// java source set so the compiler will find and compile the newly generated source files.
targetDirectory = file("src/main/java")

// Package name used for generated Java classes (for types where a fully qualified name has not
// been supplied in the schema using the 'javaType' property).
targetPackage = 'io.permit.sdk.openapi.models'

// Whether to allow 'additional' properties to be supported in classes by adding a map to
// hold these. This is true by default, meaning that the schema rule 'additionalProperties'
// controls whether the map is added. Set this to false to globally disable additional properties.
includeAdditionalProperties = false

// Whether to include a javax.annotation.Generated (Java 8 and lower) or
// javax.annotation.processing.Generated (Java 9+) in on generated types (default true).
// See also: targetVersion.
includeGeneratedAnnotation = true

// Whether to use the 'title' property of the schema to decide the class name (if not
// set to true, the filename and property names are used).
useTitleAsClassname = true

// Whether to empty the target directory before generation occurs, to clear out all source files
// that have been generated previously. <strong>Be warned</strong>, when activated this option
// will cause jsonschema2pojo to <strong>indiscriminately delete the entire contents of the target
// directory (all files and folders)</strong> before it begins generating sources.
removeOldOutput = false

// Whether to generate builder-style methods of the form withXxx(value) (that return this),
// alongside the standard, void-return setters.
generateBuilders = true

// If set to true, then the gang of four builder pattern will be used to generate builders on
// generated classes. Note: This property works in collaboration with generateBuilders.
// If generateBuilders is false then this property will not do anything.
useInnerClassBuilders = false

// Whether to include hashCode and equals methods in generated Java types.
includeHashcodeAndEquals = false

// Whether to include a toString method in generated Java types.
includeToString = false

// Whether to include getters or to omit these accessor methods and create public fields instead.
includeGetters = false

// Whether to include setters or to omit these accessor methods and create public fields instead.
includeSetters = false

// Whether to use java.util.Optional for getters on properties that are not required
useOptionalForGetters = true

// Whether to generate constructors or not.
includeConstructors = true

// Whether to include only 'required' fields in generated constructors
constructorsRequiredPropertiesOnly = true

annotationStyle = 'gson'

// Whether to initialize Set and List fields as empty collections, or leave them as null.
initializeCollections = false
}

publishing {
Expand Down
7 changes: 7 additions & 0 deletions openapi-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"apiPackage": "io.permit.sdk.openapi.api",
"invokerPackage": "io.permit.sdk.openapi.client",
"modelPackage": "io.permit.sdk.openapi.model",
"serializationLibrary": "gson",
"legacyDiscriminatorBehavior": "true"
}
18 changes: 18 additions & 0 deletions schemas/actionblockeditable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"title": "ActionBlockEditable",
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string",
"description": "a more descriptive name for the action"
},
"description": {
"title": "Description",
"type": "string",
"description": "optional description string explaining what this action represents in your system"
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/schema#"
}
31 changes: 31 additions & 0 deletions schemas/actionblockread.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"title": "ActionBlockRead",
"required": [
"id"
],
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string",
"description": "a more descriptive name for the action"
},
"description": {
"title": "Description",
"type": "string",
"description": "optional description string explaining what this action represents in your system"
},
"id": {
"title": "Id",
"type": "string",
"description": "Unique id of the action"
},
"key": {
"title": "Key",
"type": "string",
"description": "action key"
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/schema#"
}
24 changes: 24 additions & 0 deletions schemas/addrolepermissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"title": "AddRolePermissions",
"required": [
"permissions"
],
"type": "object",
"properties": {
"permissions": {
"title": "Permissions",
"type": "array",
"items": {
"type": "string"
},
"description": "List of permissions to assign to the role. If a permission is already granted to the role it is skipped. Each permission can be either a resource action id, or `{resource_key}:{action_key}`, i.e: the \"permission name\"."
}
},
"additionalProperties": false,
"example": {
"permissions": [
"document:write"
]
},
"$schema": "http://json-schema.org/schema#"
}
Loading

0 comments on commit 68f0830

Please sign in to comment.