Data Filtering on Spring Data with Open Policy Agent
opa-datafilter-jpa-spring-boot-starter
opa-datafilter-mongo-spring-boot-starter
Pre-requisites
The blog posts below explain enough of the What and Why!
- Read about Open Policy Agent Partial (OPA) Evaluation blog post here
- Read the sample use case, Write Policy in OPA. Enforce Policy in SQL
- The OPA Compile API
The Libraries
opa-datafilter-jpa-spring-boot-starter and opa-datafilter-mongo-spring-boot-starter are Spring Boot libraries which can be used together with Spring Data JPA and Spring Data MongoDB, respectively, to enforce authorization on data by filtering using OPA Partial Evaluation feature. When a user wants to access a protected collection of resources, the libraries create a partial request object which contains about the user and the operation a user wants to perform. The partial request object is sent to the OPA compile API. OPA evaluates the partial request and returns a new and simplified policy that can be evaluated more efficiently than the original policy. These libraries convert the new policy, the OPA compile API response, into SQL or MongoDB queries. A filtered collection of data is returned to the user which a user is allowed to see.
Open Policy Agent Supported Version
- Tested in OPA v0.25.0 and below
Supported Spring Data findAll
methods
The libraries override Spring Data methods:
- findAll()
- findAll(Sort sort)
- findAll(Pageable pageable)
Installation and Usage
See each individual folder for installation and usage instructions.
Query Verification
To verify how the SQL or MongoDB query looks like, use the opa-datafilter-datafilter-query-service or the the docker image, opa-query-service. The service provides an API for translating OPA partial request object into a SQL or MongoDB query.
Configurations
Properties | Type | Default Value | Description | Required |
---|---|---|---|---|
opa.authorization.url | String | http://localhost:8181/v1/compile | The OPA compile API endpoint. | Yes |
opa.authorization.data-filter-enabled | Boolean | true | Enable OPA data filter authorization | No |
opa.partial-request.log-partial-request | Boolean | false | Log the partial request json which was sent to OPA on std out for debugging | No |
opa.partial-request.query | String | The query to partially evaluate and compile | Yes | |
opa.partial-request.unknowns | Set | The terms to treat as unknown during partial evaluation | Yes | |
opa.partial-request.user-attribute-to-http-header-map | Map<String, String> | The mapping of user attribute to Http Header. These mappings will be added as subject attributes in the input of the partial request. The key will be set as the attribute name and the value of the Http header will be set as the value of the key. |
No |
Example Spring Boot Applications
See example Spring Boot microservice applications that use these libraries:
The Partial Request
Default Partial Request
When the findAll
method is invoked from OpaDataFilterRepository
interface, a partial request object is sent to the OPA compile API endpoint. The default partial request is the following:
{
"query": "data.petclinic.authz.allow = true",
"input": {
"path": ["pets"],
"method": "GET",
"subject": {
"user": "alice",
"jwt": "<jwt token>"
}
},
"unknowns": ["data.pets"]
}
where:
query
- is the value ofopa.partial-request.query
from the configuration property.input
- by default http servlet path and method are added aspath
andmethod
respectively. Thesubject
(the current user) by default hasuser
property which is derived from Authorization Basic header if it exists andjwt
property from the Authorization Bearer header if it exists.unknowns
- the value ofopa.partial-request.unknowns
from the configuration property.
Adding Attributes to the Default Partial Request
It is possible to add attributes to the subject
property of the default partial request. This can be done by mapping the attribute to the Http header using a configuration opa.partial-request.user-attribute-to-http-header-map
. For example:
opa:
partial-request:
log-partial-request: true
user-attribute-to-http-header-map:
organization: X-ORG-HEADER
The organization
is key of the attribute and the value of the X-ORG-HEADER
http header is the value of the key. The partial request will look like the following:
{
"query": "data.petclinic.authz.allow = true",
"input": {
"path": ["pets"],
"method": "GET",
"subject": {
"user": "alice",
"attributes": {
"organization": "SOMA"
}
}
},
"unknowns": ["data.pets"]
}