Try   HackMD

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

{
  "decision": {
    "operator": "allow"  
  }
}
{
  "decision": {
    "operator": "deny"  
  }
}

Given that operators can be nested; how should the below case be interpreted though?

{
  "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.

{
  "decision": {
    "operator": "fixedValue",
    "value" : false  
  }
}

Equality operator

The equality operator could be used to create the equivalent of WHERE 1 == 2.

{
  "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.

{
  "decision": {
    "result-type": "allow"  
  }
}
{
  "decision": {
    "result-type": "deny"  
  }
}
{
  "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'

{
  "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

{
  "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

{
  "operator": "eq",
  "field": "lowercase(author)",
  "value": "bob@example.com"
}

Question: do we allow multiple fields there? So e.g.

{
  "operator": "eq",
  "field": "concat(username,\"@\",domain)",
  "value": "bob@example.com"
}

Question: do we allow other operators there as well? So e.g.

{
  "operator": "eq",
  "field": "not(length(author)>99)",
  "value": true
}

Nested operators

{
  "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:

{
  "operator": "eq",
  "field": "${author}",
  "value": "bob@example.com"
}
{
  "operator": "eq",
  "field": "lowercase(${author})",
  "value": "bob@example.com"
}
{
  "operator": "in",
  "field": "merge(${author},${editors})",
  "value": "bob@example.com"
}
{
  "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

{
  "operator": "eq",
  "field": "author",
  "value": "bob@example.com"
}
{
  "operator": "eq",
  "field": {
    "operator": "lowercase", 
    "field": "author"
  },
  "value": {
    "operator": "lowercase", 
    "value": "Bob@example.com"
  }
}
{
  "operator": "in",
  "field": { 
    "operator": "merge",
    "fields": ["author","editors"]
  },
  "value": "bob@example.com"
}
{
  "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.

{
  "operator": "eq",
  "firstValue": { 
    "operator": "field", 
    "name": "author"
  },
  "secondValue": "bob@example.com"
}
{
  "operator": "eq",
  "firstValue": {
    "operator": "lowercase", 
    "value": { 
      "operator": "field", 
      "name": "author"
    }
  },
  "secondValue": {
    "operator": "lowercase", 
    "value": "Bob@example.com"
  }
}
{
  "operator": "in",
  "firstValue": { 
    "operator": "merge",
    "lists": [
      { 
        "operator": "field", 
        "name": "author"
      },
      { 
        "operator": "field", 
        "name": "editors"
      }
    ]
  },
  "secondValue": "bob@example.com"
}
{
  "operator": "eq",
  "firstValue": {
    "operator": "concat",
    "values": [
      { 
        "operator": "field", 
        "name": "username"
      },
      "@",
      { 
        "operator": "field", 
        "name": "domain"
      }
    ]
  },
  "secondValue": "bob@example.com"
}