Check a permission in all tenants
Find every tenant in which a user can perform an action on a resource, in one call to the policy decision point (PDP). This page is for developers of multi-tenant applications who need to show a user the tenants they can act in, without running one permit.check() per tenant.
Prerequisites
- A Permit SDK client connected to a container PDP (Run the PDP). The Cloud PDP doesn't support the all-tenants check (Cloud PDP capabilities).
- Users with role assignments in one or more tenants
All-tenants check function by SDK
The all-tenants check takes the same user, action, and resource arguments as permit.check(). The PDP ignores a tenant key in the resource, because it evaluates the check in every tenant.
| SDK | Function | Returns |
|---|---|---|
| Node.js | permit.checkAllTenants(user, action, resource, context?) | TenantDetails[] |
| Java | permit.checkInAllTenants(user, action, resource) | List<TenantDetails> |
| Go | permit.AllTenantsCheck(user, action, resource) | []enforcement.TenantDetails |
| PDP API | POST /allowed/all-tenants | {"allowed_tenants": [...]} |
Run an all-tenants check
This example asks in which tenants john@doe.com can read a document:
- Java
- GoLang
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;
import io.permit.sdk.enforcement.*;
import java.util.Arrays;
import java.util.List;
Permit permit = new Permit(
new PermitConfig.Builder("[YOUR_API_KEY]").build()
);
List<TenantDetails> allowedTenants = permit.checkInAllTenants(
User.fromString("john@doe.com"),
"read",
new Resource.Builder("document").build()
);
package main
import (
"encoding/json"
"fmt"
)
import p "github.com/permitio/permit-golang/pkg/permit"
import "github.com/permitio/permit-golang/pkg/config"
import "github.com/permitio/permit-golang/pkg/enforcement"
func main() {
// Create permit client
permitConfig := config.NewConfigBuilder("<YOUR_API_TOKEN>").Build()
permit := p.NewPermit(permitConfig)
// Create user and resource variables
user := enforcement.UserBuilder("john@doe.com").Build()
resource := enforcement.ResourceBuilder("document").Build()
var allowedTenants []enforcement.TenantDetails
// Check a user's permissions for a specified action on a resource across all tenants
allowedTenants, err := permit.AllTenantsCheck(user, "read", resource)
if err != nil {
fmt.Printf("Error enforcing permissions: %s", err)
} else if len(allowedTenants) > 0 {
fmt.Println("John is PERMITTED to read a document in some tenant in the environment")
for i, tenant := range allowedTenants {
attributes, _ := json.MarshalIndent(tenant.Attributes, "", "\t")
fmt.Printf("%d. Allowed Tenant is '%s', attributes are:\n%s",
i, tenant.Key, attributes,
)
}
} else {
fmt.Println("John is NOT PERMITTED to read a document in any tenant in the environment")
}
}
Read the all-tenants check result
The result is a list with one entry for each tenant in which the PDP allows the action. Each entry holds the tenant key and the tenant attributes. An empty list means the user can't perform the action in any tenant.
Run an all-tenants check with attributes
For attribute-based access control (ABAC) policies, pass user and resource attributes the same way as in permit.check(). The PDP evaluates the attributes in every tenant.
- Java
- GoLang
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;
import io.permit.sdk.enforcement.*;
import java.util.Arrays;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
Permit permit = new Permit(
new PermitConfig.Builder("[YOUR_API_KEY]").build()
);
HashMap<String,Object> resourceAttrs = new HashMap<String,Object>();
resourceAttrs.put("colors", new ArrayList<String>(Arrays.asList("red","blue")));
List<TenantDetails> allowedTenants = permit.checkInAllTenants(
User.fromString("john@doe.com"),
"read",
new Resource.Builder("document").withAttributes(resourceAttrs).build()
);
package main
import (
"encoding/json"
"fmt"
)
import p "github.com/permitio/permit-golang/pkg/permit"
import "github.com/permitio/permit-golang/pkg/config"
import "github.com/permitio/permit-golang/pkg/enforcement"
func main() {
// Create permit client
permitConfig := config.NewConfigBuilder("<YOUR_API_TOKEN>").Build()
permit := p.NewPermit(permitConfig)
// Create user and resource variables with attributes
user := enforcement.UserBuilder("john@doe.com").WithAttributes(map[string]interface{}{
"location": "England",
"department": "Engineering",
}).Build()
resource := enforcement.ResourceBuilder("document").WithAttributes(map[string]interface{}{
"hasApproval": "true",
}).Build()
var allowedTenants []enforcement.TenantDetails
// Check a user's permissions for a specified action on a resource across all tenants
allowedTenants, err := permit.AllTenantsCheck(user, "read", resource);
if err != nil {
fmt.Printf("Error enforcing permissions: %s", err)
} else if len(allowedTenants) > 0 {
fmt.Println("John is PERMITTED to read a document in some tenant in the environment")
for i, tenant := range allowedTenants {
attributes, _ := json.MarshalIndent(tenant.Attributes, "", "\t")
fmt.Printf("%d. Allowed Tenant is '%s', attributes are:\n%s",
i, tenant.Key, attributes,
)
}
} else {
fmt.Println("John is NOT PERMITTED to read a document in any tenant in the environment")
}
}
Limitation: relationship-based checks
The all-tenants check doesn't return useful results for relationship-based access control (ReBAC) policies. A ReBAC check targets a resource instance, and a resource instance belongs to exactly one tenant. The result is either an empty list or a list with that one tenant. For ReBAC, call permit.check() with the resource instance instead.