added AuditingInterceptor and IAuditDataStore with various ResourceAuditors to provide pluggable auditing functionality to FHIR server
This commit is contained in:
parent
cb8dca13d2
commit
e0d160ad7e
|
@ -0,0 +1,79 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
public class DiagnosticReportAuditor implements IResourceAuditor<DiagnosticReport> {
|
||||
|
||||
DiagnosticReport myDiagnosticReport;
|
||||
|
||||
@Override
|
||||
public boolean isAuditable() {
|
||||
return myDiagnosticReport != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if(myDiagnosticReport != null){
|
||||
return myDiagnosticReport.getName().getText().getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDt getIdentifier() {
|
||||
if(myDiagnosticReport != null){
|
||||
return myDiagnosticReport.getIdentifier();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectTypeEnum getType() {
|
||||
return SecurityEventObjectTypeEnum.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiagnosticReport getResource() {
|
||||
return myDiagnosticReport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(DiagnosticReport theDiagnosticReport) {
|
||||
myDiagnosticReport = theDiagnosticReport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null; //name and ID should suffice for audit purposes
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectDetail> getDetail() {
|
||||
List<ObjectDetail> details = new ArrayList<ObjectDetail>();
|
||||
details.add(makeObjectDetail("dateIssued", myDiagnosticReport.getIssued().getValueAsString()));
|
||||
details.add(makeObjectDetail("version", myDiagnosticReport.getId().getVersionIdPart()));
|
||||
return details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity() {
|
||||
return null; //no sensitivity indicated
|
||||
}
|
||||
|
||||
private ObjectDetail makeObjectDetail(String type, String value) {
|
||||
ObjectDetail detail = new ObjectDetail();
|
||||
if(type != null)
|
||||
detail.setType(type);
|
||||
if(value != null)
|
||||
detail.setValue(value.getBytes());
|
||||
return detail;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Encounter;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
public class EncounterAuditor implements IResourceAuditor<Encounter> {
|
||||
|
||||
private Encounter myEncounter;
|
||||
|
||||
@Override
|
||||
public Encounter getResource() {
|
||||
return myEncounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(Encounter theEncounter) {
|
||||
myEncounter = theEncounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuditable() {
|
||||
return myEncounter != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if(myEncounter != null){
|
||||
String id = myEncounter.getIdentifierFirstRep().getValue().getValue();
|
||||
String system = myEncounter.getIdentifierFirstRep().getSystem().getValueAsString();
|
||||
String service = myEncounter.getServiceProvider().getDisplay().getValue();
|
||||
return id + "/" + system + ": " + service;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDt getIdentifier() {
|
||||
if(myEncounter != null){
|
||||
return myEncounter.getIdentifierFirstRep();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectTypeEnum getType() {
|
||||
return SecurityEventObjectTypeEnum.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
if(myEncounter != null){
|
||||
String type = myEncounter.getTypeFirstRep().getText().getValue();
|
||||
String status = myEncounter.getStatus().getValueAsString();
|
||||
String startDate = myEncounter.getPeriod().getStart().getValueAsString();
|
||||
String endDate = myEncounter.getPeriod().getEnd().getValueAsString();
|
||||
return type + ": " + status +", "+ startDate + " - " + endDate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectDetail> getDetail() {
|
||||
List<ObjectDetail> details = new ArrayList<ObjectDetail>();
|
||||
details.add(makeObjectDetail("startDate", myEncounter.getPeriod().getStart().getValueAsString()));
|
||||
details.add(makeObjectDetail("endDate", myEncounter.getPeriod().getEnd().getValueAsString()));
|
||||
details.add(makeObjectDetail("service", myEncounter.getServiceProvider().getDisplay().getValue()));
|
||||
details.add(makeObjectDetail("type", myEncounter.getTypeFirstRep().getText().getValue()));
|
||||
details.add(makeObjectDetail("status", myEncounter.getStatus().getValueAsString()));
|
||||
return details;
|
||||
}
|
||||
|
||||
private ObjectDetail makeObjectDetail(String type, String value) {
|
||||
ObjectDetail detail = new ObjectDetail();
|
||||
if(type != null)
|
||||
detail.setType(type);
|
||||
if(value != null)
|
||||
detail.setValue(value.getBytes());
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity() {
|
||||
//override this method to provide sensitivity information about the visit
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
|
||||
public interface IResourceAuditor<T extends IResource> {
|
||||
|
||||
public T getResource();
|
||||
public void setResource(T resource);
|
||||
|
||||
public boolean isAuditable();
|
||||
|
||||
public String getName();
|
||||
public IdentifierDt getIdentifier();
|
||||
public SecurityEventObjectTypeEnum getType();
|
||||
public String getDescription();
|
||||
public List<ObjectDetail> getDetail();
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity();
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Medication;
|
||||
import ca.uhn.fhir.model.dstu.resource.MedicationPrescription;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
public class MedicationPrescriptionAuditor implements IResourceAuditor<MedicationPrescription> {
|
||||
|
||||
MedicationPrescription myMedicationPrescription;
|
||||
|
||||
@Override
|
||||
public boolean isAuditable() {
|
||||
return myMedicationPrescription != null; //if we have a medication prescription, we want to audit it
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if(myMedicationPrescription != null){
|
||||
if(myMedicationPrescription.getMedication() != null){
|
||||
Medication m = (Medication) myMedicationPrescription.getMedication().getResource();
|
||||
if(m != null){
|
||||
return m.getName().getValue();
|
||||
}
|
||||
}
|
||||
return myMedicationPrescription.getId().getValueAsString(); //if we don't have a medication name, use the id as the name
|
||||
}
|
||||
return ""; //no medication prescription, nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDt getIdentifier() {
|
||||
if(myMedicationPrescription != null){
|
||||
return myMedicationPrescription.getIdentifierFirstRep();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectTypeEnum getType() {
|
||||
return SecurityEventObjectTypeEnum.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MedicationPrescription getResource() {
|
||||
return myMedicationPrescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(MedicationPrescription theMedicationPrescription) {
|
||||
myMedicationPrescription = theMedicationPrescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null; //name and ID should suffice for audit purposes
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectDetail> getDetail() {
|
||||
return null; //no additional details required for audit?
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity() {
|
||||
return null; //no sensitivity indicated in MedicationPrescription
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Medication;
|
||||
import ca.uhn.fhir.model.dstu.resource.MedicationStatement;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
public class MedicationStatementAuditor implements IResourceAuditor<MedicationStatement> {
|
||||
|
||||
MedicationStatement myMedicationStatement;
|
||||
|
||||
@Override
|
||||
public boolean isAuditable() {
|
||||
return myMedicationStatement != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if(myMedicationStatement != null){
|
||||
Medication m = (Medication) myMedicationStatement.getMedication().getResource();
|
||||
if(m != null){
|
||||
return m.getName().getValue();
|
||||
}
|
||||
return myMedicationStatement.getId().getValueAsString(); //if we don't have a medication name, use the id as the name
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDt getIdentifier() {
|
||||
if(myMedicationStatement != null){
|
||||
return myMedicationStatement.getIdentifierFirstRep();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectTypeEnum getType() {
|
||||
return SecurityEventObjectTypeEnum.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MedicationStatement getResource() {
|
||||
return myMedicationStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(MedicationStatement theMedicationPrescription) {
|
||||
myMedicationStatement = theMedicationPrescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null; //name and ID should suffice for audit purposes
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectDetail> getDetail() {
|
||||
return null; //no additional details required for audit?
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity() {
|
||||
return null; //no sensitivity indicated in MedicationStatement
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package ca.uhn.fhir.rest.server.audit;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectDetail;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
|
||||
|
||||
public class PatientAuditor implements IResourceAuditor<Patient> {
|
||||
|
||||
private Patient myPatient;
|
||||
|
||||
@Override
|
||||
public boolean isAuditable() {
|
||||
return myPatient != null; //if we have a patient, we want to audit it
|
||||
}
|
||||
|
||||
@Override
|
||||
public Patient getResource() {
|
||||
return myPatient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(Patient thePatient) {
|
||||
myPatient = thePatient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if(myPatient != null){
|
||||
return myPatient.getNameFirstRep().getText().getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDt getIdentifier() {
|
||||
if(myPatient != null){
|
||||
return myPatient.getIdentifierFirstRep();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectTypeEnum getType() {
|
||||
return SecurityEventObjectTypeEnum.PERSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null; //name + identifier ought to suffice?
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ObjectDetail> getDetail() {
|
||||
if(myPatient != null){
|
||||
List<IdentifierDt> ids = myPatient.getIdentifier();
|
||||
if(ids != null && !ids.isEmpty()){
|
||||
List<ObjectDetail> detailList = new ArrayList<ObjectDetail>(ids.size());
|
||||
for(IdentifierDt id: ids){
|
||||
ObjectDetail detail = new ObjectDetail();
|
||||
detail.setType(id.getSystem().getValueAsString());
|
||||
try {
|
||||
detail.setValue(id.getValue().getValueAsString().getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
detail.setValue(id.getValue().getValueAsString().getBytes());
|
||||
}
|
||||
detailList.add(detail);
|
||||
}
|
||||
return detailList;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityEventObjectSensitivityEnum getSensitivity() {
|
||||
return null; //override to include things like locked patient records
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ObjectElement;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.Participant;
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent.ParticipantNetwork;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectLifecycleEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SecurityEventParticipantNetworkTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.UserInfoInterceptor;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.audit.IResourceAuditor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.store.IAuditDataStore;
|
||||
|
||||
public class AuditingInterceptor extends InterceptorAdapter {
|
||||
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuditingInterceptor.class);
|
||||
|
||||
private IAuditDataStore myDataStore;
|
||||
private Map<ResourceTypeEnum, Class<? extends IResourceAuditor<? extends IResource>>> myAuditableResources = new HashMap<ResourceTypeEnum, Class<? extends IResourceAuditor<? extends IResource>>>();
|
||||
|
||||
@Override
|
||||
public boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||
throws AuthenticationException {
|
||||
try{
|
||||
log.info("Auditing bundle: " + theResponseObject + " from request " + theRequestDetails);
|
||||
SecurityEvent auditEvent = new SecurityEvent();
|
||||
|
||||
SecurityEventObjectLifecycleEnum lifecycle = mapResourceTypeToSecurityLifecycle(theRequestDetails.getResourceOperationType());
|
||||
boolean hasAuditableEntry = false;
|
||||
byte[] query = getQueryFromRequestDetails(theRequestDetails);
|
||||
for(BundleEntry entry: theResponseObject.getEntries()){
|
||||
IResource resource = entry.getResource();
|
||||
boolean hasAuditableEntryInResource = addResourceObjectToEvent(auditEvent, resource, lifecycle, query);
|
||||
if(hasAuditableEntryInResource) hasAuditableEntry = true;
|
||||
}
|
||||
if(!hasAuditableEntry) return true; //no PHI to audit
|
||||
addParticipantToEvent(theServletRequest, auditEvent);
|
||||
store(auditEvent);
|
||||
return true;
|
||||
}catch(Exception e){
|
||||
log.error("Unable to audit resource: " + theResponseObject + " from request: " + theRequestDetails, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void store(SecurityEvent auditEvent) {
|
||||
if(myDataStore == null) throw new InternalErrorException("No data store provided to persist audit events");
|
||||
myDataStore.store(auditEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean outgoingResponse(RequestDetails theRequestDetails, IResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||
throws AuthenticationException {
|
||||
try{
|
||||
log.info("Auditing resource: " + theResponseObject + " from request: " + theRequestDetails);
|
||||
SecurityEvent auditEvent = new SecurityEvent();
|
||||
byte[] query = getQueryFromRequestDetails(theRequestDetails);
|
||||
SecurityEventObjectLifecycleEnum lifecycle = mapResourceTypeToSecurityLifecycle(theRequestDetails.getResourceOperationType());
|
||||
boolean hasAuditableEntry = addResourceObjectToEvent(auditEvent, theResponseObject, lifecycle , query);
|
||||
if(!hasAuditableEntry) return true; //nothing to audit
|
||||
store(auditEvent);
|
||||
return true;
|
||||
}catch(Exception e){
|
||||
log.error("Unable to audit resource: " + theResponseObject + " from request: " + theRequestDetails, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getQueryFromRequestDetails(RequestDetails theRequestDetails) {
|
||||
byte[] query;
|
||||
try {
|
||||
query = theRequestDetails.getCompleteUrl().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e1) {
|
||||
log.warn("Unable to encode URL to bytes in UTF-8, defaulting to platform default charset.", e1);
|
||||
query = theRequestDetails.getCompleteUrl().getBytes();
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the resource is considered an auditable resource containing PHI, add it as an object to the Security Event
|
||||
* @param auditEvent
|
||||
* @param resource
|
||||
* @param lifecycle
|
||||
* @param query
|
||||
* @return
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
*/
|
||||
protected boolean addResourceObjectToEvent(SecurityEvent auditEvent, IResource resource, SecurityEventObjectLifecycleEnum lifecycle, byte[] query) throws InstantiationException, IllegalAccessException {
|
||||
//TODO: get resource name from IResource -- James will put this in the model
|
||||
//reference ResourceTypeEnum
|
||||
ResourceTypeEnum resourceType = null; //resource.getResourceType();
|
||||
if(myAuditableResources.containsKey(resourceType)){
|
||||
@SuppressWarnings("unchecked")
|
||||
IResourceAuditor<IResource> auditableResource = (IResourceAuditor<IResource>) myAuditableResources.get(resourceType).newInstance();
|
||||
auditableResource.setResource(resource);
|
||||
if(auditableResource.isAuditable()){
|
||||
ObjectElement object = auditEvent.addObject();
|
||||
object.setReference(new ResourceReferenceDt(resource.getId()));
|
||||
object.setLifecycle(lifecycle);
|
||||
object.setQuery(query);
|
||||
object.setName(auditableResource.getName());
|
||||
object.setIdentifier(auditableResource.getIdentifier());
|
||||
object.setType(auditableResource.getType());
|
||||
object.setDescription(auditableResource.getDescription());
|
||||
object.setDetail(auditableResource.getDetail());
|
||||
object.setSensitivity(auditableResource.getSensitivity());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; //not something we care to audit
|
||||
}
|
||||
|
||||
private void addParticipantToEvent(HttpServletRequest theServletRequest, SecurityEvent auditEvent) {
|
||||
if(theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")){
|
||||
//TODO: get user info from token
|
||||
throw new NotImplementedException("OAuth user auditing not yet implemented.");
|
||||
}else { //no auth or basic auth or anything else, use HTTP headers for user info
|
||||
String userId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_USER_ID);
|
||||
if(userId == null) userId = "anonymous"; //TODO: throw new InvalidParameterException(UserInfoInterceptor.HEADER_USER_ID + " must be specified as an HTTP header to access PHI.");
|
||||
String userName = theServletRequest.getHeader(UserInfoInterceptor.HEADER_USER_NAME);
|
||||
if(userName == null) userName = "Anonymous";
|
||||
String userIp = theServletRequest.getRemoteAddr();
|
||||
Participant participant = auditEvent.addParticipant();
|
||||
participant.setUserId(userId);
|
||||
participant.setName(userName);
|
||||
ParticipantNetwork network = participant.getNetwork();
|
||||
network.setType(SecurityEventParticipantNetworkTypeEnum.IP_ADDRESS);
|
||||
network.setIdentifier(userIp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private SecurityEventObjectLifecycleEnum mapResourceTypeToSecurityLifecycle(RestfulOperationTypeEnum resourceOperationType) {
|
||||
switch (resourceOperationType) {
|
||||
case READ: return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE;
|
||||
case CREATE: return SecurityEventObjectLifecycleEnum.ORIGINATION_OR_CREATION;
|
||||
case DELETE: return SecurityEventObjectLifecycleEnum.LOGICAL_DELETION;
|
||||
case HISTORY_INSTANCE: return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE;
|
||||
case HISTORY_TYPE: return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE;
|
||||
case SEARCH_TYPE: return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE;
|
||||
case UPDATE: return SecurityEventObjectLifecycleEnum.AMENDMENT;
|
||||
case VALIDATE: return SecurityEventObjectLifecycleEnum.VERIFICATION;
|
||||
case VREAD: return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE;
|
||||
default:
|
||||
return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE; //access/use catch all
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataStore(IAuditDataStore theDataStore) {
|
||||
myDataStore = theDataStore;
|
||||
}
|
||||
|
||||
public Map<ResourceTypeEnum, Class<? extends IResourceAuditor<? extends IResource>>> getAuditableResources() {
|
||||
return myAuditableResources;
|
||||
}
|
||||
|
||||
public void setAuditableResources(Map<ResourceTypeEnum, Class<? extends IResourceAuditor<? extends IResource>>> theAuditableResources) {
|
||||
myAuditableResources = theAuditableResources;
|
||||
}
|
||||
|
||||
public void addAuditableResource(ResourceTypeEnum resourceType, Class<? extends IResourceAuditor<? extends IResource>> auditableResource){
|
||||
if(myAuditableResources == null) myAuditableResources = new HashMap<ResourceTypeEnum, Class<? extends IResourceAuditor<? extends IResource>>>();
|
||||
myAuditableResources.put(resourceType, auditableResource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ca.uhn.fhir.store;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.resource.SecurityEvent;
|
||||
|
||||
/**
|
||||
* This interface provides a way to persist FHIR SecurityEvents to any kind of data store
|
||||
*/
|
||||
public interface IAuditDataStore {
|
||||
|
||||
/**
|
||||
* Take in a SecurityEvent object and handle storing it to a persistent data store (database, JMS, file, etc).
|
||||
* @param auditEvent a FHIR SecurityEvent to be persisted
|
||||
* @throws Exception if there is an error while persisting the data
|
||||
*/
|
||||
public void store(SecurityEvent auditEvent) throws Exception;
|
||||
|
||||
}
|
Loading…
Reference in New Issue