For #126 - Don't use BoundCodeableConcept for empty enums

This commit is contained in:
jamesagnew 2015-07-17 08:34:44 -04:00
parent 3bdf846a3d
commit ddbe79cb86
12 changed files with 286 additions and 185 deletions

View File

@ -23,8 +23,8 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.Map;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
@ -75,7 +75,7 @@ public interface IResourceAuditor<T extends IResource> {
* Denotes policy-defined sensitivity for the Participant Object ID such as VIP, HIV status, mental health status or similar topics
* @return the sensitivity of this resource
*/
public SecurityEventObjectSensitivityEnum getSensitivity();
public BaseCodingDt getSensitivity();
}

View File

@ -23,9 +23,9 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.dstu.resource.AdverseReaction;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class AdverseReactionAuditor implements IResourceAuditor<AdverseReaction> {
@ -78,7 +78,7 @@ public class AdverseReactionAuditor implements IResourceAuditor<AdverseReaction>
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null;
}

View File

@ -23,9 +23,9 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class DiagnosticReportAuditor implements IResourceAuditor<DiagnosticReport> {
@ -83,7 +83,7 @@ public class DiagnosticReportAuditor implements IResourceAuditor<DiagnosticRepor
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null; //no sensitivity indicated
}
}

View File

@ -23,9 +23,9 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Encounter;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class EncounterAuditor implements IResourceAuditor<Encounter> {
@ -96,7 +96,7 @@ public class EncounterAuditor implements IResourceAuditor<Encounter> {
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
//override this method to provide sensitivity information about the visit
return null;
}

View File

@ -22,10 +22,10 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
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.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class MedicationPrescriptionAuditor implements IResourceAuditor<MedicationPrescription> {
@ -85,7 +85,7 @@ public class MedicationPrescriptionAuditor implements IResourceAuditor<Medicatio
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null; //no sensitivity indicated in MedicationPrescription
}

View File

@ -22,10 +22,10 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
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.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class MedicationStatementAuditor implements IResourceAuditor<MedicationStatement> {
@ -83,7 +83,7 @@ public class MedicationStatementAuditor implements IResourceAuditor<MedicationSt
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null; //no sensitivity indicated in MedicationStatement
}

View File

@ -23,9 +23,9 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class ObservationAuditor implements IResourceAuditor<Observation> {
@ -79,7 +79,7 @@ public class ObservationAuditor implements IResourceAuditor<Observation> {
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null;
}

View File

@ -24,9 +24,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class PatientAuditor implements IResourceAuditor<Patient> {
@ -93,7 +93,7 @@ public class PatientAuditor implements IResourceAuditor<Patient> {
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null; //override to include things like locked patient records
}

View File

@ -23,10 +23,10 @@ package ca.uhn.fhir.rest.server.audit;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Procedure;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectSensitivityEnum;
import ca.uhn.fhir.model.dstu.valueset.SecurityEventObjectTypeEnum;
public class ProcedureAuditor implements IResourceAuditor<Procedure> {
@ -79,7 +79,7 @@ public class ProcedureAuditor implements IResourceAuditor<Procedure> {
}
@Override
public SecurityEventObjectSensitivityEnum getSensitivity() {
public BaseCodingDt getSensitivity() {
return null;
}

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.server.interceptor;
package ca.uhn.fhir.rest.server.interceptor;
/*
* #%L
@ -66,142 +66,147 @@ import ca.uhn.fhir.store.IAuditDataStore;
/**
* Server interceptor that provides auditing capability
*
* To use, set a data store that implements the IAuditDataStore interface, specify
* To use, set a data store that implements the IAuditDataStore interface, specify
*/
public class AuditingInterceptor extends InterceptorAdapter {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuditingInterceptor.class);
private IAuditDataStore myDataStore = null;
private IAuditDataStore myDataStore = null;
private Map<String, Class<? extends IResourceAuditor<? extends IResource>>> myAuditableResources = new HashMap<String, Class<? extends IResourceAuditor<? extends IResource>>>();
private boolean myClientParamsOptional = false;
protected String mySiteId;
/**
* Create a new AuditingInterceptor with auditing required by default and a siteid of "NONE"
*/
public AuditingInterceptor() {
mySiteId = "NONE";
myClientParamsOptional = false;
myClientParamsOptional = false;
}
/**
* Create a new AuditingInterceptor with auditing required by default and a site ID as specified
* @param theSiteId the name of the site producing the audit data (will be set as SecurityEvent.Source.siteid)
*
* @param theSiteId
* the name of the site producing the audit data (will be set as SecurityEvent.Source.siteid)
*/
public AuditingInterceptor(String theSiteId) {
mySiteId = theSiteId;
myClientParamsOptional = false;
myClientParamsOptional = false;
}
/**
* Create a new AuditingInterceptor with the specified site ID and indicating if auditing is optional or required
* @param theSiteId theSiteId the name of the site producing the audit data (will be set as SecurityEvent.Source.siteid)
* @param theClientParamsOptional - true if auditing is optional, false if auditing is required (will throw exception if
* user params are not specified or audit store is not set)
*
* @param theSiteId
* theSiteId the name of the site producing the audit data (will be set as SecurityEvent.Source.siteid)
* @param theClientParamsOptional
* - true if auditing is optional, false if auditing is required (will throw exception if user params are
* not specified or audit store is not set)
*/
public AuditingInterceptor(String theSiteId, boolean theClientParamsOptional){
public AuditingInterceptor(String theSiteId, boolean theClientParamsOptional) {
mySiteId = theSiteId;
myClientParamsOptional = theClientParamsOptional;
}
/**
* Intercept the outgoing response to perform auditing of the request data if the bundle contains auditable resources.
* Intercept the outgoing response to perform auditing of the request data if the bundle contains auditable
* resources.
*/
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException {
if(myClientParamsOptional && myDataStore == null){
//auditing is not required or configured, so do nothing here
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
if (myClientParamsOptional && myDataStore == null) {
// auditing is not required or configured, so do nothing here
log.debug("No auditing configured.");
return true;
}
if(theResponseObject == null || theResponseObject.isEmpty()){
if (theResponseObject == null || theResponseObject.isEmpty()) {
log.debug("No bundle to audit");
return true;
}
try{
try {
log.info("Auditing bundle: " + theResponseObject + " from request " + theRequestDetails);
SecurityEvent auditEvent = new SecurityEvent();
auditEvent.setEvent(getEventInfo(theRequestDetails));
//get user info from request if available
SecurityEvent auditEvent = new SecurityEvent();
auditEvent.setEvent(getEventInfo(theRequestDetails));
// get user info from request if available
Participant participant = getParticipant(theServletRequest);
if(participant == null){
if (participant == null) {
log.debug("No participant to audit");
return true; //no user to audit - throws exception if client params are required
return true; // no user to audit - throws exception if client params are required
}
List<Participant> participants = new ArrayList<SecurityEvent.Participant>(1);
participants.add(participant);
auditEvent.setParticipant(participants);
SecurityEventObjectLifecycleEnum lifecycle = mapResourceTypeToSecurityLifecycle(theRequestDetails.getResourceOperationType());
SecurityEventObjectLifecycleEnum lifecycle = mapResourceTypeToSecurityLifecycle(theRequestDetails.getResourceOperationType());
byte[] query = getQueryFromRequestDetails(theRequestDetails);
List<ObjectElement> auditableObjects = new ArrayList<SecurityEvent.ObjectElement>();
for(BundleEntry entry: theResponseObject.getEntries()){
IResource resource = entry.getResource();
ObjectElement auditableObject = getObjectElement(resource, lifecycle , query);
if(auditableObject != null) auditableObjects.add(auditableObject);
for (BundleEntry entry : theResponseObject.getEntries()) {
IResource resource = entry.getResource();
ObjectElement auditableObject = getObjectElement(resource, lifecycle, query);
if (auditableObject != null)
auditableObjects.add(auditableObject);
}
if(auditableObjects.isEmpty()){
if (auditableObjects.isEmpty()) {
log.debug("No auditable resources to audit.");
return true; //no PHI to audit
}else{
return true; // no PHI to audit
} else {
log.debug("Auditing " + auditableObjects.size() + " resources.");
}
auditEvent.setObject(auditableObjects);
auditEvent.setSource(getSourceElement(theServletRequest));
store(auditEvent);
return true; //success
}catch(Exception e){
return true; // success
} catch (Exception e) {
log.error("Unable to audit resource: " + theResponseObject + " from request: " + theRequestDetails, e);
throw new InternalErrorException("Auditing failed, unable to complete request", e);
}
}
/**
* Intercept the outgoing response to perform auditing of the request data if the resource is auditable.
*/
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException {
if(myClientParamsOptional && myDataStore == null){
//auditing is not required or configured, so do nothing here
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
if (myClientParamsOptional && myDataStore == null) {
// auditing is not required or configured, so do nothing here
log.debug("No auditing configured.");
return true;
}
if(theResponseObject == null){
if (theResponseObject == null) {
log.debug("No object to audit");
return true;
}
try{
try {
log.info("Auditing resource: " + theResponseObject + " from request: " + theRequestDetails);
SecurityEvent auditEvent = new SecurityEvent();
auditEvent.setEvent(getEventInfo(theRequestDetails));
//get user info from request if available
auditEvent.setEvent(getEventInfo(theRequestDetails));
// get user info from request if available
Participant participant = getParticipant(theServletRequest);
if(participant == null){
if (participant == null) {
log.debug("No participant to audit");
return true; //no user to audit - throws exception if client params are required
return true; // no user to audit - throws exception if client params are required
}
List<Participant> participants = new ArrayList<SecurityEvent.Participant>(1);
participants.add(participant);
auditEvent.setParticipant(participants);
byte[] query = getQueryFromRequestDetails(theRequestDetails);
SecurityEventObjectLifecycleEnum lifecycle = mapResourceTypeToSecurityLifecycle(theRequestDetails.getResourceOperationType());
ObjectElement auditableObject = getObjectElement((IResource) theResponseObject, lifecycle , query);
if(auditableObject == null){
ObjectElement auditableObject = getObjectElement((IResource) theResponseObject, lifecycle, query);
if (auditableObject == null) {
log.debug("No auditable resources to audit");
return true;
return true;
}
List<ObjectElement> auditableObjects = new ArrayList<SecurityEvent.ObjectElement>(1);
auditableObjects.add(auditableObject);
auditEvent.setObject(auditableObjects);
auditEvent.setSource(getSourceElement(theServletRequest));
log.debug("Auditing one resource.");
store(auditEvent);
store(auditEvent);
return true;
}catch(Exception e){
} catch (Exception e) {
log.error("Unable to audit resource: " + theResponseObject + " from request: " + theRequestDetails, e);
throw new InternalErrorException("Auditing failed, unable to complete request", e);
}
@ -209,31 +214,41 @@ public class AuditingInterceptor extends InterceptorAdapter {
/**
* Store the SecurityEvent generated for this request to a persistent store (database, file, JMS, etc)
* @param auditEvent the SecurityEvent generated for this request
* @throws Exception if the data store is not configured or if an error occurs during storage
*
* @param auditEvent
* the SecurityEvent generated for this request
* @throws Exception
* if the data store is not configured or if an error occurs during storage
*/
protected void store(SecurityEvent auditEvent) throws Exception {
if(myDataStore == null) throw new InternalErrorException("No data store provided to persist audit events");
if (myDataStore == null)
throw new InternalErrorException("No data store provided to persist audit events");
myDataStore.store(auditEvent);
}
/**
* Generates the Event segment of the SecurityEvent based on the incoming request details
* @param theRequestDetails the RequestDetails of the incoming request
*
* @param theRequestDetails
* the RequestDetails of the incoming request
* @return an Event populated with the action, date, and outcome
*/
protected Event getEventInfo(RequestDetails theRequestDetails) {
Event event = new Event();
event.setAction(mapResourceTypeToSecurityEventAction(theRequestDetails.getResourceOperationType()));
event.setDateTimeWithMillisPrecision(new Date());
event.setOutcome(SecurityEventOutcomeEnum.SUCCESS); //we audit successful return of PHI only, otherwise an exception is thrown and no resources are returned to be audited
event.setOutcome(SecurityEventOutcomeEnum.SUCCESS); // we audit successful return of PHI only, otherwise an
// exception is thrown and no resources are returned to be
// audited
return event;
}
/**
* Return the query URL encoded to bytes to be set as the Object.query on the Security Event
* @param theRequestDetails the RequestDetails of the incoming request
*
* @param theRequestDetails
* the RequestDetails of the incoming request
* @return the query URL of the request encoded to bytes
*/
protected byte[] getQueryFromRequestDetails(RequestDetails theRequestDetails) {
@ -249,22 +264,28 @@ public class AuditingInterceptor extends InterceptorAdapter {
/**
* If the resource is considered an auditable resource containing PHI, create an ObjectElement, otherwise return null
* @param resource the resource to be audited
* @param lifecycle the SecurityEventObjectLifecycleEnum of the request
* @param query the byte encoded query string of the request
*
* @param resource
* the resource to be audited
* @param lifecycle
* the SecurityEventObjectLifecycleEnum of the request
* @param query
* the byte encoded query string of the request
* @return an ObjectElement populated with information about the resource
* @throws IllegalAccessException if the auditor for this resource cannot be instantiated
* @throws InstantiationException if the auditor for this resource cannot be instantiated
* @throws IllegalAccessException
* if the auditor for this resource cannot be instantiated
* @throws InstantiationException
* if the auditor for this resource cannot be instantiated
*/
protected ObjectElement getObjectElement(IResource resource, SecurityEventObjectLifecycleEnum lifecycle, byte[] query) throws InstantiationException, IllegalAccessException {
String resourceType = resource.getResourceName();
if(myAuditableResources.containsKey(resourceType)){
String resourceType = resource.getResourceName();
if (myAuditableResources.containsKey(resourceType)) {
log.debug("Found auditable resource of type: " + resourceType);
@SuppressWarnings("unchecked")
IResourceAuditor<IResource> auditableResource = (IResourceAuditor<IResource>) myAuditableResources.get(resourceType).newInstance();
IResourceAuditor<IResource> auditableResource = (IResourceAuditor<IResource>) myAuditableResources.get(resourceType).newInstance();
auditableResource.setResource(resource);
if(auditableResource.isAuditable()){
if (auditableResource.isAuditable()) {
ObjectElement object = new ObjectElement();
object.setReference(new ResourceReferenceDt(resource.getId()));
object.setLifecycle(lifecycle);
@ -274,198 +295,260 @@ public class AuditingInterceptor extends InterceptorAdapter {
object.setType(auditableResource.getType());
object.setDescription(auditableResource.getDescription());
Map<String, String> detailMap = auditableResource.getDetail();
if(detailMap != null && !detailMap.isEmpty()){
if (detailMap != null && !detailMap.isEmpty()) {
List<ObjectDetail> details = new ArrayList<SecurityEvent.ObjectDetail>();
for(Entry<String, String> entry: detailMap.entrySet()){
for (Entry<String, String> entry : detailMap.entrySet()) {
ObjectDetail detail = makeObjectDetail(entry.getKey(), entry.getValue());
details.add(detail);
}
object.setDetail(details);
}
object.setSensitivity(auditableResource.getSensitivity());
return object;
}else{
}
object.setDetail(details);
}
if (auditableResource.getSensitivity() != null) {
CodingDt coding = object.getSensitivity().addCoding();
coding.setSystem(auditableResource.getSensitivity().getSystemElement().getValue());
coding.setCode(auditableResource.getSensitivity().getCodeElement().getValue());
coding.setDisplay(auditableResource.getSensitivity().getDisplayElement().getValue());
}
return object;
} else {
log.debug("Resource is not auditable");
}
}else{
} else {
log.debug("No auditor configured for resource type " + resourceType);
}
return null; //not something we care to audit
return null; // not something we care to audit
}
/**
* Helper method to create an ObjectDetail from a pair of Strings.
* @param type the type of the ObjectDetail
* @param value the value of the ObejctDetail to be encoded
*
* @param type
* the type of the ObjectDetail
* @param value
* the value of the ObejctDetail to be encoded
* @return an ObjectDetail of the given type and value
*/
protected ObjectDetail makeObjectDetail(String type, String value) {
protected ObjectDetail makeObjectDetail(String type, String value) {
ObjectDetail detail = new ObjectDetail();
if(type != null)
if (type != null)
detail.setType(type);
if(value != null)
if (value != null)
detail.setValue(value.getBytes());
return detail;
}
/**
* Create a participant object based on information from the incoming servlet request
* @param theServletRequest the incoming request
*
* @param theServletRequest
* the incoming request
* @return a Participant object populated with the user id, user name, and IP
* @throws InvalidRequestException if auditing is required but userId is not specified as a request header
* @throws NotImplementedException if the authorization type is OAuth
* @throws InvalidRequestException
* if auditing is required but userId is not specified as a request header
* @throws NotImplementedException
* if the authorization type is OAuth
*/
protected Participant getParticipant(HttpServletRequest theServletRequest) throws InvalidRequestException, NotImplementedException {
//TODO: move the specification of auth params into another interceptor separate from auditing?
if(theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")){
if(myClientParamsOptional){
// TODO: move the specification of auth params into another interceptor separate from auditing?
if (theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")) {
if (myClientParamsOptional) {
log.debug("OAuth request received but no auditing required.");
return null;
return null;
}
//TODO: get user info from token
// 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){
if(myClientParamsOptional) return null; //no auditing
else throw new InvalidRequestException(UserInfoInterceptor.HEADER_USER_ID + " must be specified as an HTTP header to access PHI.");
} 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) {
if (myClientParamsOptional)
return null; // no auditing
else
throw new InvalidRequestException(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();
if (userName == null)
userName = "Anonymous";
String userIp = theServletRequest.getRemoteAddr();
Participant participant = new Participant();
participant.setUserId(userId);
participant.setName(userName);
participant.setUserId(userId);
participant.setName(userName);
ParticipantNetwork network = participant.getNetwork();
network.setType(SecurityEventParticipantNetworkTypeEnum.IP_ADDRESS);
network.setIdentifier(userIp);
return participant;
}
}
/**
* Create a Source object based on information in the incoming request
* @param theServletRequest the incoming request
*
* @param theServletRequest
* the incoming request
* @return a Source object with the identifier, type, and site specified
* @throws NotImplementedException if the authorization type is OAuth
* @throws NotImplementedException
* if the authorization type is OAuth
*/
protected Source getSourceElement(HttpServletRequest theServletRequest) throws NotImplementedException{
if(theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")){
if(myClientParamsOptional) return null; //no auditing required
//TODO: get application info from token
protected Source getSourceElement(HttpServletRequest theServletRequest) throws NotImplementedException {
if (theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")) {
if (myClientParamsOptional)
return null; // no auditing required
// TODO: get application info from token
throw new NotImplementedException("OAuth auditing not yet implemented.");
}else { //no auth or basic auth or anything else, use HTTP headers for audit info
String appId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_APPLICATION_NAME);
} else { // no auth or basic auth or anything else, use HTTP headers for audit info
String appId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_APPLICATION_NAME);
Source source = new Source();
source.setIdentifier(appId);
source.setType(getAccessType(theServletRequest));
source.setSite(getSiteId(theServletRequest));
return source;
}
}
}
/**
* Returns the site ID (for SecurityEvent.source.siteid)
* @param theServletRequest the incoming request
* @return the site ID to audit. By default, uses the value set in the constructor. Override this method to set the value via request parameters.
*
* @param theServletRequest
* the incoming request
* @return the site ID to audit. By default, uses the value set in the constructor. Override this method to set the
* value via request parameters.
*/
protected StringDt getSiteId(HttpServletRequest theServletRequest) {
return new StringDt(mySiteId); //override this method to pull the site id from the request info
return new StringDt(mySiteId); // override this method to pull the site id from the request info
}
/**
* Return the access type for this request
* @param theServletRequest the incoming request
*
* @param theServletRequest
* the incoming request
* @return the SecurityEventSourceTypeEnum representing the type of request being made
*/
protected List<CodingDt> getAccessType(HttpServletRequest theServletRequest) {
List<CodingDt> types = new ArrayList<CodingDt>();
if(theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")){
types.add(new CodingDt(SecurityEventSourceTypeEnum.USER_DEVICE.getSystem(), SecurityEventSourceTypeEnum.USER_DEVICE.getCode()));
}else{
String userId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_USER_ID);
List<CodingDt> types = new ArrayList<CodingDt>();
if (theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION) != null && theServletRequest.getHeader(Constants.HEADER_AUTHORIZATION).startsWith("OAuth")) {
types.add(new CodingDt(SecurityEventSourceTypeEnum.USER_DEVICE.getSystem(), SecurityEventSourceTypeEnum.USER_DEVICE.getCode()));
} else {
String userId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_USER_ID);
String appId = theServletRequest.getHeader(UserInfoInterceptor.HEADER_APPLICATION_NAME);
if (userId == null && appId != null) types.add(new CodingDt(SecurityEventSourceTypeEnum.APPLICATION_SERVER.getSystem(), SecurityEventSourceTypeEnum.APPLICATION_SERVER.getCode()));
else types.add(new CodingDt(SecurityEventSourceTypeEnum.USER_DEVICE.getSystem(), SecurityEventSourceTypeEnum.USER_DEVICE.getCode()));
if (userId == null && appId != null)
types.add(new CodingDt(SecurityEventSourceTypeEnum.APPLICATION_SERVER.getSystem(), SecurityEventSourceTypeEnum.APPLICATION_SERVER.getCode()));
else
types.add(new CodingDt(SecurityEventSourceTypeEnum.USER_DEVICE.getSystem(), SecurityEventSourceTypeEnum.USER_DEVICE.getCode()));
}
return types;
return types;
}
/**
* Returns the SecurityEventActionEnum corresponding to the specified RestfulOperationTypeEnum
* @param resourceOperationType the type of operation (Read, Create, Delete, etc)
*
* @param resourceOperationType
* the type of operation (Read, Create, Delete, etc)
* @return the corresponding SecurityEventActionEnum (Read/View/Print, Create, Delete, etc)
*/
protected SecurityEventActionEnum mapResourceTypeToSecurityEventAction(RestfulOperationTypeEnum resourceOperationType) {
if(resourceOperationType == null) return null;
if (resourceOperationType == null)
return null;
switch (resourceOperationType) {
case READ: return SecurityEventActionEnum.READ_VIEW_PRINT;
case CREATE: return SecurityEventActionEnum.CREATE;
case DELETE: return SecurityEventActionEnum.DELETE;
case HISTORY_INSTANCE: return SecurityEventActionEnum.READ_VIEW_PRINT;
case HISTORY_TYPE: return SecurityEventActionEnum.READ_VIEW_PRINT;
case SEARCH_TYPE: return SecurityEventActionEnum.READ_VIEW_PRINT;
case UPDATE: return SecurityEventActionEnum.UPDATE;
case VALIDATE: return SecurityEventActionEnum.READ_VIEW_PRINT;
case VREAD: return SecurityEventActionEnum.READ_VIEW_PRINT;
case READ:
return SecurityEventActionEnum.READ_VIEW_PRINT;
case CREATE:
return SecurityEventActionEnum.CREATE;
case DELETE:
return SecurityEventActionEnum.DELETE;
case HISTORY_INSTANCE:
return SecurityEventActionEnum.READ_VIEW_PRINT;
case HISTORY_TYPE:
return SecurityEventActionEnum.READ_VIEW_PRINT;
case SEARCH_TYPE:
return SecurityEventActionEnum.READ_VIEW_PRINT;
case UPDATE:
return SecurityEventActionEnum.UPDATE;
case VALIDATE:
return SecurityEventActionEnum.READ_VIEW_PRINT;
case VREAD:
return SecurityEventActionEnum.READ_VIEW_PRINT;
default:
return SecurityEventActionEnum.READ_VIEW_PRINT; //read/view catch all
return SecurityEventActionEnum.READ_VIEW_PRINT; // read/view catch all
}
}
/**
* Returns the SecurityEventObjectLifecycleEnum corresponding to the specified RestfulOperationTypeEnum
* @param resourceOperationType the type of operation (Read, Create, Delete, etc)
* @return the corresponding SecurityEventObjectLifecycleEnum (Access/Use, Origination/Creation, Logical Deletion, etc)
*
* @param resourceOperationType
* the type of operation (Read, Create, Delete, etc)
* @return the corresponding SecurityEventObjectLifecycleEnum (Access/Use, Origination/Creation, Logical Deletion,
* etc)
*/
protected SecurityEventObjectLifecycleEnum mapResourceTypeToSecurityLifecycle(RestfulOperationTypeEnum resourceOperationType) {
if(resourceOperationType == null) return null;
if (resourceOperationType == null)
return null;
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;
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
return SecurityEventObjectLifecycleEnum.ACCESS_OR_USE; // access/use catch all
}
}
/**
* Provide a persistent store implementing IAuditDataStore to store the audit events
* @param theDataStore an implementation of IAuditDataStore to be used to store the audit events
*
* @param theDataStore
* an implementation of IAuditDataStore to be used to store the audit events
*/
public void setDataStore(IAuditDataStore theDataStore) {
myDataStore = theDataStore;
}
/**
* Get this auditor's map of auditable resources and auditors
*
* @return the map of auditable resource types to auditors
*/
public Map<String, Class<? extends IResourceAuditor<? extends IResource>>> getAuditableResources() {
return myAuditableResources;
}
/**
* Specify which types of resources are to be audited (Patient, Encounter, etc) and provide an IResourceAuditor for each type
* @param theAuditableResources a map of resources to be audited and their corresponding IResouceAuditors
* Specify which types of resources are to be audited (Patient, Encounter, etc) and provide an IResourceAuditor for
* each type
*
* @param theAuditableResources
* a map of resources to be audited and their corresponding IResouceAuditors
*/
public void setAuditableResources(Map<String, Class<? extends IResourceAuditor<? extends IResource>>> theAuditableResources) {
myAuditableResources = theAuditableResources;
}
/**
* Add a type of auditable resource and its auditor to this AuditingInterceptor's resource map
* @param resourceType the type of resource to be audited (Patient, Encounter, etc)
* @param auditableResource an implementation of IResourceAuditor that can audit resources of the given type
*
* @param resourceType
* the type of resource to be audited (Patient, Encounter, etc)
* @param auditableResource
* an implementation of IResourceAuditor that can audit resources of the given type
*/
public void addAuditableResource(String resourceType, Class<? extends IResourceAuditor<? extends IResource>> auditableResource){
if(myAuditableResources == null) myAuditableResources = new HashMap<String, Class<? extends IResourceAuditor<? extends IResource>>>();
public void addAuditableResource(String resourceType, Class<? extends IResourceAuditor<? extends IResource>> auditableResource) {
if (myAuditableResources == null)
myAuditableResources = new HashMap<String, Class<? extends IResourceAuditor<? extends IResource>>>();
myAuditableResources.put(resourceType, auditableResource);
}
}

View File

@ -10,6 +10,7 @@ import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -108,6 +109,18 @@ public class ValueSetGenerator {
}
}
}
/*
* Purge empty valuesets
*/
for (Iterator<java.util.Map.Entry<String, ValueSetTm>> iter = myValueSets.entrySet().iterator(); iter.hasNext(); ) {
java.util.Map.Entry<String, ValueSetTm> next = iter.next();
if (next.getValue().getCodes().isEmpty()) {
iter.remove();
continue;
}
}
// File[] files = new
// File(myResourceValueSetFiles).listFiles((FilenameFilter) new

View File

@ -14,6 +14,11 @@
<action type="add">
SyntaxHighlightingInterceptor now also highlights OperationOutcome responses for errors/exceptions.
</action>
<action type="fix" issue="126">
Model classes do not use BoundCodeableConcept for example bindings that do not
actually point to any codes (e.g. Observation.interpretation). Thanks
to GitHub user @steve1medix for reporting!
</action>
</release>
<release version="1.1" date="2015-07-13">
<action type="add">