Core Documentation
Conditions

Conditions

Ordinarily, the resource field determines the scope of permission conferred (or denied) by a rule. It might broadly grant permission over all resources of a type using the wildcard scope as in FHIR:Patient:* ("all patients"), or it might enumerate specific resources by logical identifier, as in [FHIR:Patient:6eb3a6ef-ed5f-441a-b12f-4ecaf62ea7ab, FHIR:Patient:ac2a8074-25a5-4d74-9ba7-797cded27a6e]\. Sometimes, however, we may not want to grant permissions over all resources, but we may also not know the identifier of every resource we'd like to reference. In other cases, the number of identifiers we'd need to reference would render that enumerative approach impractical. In some cases what we want to do is grant a permission over resources sharing a specific characteristic.

To facilitate such a use case over FHIR resources, ZapEHR offers a FHIR-based condition field. Its function is fairly simple: it grants access over a scope that is defined by the bundle(s) returned from a FHIR query.

The condition field is optional; when used, it must contain a string or list of strings. Furthermore, a number of requirements must be met that reflect the concept's close relationship to the FHIR search specification (opens in a new tab):

  1. The resource field must contain exactly 1 FHIR resource.
  2. The resource field may not reference an individual resource by logical id.
  3. Every member of the condition field must be a valid query expression where the resource field provides the basis for the query.
  4. Executing the query (or queries where a list of conditions is used) must return a Bundle (opens in a new tab) containing only resources of the same type used in the rule's resource field.
  5. The effect must be 'Allow'.

Consider the following use of the condition field:

{
  "rule": [
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Allow",
      "condition": "[email protected]"
    }
  ]
}

Taking the resource as the base, we can formulate the FHIR query expressed by the rule as: [email protected]. This is a valid rule because it expresses a valid search on the Patient resource (opens in a new tab) and the result of the request returns a bundle of Patient-type resources.

The rule grants the FHIR:Read action over all Patient resources that would be returned when the query is executed. Note the role that the condition field is playing in determining the scope of the permission: the presence of the condition field tells ZapEHR to interpret the scope granted by the rule not as "all FHIR:Patient resources", but rather "all FHIR:Patient resources meeting the criteria expressed by the query in the condition field".

Currently, the FHIR service is the only ZapEHR service making use of the condition field, but that may change as the product evolves with the needs of our users.

Multiple Conditions

When multiple conditions are included in the query field, the same rules apply: every member must form a valid query with the resource as the base, and must return a bundle of resources with the same type as the base.

Scope Interpretation

When it comes to interpreting the scope of a rule that contains multiple valid query conditions, ZapEHR applies a disjunctive test. That is, the rule grants its actions over all resources that meet any of the criteria, not just any resource that meets all criteria.

In addition to patients with email "[email protected]", this rule grants FHIR:Read access over all Patients with an appointment with a specific Practitioner:

{
  "rule": [
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Allow",
      "condition": ["[email protected]", "_has:Appointment:patient:practitioner._id=caba8393-b376-48e3-9873-e5deb0b7bae1"]
    }
  ]
}

Note on Evaluation Logic

While the condition field acts to narrow the scope of its rule's resource, it will not act to narrow the scope on that same resource if another rule in the same policy grants the same action with a broader scope. Consider the following example policy:

{
  "rule": [
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Allow",
      "condition": ["[email protected]", "_has:Appointment:patient:practitioner._id=caba8393-b376-48e3-9873-e5deb0b7bae1"]
    },
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:*"],
      "effect": "Allow"
    },
  ]
}

The second rule effectively cancels out the first rule because it grants the FHIR:Read action (and all valid FHIR actions) over all Patient resources.

Invalid Actions

Some actions can't be used in combination with the condition field because they require a scope that can't be applied to scopes narrower than "*" and therefore can't be defined by a fhir query. There are currently two such actions: FHIR:Search and FHIR:Create.

Note however that the catch-all action "FHIR:*" may still be used with the condition, and will be interpreted as "all FHIR actions that can be used with the condition field".

Examples

The "_include" param in this expression adds Organization-type resources to the bundle, which violates the rule requiring the query only return resources matching the type of the resource whose scope it is defining, "Slot", in this case.

{
  "rule": [
    {
      "action": ["FHIR:*"],
      "resource": ["FHIR:Slot"],
      "effect": "Allow",
      "condition": "schedule.actor:Location._id=6eb3a6ef-ed5f-441a-b12f-4ecaf62ea7ab&_include=Location:organization"
    }
  ]
}

Make it valid by splitting into two rules with mono-typed queries:

{
  "rule": [
    {
      "action": "FHIR:*",
      "resource": "FHIR:Slot",
      "effect": "Allow",
      "condition": "schedule.actor:Location._id=6eb3a6ef-ed5f-441a-b12f-4ecaf62ea7ab"
    },
    {
      "action": ["FHIR:*"],
      "resource": "FHIR:Organization",
      "effect": "Allow",
      "condition": "_has:Location:organization:_id=6eb3a6ef-ed5f-441a-b12f-4ecaf62ea7ab"
    }
  ]
}

This rule is invalid because it uses "Deny" in the effect field:

{
  "rule": [
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Allow",
    },
    {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Deny",
      "condition": "[email protected]"
    }
  ]
}

Make it valid by restating as a single "Allow" rule:

{
  "rule":  {
      "resource": "FHIR:Patient:*", 
      "action": ["FHIR:Read"],
      "effect": "Allow",
      "condition": "email:[email protected]"
    }
}