The IHE Basic Audit Log Patterns implementation guide describes a set of workflows and data models for the creation of AuditEvent resources based on user/client actions.
HAPI FHIR provides an interceptor that can be registered against a server, and will observe events on that server and automatically generate AuditEvent resources which are conformant to the appropriate profiles within the BALP specification.
This interceptor implements the following profiles:
BALP Profile | Trigger | Triggering Pointcut |
---|---|---|
Create | Performed when a resource has been created that is not a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_CREATED |
PatientCreate | Performed when a resource has been created that is a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_CREATED |
Read |
Performed when a resource has been read that is not a member of the Patient compartment.
Note that
other extended operations which expose individual resource data may also trigger the creation of
an AuditEvent with this profile. For example, the $diff operation exposes data within
a resource, so it will also trigger this event.
|
STORAGE_PRESHOW_RESOURCES |
PatientRead |
Performed when a resource has been read that is a member of the Patient compartment.
Note that
other extended operations which expose individual resource data may also trigger the creation of
an AuditEvent with this profile. For example, the $diff operation exposes data within
a resource, so it will also trigger this event.
|
STORAGE_PRESHOW_RESOURCES |
Update | Performed when a resource has been updated that is not a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_UPDATED |
PatientUpdate | Performed when a resource has been updated that is a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_UPDATED |
Delete | Performed when a resource has been deleted that is not a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_DELETED |
PatientDelete | Performed when a resource has been deleted that is a member of the Patient compartment. | STORAGE_PRECOMMIT_RESOURCE_DELETED |
Query | Performed when a non-patient-oriented search is performed. This refers to a search that is returning data that is not in a specific patient compartment. | STORAGE_PRESHOW_RESOURCES |
PatientQuery | Performed when a patient-oriented search is performed. This refers to a search that returns data in a specific patient compartment. | STORAGE_PRESHOW_RESOURCES |
The HAPI FHIR BALP infrastructure consists of the following components:
The BALP IBalpAuditEventSink receives and handles generated audit events.
This interface is designed to support custom implementations, so you can absolutely create your own. HAPI FHIR ships with the following implementation:
If you create an implementation of this interface that you think would be useful to others, we would welcome community contributions!
In order to use this interceptor, you must suply an instance of IBalpAuditContextServices. This interface supplies the information about each request that the interceptor cannot determine on its own, such as the identity of the requesting user and the requesting client.
The implementation of this interface for the public HAPI FHIR server is available here.
The following example shows a simple implementation of the Context Services:
public class ExampleBalpAuditContextServices implements IBalpAuditContextServices {
/**
* Here we are just hard-coding a simple display name. In a real implementation
* we should use the actual identity of the requesting client.
*/
@Nonnull
@Override
public Reference getAgentClientWho(RequestDetails theRequestDetails) {
Reference client = new Reference();
client.setDisplay("Growth Chart Application");
client.getIdentifier().setSystem("http://example.org/clients").setValue("growth_chart");
return client;
}
/**
* Here we are just hard-coding a simple display name. In a real implementation
* we should use the actual identity of the requesting user.
*/
@Nonnull
@Override
public Reference getAgentUserWho(RequestDetails theRequestDetails) {
Reference user = new Reference();
user.getIdentifier().setSystem("http://example.org/users").setValue("my_username");
return user;
}
}
And the following example shows a HAPI FHIR Basic Server with the BALP interceptor wired in:
public class MyServer extends RestfulServer {
/**
* Constructor
*/
public MyServer() {
super(FhirContext.forR4Cached());
}
@Override
protected void initialize() throws ServletException {
// Register your resource providers and other interceptors here...
/*
* Create our context sservices object
*/
IBalpAuditContextServices contextServices = new ExampleBalpAuditContextServices();
/*
* Create our event sink
*/
FhirContext fhirContext = FhirContext.forR4Cached();
String targetUrl = "http://my.fhir.server/baseR4";
List<Object> clientInterceptors = List.of(
// We'll register an auth interceptor against the sink FHIR client so that
// credentials get passed to the target server. Of course in a real implementation
// you should never hard code credentials like this.
new BasicAuthInterceptor("username", "password"));
IBalpAuditEventSink eventSink =
new AsyncMemoryQueueBackedFhirClientBalpSink(fhirContext, targetUrl, clientInterceptors);
}
}