Data Filtering
Implementing data filtering within access control represents a different approach to managing permissions. Instead of merely granting or denying access, it curates what users see, tailoring the data to their individual permissions. This method ensures not only secure access but also optimized data delivery.
When working to filter data (e.g. data coming from databases), there are two main types of authorization:
Boolean Query Filtering: This involves checking whether a query should be allowed to execute. Here, the query is translated from SQL to a policy (e.g., using an Abstract Syntax Tree (AST) for SQL, or such as this simple parser for Couchbase N1QL). Essentially, the query is mapped to resources and actions, and these are enforced with a standard check.
Data Filtering from Queries: This has four subtypes:
- Application-Level Filtering: In this method, the whole data is fetched from the DB and then uses a set of boolean results obtained from the Policy Decision Point (PDP) through bulk checks.
- PDP-Level Filtering: In this method, the data is fetched from the DB, and then use the
filterObjects
function (see below), which returns a subset of the objects passed to it based on the policy. - PDP-Level Filtering Based on the Information Graph: This method involves returning pre-filtered objects based on data synchronized with the PDP in advance. It includes functions like
getUserPermissions
(which returns all objects a user has access to) andgetAuthorizedUsers
(which returns all users who have access to a specific resource). In this method, the allowed objects returned from the authorization graph are added to the DB query before making the query. - Source-Level Filtering (in the Database): Also known as Partial Evaluation, where the PDP returns a query basis (e.g., SQL) that is sent or appended to an existing query and sent to the database, which returns the relevant data pre-filtered. This capability exists in Open Policy Agent (OPA) under the
compile
API and is already available within Permit’s PDP. In this method the DB query is modified before being executed against the DB.- Simplified Partial-evaluation, is an upcoming feature in advanced stages of release, which includes built-in translation to SQL.
PDP-Level Filtering
Below is a simple use example to use permit.filterObjects
package main
import (
"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("").Build()
permit := p.New(permitConfig)
requestContext := map[string]string{
"source": "docs",
}
user := enforcement.UserBuilder("john@doe.com").Build()
var action enforcement.Action = "read"
resourcesToCheck := []enforcement.ResourceI{
enforcement.ResourceBuilder("document").WithID("document-1").WithTenant(enforcement.DefaultTenant),
enforcement.ResourceBuilder("folder").WithID("folder-1").WithTenant(enforcement.DefaultTenant),
enforcement.ResourceBuilder("document").WithID("document-2").WithTenant(enforcement.DefaultTenant),
enforcement.ResourceBuilder("document").WithID("document-3").WithTenant(enforcement.DefaultTenant),
}
var allowedResources []enforcement.ResourceI
var err error
// Filter the objects
allowedResources, err = permit.FilterObjects(user, action, requestContext, resourcesToCheck...)
if err != nil {
fmt.Printf("Error enforcing permissions: %s", err)
} else {
// The response indexes correspond to the request indexes
for i, resource := range allowedResources {
fmt.Printf("%d. User '%s' is PERMITTED to '%s' a '%s' with id '%s'\n",
i, user.Key, action, resource.GetType(), resource.GetID(),
)
}
}
}