owned this note
owned this note
Published
Linked with GitHub
# Attribute Store & Policy Store
**Contents**
[TOC]
## Attribute Store
XACML: [The system entity that acts as a source of attribute values (i.e. a resource, subject, environment)](https://en.wikipedia.org/wiki/XACML#Terminology)
### URI
- `xain:eth:id/balanceOf?address=0x123` (just a proposal)
- `xain` is the scheme (is always `xain`)
- `eth` is the name of the authority / system (`eth` means ethereum mainnet)
- `id` is the id of an object (e.g. the address of a smart contract)
- `balanceOf` is the path (e.g. the method of the smart contract)
- `?address=0x123` is the query (e.g. the parameter `address` of the method `balanceOf`)
The **Attribute Store** is an alias for the **Policy Information Point**.
### Interface for the Attribute Store
```javascript
interface attribute_store {
function fetch(uri) return attribute_object or error
}
```
The `attribute_store` has a list of `resolver`s. There is a `resolver` for each `authority`, e.g. one for the ethereum mainnet and another one for the big data architecture and so on. Each `resolver` is responsible for getting the `attribute_object` for the given `URI`.
The `attribute_store` needs to parse the `URI` and has to validate the schema of the `URI`. It has to check if there is a `resolver` listed for the given `authority` and thus decides which `resolver` is selected based on the name of the `authority`.
If the schema is valid and a `resolver` exists, the call is delegated to the specific `resolver`. If the `resolver` returns an `attribute_object`, then the `attribute_store` in turn passes this `attribute_object`, otherwise an `error` is returned.
The instance calling the `attribute_store` might cache `attribute_object`s. Reasonable time frames have to be considered for the validity of the cached `attribute_object` to avoid caching outdated or altered values. A flag `is_cachable` might be needed.
### Interface for the Resolver
```javascript
interface resolver {
function fetch(uri) return attribute_object or error
}
```
The `resolver` has to validate the schema of the `URI` and additionally it has to retrieve and return an `attribute_object`. If the schema is valid and a the `attribute_object` can be retrieved, this `attribute_object` is returned, otherwise an `error` is returned.
### Attribute Objects `attribute_object`
An `attribute_object` could contain just a (`type`, `value`)-pair, e.g.
```json
{
"@type": "http://www.w3.org/2001/XMLSchema#dateTime",
"@value": "2011-04-09T20:00Z"
}
```
It could also contain a more complex object, e.g.
```json
Vehicle {
"@context": {
"resource":"https://xain.io/contexts/resource.jsonld",
"crypto": "https://xain.io/contexts/crypto.jsonld"
},
"crypto:publicKey": "0xDBE...",
"resource:owner": {
"@id": "xain:bda:id_of_owner", // a link to another object
"@type": "@id"
}
}
```
```json
Owner {
"@context": {
"person":"https://xain.io/contexts/person.jsonld",
"crypto": "https://xain.io/contexts/crypto.jsonld"
},
"crypto:publicKey": "0x231...",
"person:siblings": {
"@id": "xain:bda:id_of_daughter", // a link to another object
"@type": "@id"
}
}
Daughter {
"@context": "https://xain.io/contexts/crypto.jsonld",
"publicKey": "0xAAA..."
}
```
- To get the daughter's public key, the URI could look like this: `xain:bda:id_of_vehicle#owner.siblings.daughter.publicKey`
## Policy Store
XACML: [Point where the policies are stored](https://en.wikipedia.org/wiki/XACML#Terminology)
### Interface of the policy store (on device)
```javascript
interface policy_store {
function put({id: policy_id, policy: policy_object, signature: policy_id_signature, hash: hash_function}) return boolean or error
function get(id: policy_id) return {policy : policy_object, signature: policy_id_signature, hash: hash_function} / false or error
function has(id: policy_id) return boolean or error
function del(id: policy_id) return boolean or error
}
```
Every record in the policy store consists of a (`policy_id`, `policy_object`, `policy_id_signature`, `hash_function`)-tuple, where the `policy_id` is used as an unique identifier for the record later on.
The function `put` tries to create a new record in the `policy_store` and returns either `true` on success or an `error` otherwise. The `policy_store` must normalize the `policy_object` (see section [Policy normalization](#Policy-normalization)) -- this is of the same complexity and computational cost as checking if it is already normalized. Furthermore, the `policy_store` must check if it knows the `hash_function`, then calculate the hash of the `policy_object` under the `hash_function` and compare it to the `policy_id`. Finally, the `policy_store` must check if it knows the `signature_algorithm` of the `policy_id_signature` and then attempt to verify the `policy_id_signature` (see section [Policy signatures](#Policy-signatures-policy_id_signature)).
The functions `get` and `has` try to retrieve a record from the `policy_store` and return either a (`policy_object`, `policy_id_signature`, `hash_function`)-triple or `true` if it exists, respectively, or return `false` if it doesn't exist or return an `error` otherwise.
The function `del` tries to delete a record and returns either `true` on success or an `error` otherwise. It might be necessary for the `policy_store` to keep the `policy_id` of a deleted record in a tombstone set.
The function `put` is meant as a create operation and not as an update operation and applying `put` to a record that already exists in the `policy_store` should result in an `error`. Updating a policy should only be done in an atomic way by `del` and then `put`, since a changed `policy_object` doesn't relate to its old `policy_id` and `policy_id_signature` due to the collision resistance of the `hash_function`.
The function `has` could be seen as a subfunctionality of `get`, where both are read operations. Both return `false` on non-existence or `error` on errors and they differ only in returning `true` or a (`policy_object`, `policy_id_signature`, `hash_function`)-triple on existence.
### Policy objects `policy_object`
The `policy_object` consists of `policy_goc`, `policy_doc` and the `obligation_grant`, `obligation_deny` objects (Boolean circuits). In case of conflict- and gap-free policies (`policy_goc` equals `policy_doc`) it might be better memory-wise to story only one of the two and let the other reference to the former.
```json
{
"policy_goc": {...},
"policy_doc": {...},
"obligation_grant": {...},
"obligation_deny": {...}
}
```
See also the section on [generalized policy objects](https://hackmd.io/t5YMLzMCRQ2CEVEER2Vzpg?view#Generalized-Policy-Objects) in the compilation document, which extends the above notation into a uniform approach for policies as well as obligation policies.
### Unique policy identifiers `policy_id`
The `policy_id` is the hash of the `policy_object` under the hash function specified by `hash_function`. The `policy_id` of the `policy_object` must always be the same, even if the syntax of the `policy_object` is different, see the following example.
#### Example
```json
{
"constant": "object",
"operation": "eq",
"attribute_list": [...]
}
```
```json
{
"attribute_list": [...],
"constant": "object",
"operation": "eq"
}
```
The semantics for these two `policy_object`s are identical but the syntax is not, i.e. the hash would be different for the same semantic objects. This could be solved by normalizing the `policy_object`.
#### Policy normalization
Normalizing a JSON object means removing all spaces, sorting the keys and ensuring that everything is encoded in UTF-8. It is important that the order of the elements within an array remains the same, since the reordering of these lists could change the semantic meaning of the operation applied to the list (e.g. `"leq"` on two-element array).
Note that this only aims at normalizing the `policy_object` representing the policy, a further step would be to simplify the Boolean circuits before storing them in the `policy_object`. In the latter case special care has to be taken regarding the compilation of obligations.
```json
{
// the keys must be sorted
"obligation_deny": {
// the keys must be sorted
[
// the order of the elements must not be changed
]
},
"obligation_grant": {
// the keys must be sorted
[
// the order of the elements must not be changed
{
// the keys must be sorted
"attr": "org.openvehicle_api_v1.23.1_vehicle.methods.openDoors",
"method": "org.openvehicle_api_v1.23.1_vehicle.methods"
},
{
// the keys must be sorted
"attr": "org.openvehicle_api_v1.23.1_vehicle.methods.startEngine",
"method": "org.openvehicle_api_v1.23.1_vehicle.methods"
}
]
},
"policy_doc": {
// the keys must be sorted
"$and": [
// the order of the elements must not be changed
{
// the keys must be sorted
"constant": "object",
"operation": "eq",
...
},
...
]
},
"policy_goc": {
// the keys must be sorted
...
}
}
```
#### Policy ID with policy normalization
Therefore, the `policy_id` is the hash of the normalized `policy_object`:
```
policy_id = hash_function(JSONNormalize(policy_object))
```
The validity of the `policy_id` can be verified, e.g. by the `policy_store`, by normalizing the `policy_object` and hashing this under the `hash_function`.
### Policy signatures `policy_id_signature`
The `policy_id_signature` is the object containing the `signature` defined by the `signature_algorithm` over the `policy_id`. It includes the `public_key` of the signer to provide all necessary information for verification.
```json
{
"signature_algorithm": "...",
"signature" : "...",
"public_key" : "..."
}
```
The validity of the `signature` from the `policy_id_signature` object can be verified, e.g. by the `policy_store`, by applying the `signature_algorithm` to the `signature` and the `public_key`.
### Policy store implemented as a key value store
The `policy_store` might be implemented as a key-value-store, where the keys are the `policy_id`s and the values are the (`policy_object`,`policy_id_signature`,`hash_function`)-triples.
```json
{
"policy_id" : {
"policy" : policy_object,
"signature": policy_id_signature,
"hash": hash_function
},
...
}
```