# Decisions for partial evaluation API ## Top level response options (allow/deny/partial) How should we indicate, at the top-level, whether an evaluation is partial or full with a given result? ### Deny and allow operators ``` json { "decision": { "operator": "allow" } } ``` ``` json { "decision": { "operator": "deny" } } ``` Given that operators can be nested; how should the below case be interpreted though? ``` json { "decision": { "operator": "or", "terms": [ { "operator": "eq", "field": "author", "value": "bob@example.com" }, { "operator": "allow" } ] } } ``` ### Fixed value operator An operator can be introduced that always returns a fixed value; which can then be used to indicate allow or deny decisions. ``` json { "decision": { "operator": "fixedValue", "value" : false } } ``` ### Equality operator The equality operator could be used to create the equivalent of `WHERE 1 == 2`. ``` json { "decision": { "operator": "eq", "field": "1", "value" : "2" } } ``` ### Top-level decision object with result type A top-level object could be introduced to explicitly describe the type of decision. ``` json { "decision": { "result-type": "allow" } } ``` ``` json { "decision": { "result-type": "deny" } } ``` ``` json { "decision": { "result-type": "partial", "residual-filter": { "operator": "eq", "field": "author", "value": "bob@example.com" } } } ``` ## Enabling logical composition How do we want do enable multiple operators to be logically combined with and/or/not/xor logic etc. ### Logical composition as 'just another operator' ``` json { "operator": "or", "terms": [ { "operator": "eq", "field": "author", "value": "bob@example.com" }, { "operator": "and", "terms": [ { "operator": "eq", "field": "public", "value": true }, { "operator": "not", "term": { "operator": "in", "field": "tags", "value": "sensitive" } } ] } ] } ``` ### Special casing for logical composition ``` json { "or": [ { "operator": "eq", "field": "author", "value": "bob@example.com" }, { "and": [ { "operator": "eq", "field": "public", "value": true }, { "not": { "operator": "in", "field": "tags", "value": "sensitive" } } ] } ] } ``` ## Custom operators How do we want to enable custom operators not defined by AuthZEN standard itself? ### Namespaced operator names Define a mechanism for namespacing; such as dot notation, and reserve the main namespace for AuthZEN For example ``` { "operator": "eq" } ``` and ``` { "operator": "org.fhir.query", "query": "Patient?_has:Observation:patient:_has:AuditEvent:entity:agent:Practitioner.name=janedoe" } ``` ### Namespacing field Define a dedicated field in the operator object to indicate the source of the operator. The fieldname could be something like `source`, `module` or just `namespace`. Third party operators would then look something like this: ``` { "namespace": "org.fhir" "operator": "query", "query": "Patient?_has:Observation:patient:_has:AuditEvent:entity:agent:Practitioner.name=janedoe" } ``` And AuthZEN's own operators would be taken as default value. ``` { "operator": "eq" } ``` is equivalent to ``` { "namespace": "net.openid.authzen", "operator": "eq" } ``` ## Function composition ### String expressions in regular operators ``` json { "operator": "eq", "field": "lowercase(author)", "value": "bob@example.com" } ``` Question: do we allow multiple fields there? So e.g. ``` json { "operator": "eq", "field": "concat(username,\"@\",domain)", "value": "bob@example.com" } ``` Question: do we allow other operators there as well? So e.g. ``` json { "operator": "eq", "field": "not(length(author)>99)", "value": true } ``` ### Nested operators ``` json { "operator": "eq", "field": { "operator": "lowercase", "value": "author" }, "value": "bob@example.com" } ``` ## Differentiating between values and references to fields/variables When allowing operators to be composed/nested the inputs to operators can sometimes by values and sometimes references to fields. For example when you concatenate fieds together into a URL or email; concat(username,"@",domain). ### Placeholder syntax We can specify explicitly which values are references to a field/variable by e.g placing it inside a `${...}` block or something of that sort. Then you would get examples like this: ``` json { "operator": "eq", "field": "${author}", "value": "bob@example.com" } ``` ``` json { "operator": "eq", "field": "lowercase(${author})", "value": "bob@example.com" } ``` ``` json { "operator": "in", "field": "merge(${author},${editors})", "value": "bob@example.com" } ``` ``` json { "operator": "eq", "field": "concat(${username},\"@\",${domain})", "value": "bob@example.com" } ``` Note: `field` and `value` make less sense as names anymore in this case. `leftHand` and `rightHand` or `first` and `second` would then be more logica ### Nested operators with `field` vs `value` convention Another way to approach this is to adopt nested operators instead and use the convention that in an operator a `field` is resolved while a `value` is used directly. This would get you things like ``` json { "operator": "eq", "field": "author", "value": "bob@example.com" } ``` ``` json { "operator": "eq", "field": { "operator": "lowercase", "field": "author" }, "value": { "operator": "lowercase", "value": "Bob@example.com" } } ``` ``` json { "operator": "in", "field": { "operator": "merge", "fields": ["author","editors"] }, "value": "bob@example.com" } ``` ``` json { "operator": "eq", "field": { "operator": "concat", "values": ["??username??","@","??domain??"] }, "value": "bob@example.com" } ``` Note: I can't really see how to make the switching between values and references in the concatenation values would work. ### Dedicated "field" operator to resolve fields You could specify a special operator that resolves fields and assume that everything else is just a value. I've renamed the equality operator fields to 'firstValue' and 'secondValue' for clarity. ``` json { "operator": "eq", "firstValue": { "operator": "field", "name": "author" }, "secondValue": "bob@example.com" } ``` ``` json { "operator": "eq", "firstValue": { "operator": "lowercase", "value": { "operator": "field", "name": "author" } }, "secondValue": { "operator": "lowercase", "value": "Bob@example.com" } } ``` ``` json { "operator": "in", "firstValue": { "operator": "merge", "lists": [ { "operator": "field", "name": "author" }, { "operator": "field", "name": "editors" } ] }, "secondValue": "bob@example.com" } ``` ``` json { "operator": "eq", "firstValue": { "operator": "concat", "values": [ { "operator": "field", "name": "username" }, "@", { "operator": "field", "name": "domain" } ] }, "secondValue": "bob@example.com" } ```