owned this note
owned this note
Published
Linked with GitHub
# Boxcarring proposal
Author: Omri Gazitt <omri@aserto.com>
Date: 2024-05-31
## Abstract
The first implementer's draft of the AuthZEN evaluation API takes a single request and returns a single response. This proposal aims to extend this with a capability to piggy-back (or "boxcar") multiple evaluation queries in a single request/response.
## Current message formats
An AuthZEN evaluation request takes a JSON object which has four keys: `subject`, `action`, `resource`, and `context`. These are referred to as the "4-tuple" in the subsequent text. Each of these keys can take a JSON object value, or be omitted.
### Request
~~~json
{
"subject":{
"id": {
"username": "Art",
"jwt": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsIm5hbWUiOiJBcnQgVmFuZGVsYXkiLCJpYXQiOjE1MTYyMzkwMjJ9.QR3kS983lnaRVM1ZVJ_TM7XxJDPppELnCSCV_upUHQIGs28mB4JE_VqC9WBlcCYIYZn_E3r1RXarnFBe5UAy9g"
}
},
"resource":{
"path": "/api/account/123"
},
"action":{
"method": "GET"
},
"context":{
"time": "1985-10-26T01:22-07:00"
}
}
~~~
### Response
The response format for this single request is a JSON object which contains a key called `decision` with a boolean value, and a `context` key with a JSON object value.
~~~ json
{
"decision": true,
"context": {
}
}
~~~
## Boxcarring proposal
To extend this simple request/response format to contain multiple requests, while maintaining backwards-compatibility, we propose the following extension:
### Request
An optional `evaluations` key, with an object-typed value, contains a keyed list JSON objects, each typed as a 4-tuple, and specifying a discrete request.
If an `evaluations` key/value is present and contains one or more objects, these form distinct requests that the PDP will evaluate.
In this case, the top-level `subject`, `action`, `resource`, and `context` keys in the request object can be omitted. However, if any of these values is provided, they provide default values for their respective fields in the evaluation requests in the array.
The following is a non-normative example for specifying three requests (keyed `eval-1`, `eval-2`, and `eval-3`), with no default values:
~~~json
{
"evaluations": {
"eval-1": {
"subject": {
"type": "user",
"id": "omri@aserto.com"
},
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "boxcarring.md"
},
"context":{
"time": "2024-05-31T15:22-07:00"
}
},
"eval-2": {
"subject": {
"type": "user",
"id": "omri@aserto.com"
},
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "subject-search.md"
},
"context":{
"time": "2024-05-31T15:22-07:00"
}
},
"eval-3": {
"subject": {
"type": "user",
"id": "omri@aserto.com"
},
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "resourc-search.md"
},
"context":{
"time": "2024-05-31T15:22-07:00"
}
}
}
}
~~~
#### Default values
While the example above provides the most flexibility in specifying distinct values in each request for every evaluation, it is very common for boxcarred requests to share one or more values of the 4-tuple. For example, evaluations may all refer to a single subject, and/or have the same contextual (environmental) attributes.
Default values offer a more compact syntax that avoids over-duplication of request data.
If any of the top-level `subject`, `action`, `resource`, and `context` keys are provided, they are treated as default values for the 4-tuples specified in the `evaluations` object. Any values specified in the 4-tuples present in the `evaluations` object take precedence over these default values.
The following is a non-normative example for specifying three requests that refer to a single subject and context:
~~~json
{
"subject": {
"type": "user",
"id": "omri@aserto.com"
},
"context":{
"time": "2024-05-31T15:22-07:00"
},
"evaluations": {
"eval-1": {
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "boxcarring.md"
}
},
"eval-2": {
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "subject-search.md"
}
},
"eval-3": {
"action": {
"name": "can_read"
},
"resource": {
"type": "document",
"id": "resourc-search.md"
}
}
}
}
~~~
The following is a non-normative example for specifying three requests that refer to a single `subject` and `context`, with a default value for `action`, that is overridden by the third request:
~~~json
{
"subject": {
"type": "user",
"id": "omri@aserto.com"
},
"context":{
"time": "2024-05-31T15:22-07:00"
},
"action": {
"name": "can_read"
},
"evaluations": {
"eval-1": {
"resource": {
"type": "document",
"id": "boxcarring.md"
}
},
"eval-2": {
"resource": {
"type": "document",
"id": "subject-search.md"
}
},
"eval-3": {
"action": {
"name": "can_edit"
},
"resource": {
"type": "document",
"id": "resourc-search.md"
}
}
]
}
~~~
### Response
Like the request format, the response format for a boxcarred request adds an `evaluations` key that is object-typed, keyed by the request IDs in the `evaluations` object in the request. Each value of the evaluations object is typed as an evaluation response object.
In case the `evaluations` key is present, the `decision` key can be omitted, and if present, can be ignored by the caller.
The following is a non-normative example of a response to a boxcarred request containing three evaluation objects:
~~~json
{
"evaluations": {
"eval-1": {
"decision": true
},
"eval-2": {
"decision": false,
"context": {
"reason": "resource not found"
}
},
"eval-3": {
"decision": false,
"context": {
"reason": "Subject is a viewer of the resource"
}
}
]
}
~~~
### Errors
There are two types of errors, and they are handled differently:
1. Transport-level errors, or errors that pertain to the entire payload.
2. Errors in individual evaluations.
The first type of error is handled at the transport level. For example, for the HTTP binding, the 4XX and 5XX codes indicate a general error that pertains to the entire payload.
The second type of error is handled at the payload level. Decisions default to *closed* (i.e. `false`), but the `context` field can include errors that are specific to that request.
The following is a non-normative example of a response to a boxcarred request containing three evaluation objects, one of them demonstrating how an error can be returned for a single evaluation:
~~~json
{
"evaluations": {
"eval-1": {
"decision": true
},
"eval-2": {
"decision": false,
"context": {
"error": {
"status": 404,
"message": "Resource not found"
}
}
},
"eval-3": {
"decision": false,
"context": {
"reason": "Subject is a viewer of the resource"
}
}
]
}
~~~