Hi all,
I’m currently looking into implementing authorization checks onto our HAPI FHIR store. Our store is accessed by applications (not users) as SMART Backend Services. Every application has their own client_id
and their own Device
instance.
I’ve written an interceptor, that adds an extension (resource-origin: Reference(Device)) to every DomainResource
that gets persisted. This way we can track who originally created and “owns” a resource.
The next step is to implement an Authorization Interceptor and a Search Narrowing Interceptor. As they both use compartments, the logical step seemed to be to create a CompartmentDefinition that groups any DomainResource
created by an application to its own “application compartment” via the newly created resource-origin
extension. So the following CompartmentDefinition
is created:
PUT {{baseUrl}}/CompartmentDefinition/ResourceOrigin
{
"resourceType": "CompartmentDefinition",
...
"id": "ResourceOrigin",
"name": "ResourceOrigin",
"search": true,
"code": "Device",
"resource": [
{"code": "ActivityDefinition", "param": ["resource-origin"]},
{"code": "CareTeam", "param": ["resource-origin"]},
...
]
}
I can successfully create the CompartmentDefinition
, but I’m unsure on how to use this in combination with the interceptor. It felt like the following should work:
@Override
public List<IAuthRule> buildRuleList(RequestDetails requestDetails) {
Device device = ResourceOriginUtil.getDevice(requestDetails, deviceDao)
.orElseThrow(() -> new IllegalStateException("Device not present"));
return new RuleBuilder()
.allow().read().allResources().inCompartment("ResourceOrigin", device.getIdElement())
.andThen().denyAll().build();
}
When the interceptor is being executed, I always get the following response:
{
"resourceType": "OperationOutcome",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h1>Operation Outcome</h1><table border=\"0\"><tr><td style=\"font-weight: bold;\">ERROR</td><td>[]</td><td><pre>Access denied by rule: (unnamed rule)</pre></td>\n\t\t\t</tr>\n\t\t</table>\n\t</div>"
},
"issue": [ {
"severity": "error",
"code": "processing",
"diagnostics": "Access denied by rule: (unnamed rule)"
} ]
}
HL7 does mention they are only allowed to create CompartmentDefinitions
. I am unsure if this counts for HAPI as it’s not mentioned in the HAPI documentation and they use compartments as the core of the authorization & search narrowing interceptors.
So my questions are:
- Is the above a good approach to handling authorizations in HAPI?
- If not, what would be a “best practice” alternative?
- If it is, how should I refer to a compartment for a specific
Device
? So for example: allow to read all resources that have the resource-origin extension with value ABC. - Does the
RuleBuilder.inCompartment(String theCompartmentName, IIdType theOwner)
find the compartment based on theCompartmentDefinition.name
property? - I’ve also seen an approach where they seem to overwrite the
CompartmentDefinition
. Would this be an option for HAPI as well if the above is not possible?
Thanks in advance,
Joris