public FhirResourceNarrative(IHtmlGenerationSupport IHtmlGenerationSupport) { this.IHtmlGenerationSupport = IHtmlGenerationSupport; }
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { var IResourceServiceFactory = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(IResourceServiceFactory)) as IResourceServiceFactory; var IUnitOfWork = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(IUnitOfWork)) as IUnitOfWork; var IRequestMetaFactory = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(IRequestMetaFactory)) as IRequestMetaFactory; var IResourceServices = IResourceServiceFactory.Create <IResourceServices>(); var ICommonFactory = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(ICommonFactory)) as ICommonFactory; var IPyroRequestUriFactory = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(IPyroRequestUriFactory)) as IPyroRequestUriFactory; var IGlobalProperties = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(IGlobalProperties)) as IGlobalProperties; //var ILog = actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(typeof(ILog)) as ILog; using (DbContextTransaction Transaction = IUnitOfWork.BeginTransaction()) { try { DateTime dtStart = (DateTime)actionExecutedContext.Request.Properties[DateTimeKey]; System.Diagnostics.Stopwatch stopwatch = (System.Diagnostics.Stopwatch)actionExecutedContext.Request.Properties[StopwatchKey]; stopwatch.Stop(); TimeSpan duration = stopwatch.Elapsed; IPyroRequestUri DtoRequestUri = IPyroRequestUriFactory.CreateFhirRequestUri(); DtoRequestUri.FhirRequestUri.Parse(actionExecutedContext.Request.RequestUri.OriginalString); // use owin context so we can self host (i.e. avoid System.Web.HttpContext.Current) var owinContext = actionExecutedContext.Request.GetOwinContext(); string machineName = System.Environment.MachineName; string httpVerb = actionExecutedContext.Request.Method.ToString(); string ipAddress = owinContext.Request.RemoteIpAddress; string controllerName = actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName; string actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName; bool successfulRequest = (actionExecutedContext.Exception == null); System.Web.Http.Routing.IHttpRouteData route = actionExecutedContext.ActionContext.ControllerContext.RouteData; // Get the resource base string baseUri = DtoRequestUri.FhirRequestUri.UriPrimaryServiceRoot.OriginalString; // Create the Security Event Object AuditEvent Audit = new AuditEvent(); if (actionExecutedContext.Request.Method == HttpMethod.Put) { Audit.Action = AuditEvent.AuditEventAction.U; } else if (actionExecutedContext.Request.Method == HttpMethod.Post) { Audit.Action = AuditEvent.AuditEventAction.C; } else if (actionExecutedContext.Request.Method == HttpMethod.Delete) { Audit.Action = AuditEvent.AuditEventAction.D; } else { Audit.Action = AuditEvent.AuditEventAction.R; } Audit.Recorded = DateTimeOffset.Now; Audit.Outcome = AuditEvent.AuditEventOutcome.N0; if (!successfulRequest) { // log error if (actionExecutedContext.Exception is PyroException) { var fse = actionExecutedContext.Exception as PyroException; if ((int)fse.HttpStatusCode >= 500) { Audit.Outcome = AuditEvent.AuditEventOutcome.N8; } else if ((int)fse.HttpStatusCode >= 400) { Audit.Outcome = AuditEvent.AuditEventOutcome.N4; } } else { Audit.Outcome = AuditEvent.AuditEventOutcome.N8; } } Audit.Type = new Coding() { System = "http://hl7.org/fhir/security-event-type", Code = "rest", Display = "Restful Operation" }; Audit.Subtype = new List <Coding>(); if (actionExecutedContext.Request.Method == HttpMethod.Put) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "update", Display = "update" }); } else if (actionExecutedContext.Request.Method == HttpMethod.Post) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "create", Display = "create" }); } else if (actionExecutedContext.Request.Method == HttpMethod.Delete) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "delete", Display = "delete" }); } else if (actionExecutedContext.Request.Method == HttpMethod.Options) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "read", Display = "read" }); } else if (route.Values.ContainsKey("ResourceName") && route.Values.ContainsKey("id") && route.Values.ContainsKey("vid")) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "vread", Display = "vread" }); } else if (route.Values.ContainsKey("ResourceName") && route.Values.ContainsKey("id")) { if (owinContext.Request.Uri.OriginalString.Contains("_history")) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "history-instance", Display = "history-instance" }); } else { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "read", Display = "read" }); } } else if (route.Values.ContainsKey("ResourceName")) { if (owinContext.Request.Uri.OriginalString.Contains("_history")) { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "history-type", Display = "history-type" }); } else { Audit.Subtype.Add(new Coding() { System = "http://hl7.org/fhir/restful-interaction", Code = "search-type", Display = "search-type" }); } } Audit.Agent.Add(new AuditEvent.AgentComponent()); // se.Participant[0].UserId = ""; // se.Participant[0].AltId = owinContext.Authentication.; if (owinContext.Authentication.User != null && owinContext.Authentication.User.Identity.IsAuthenticated) { Audit.Agent[0].Name = owinContext.Authentication.User.Identity.Name; // read additional details from the identity claims if (owinContext.Authentication.User.Identity is System.Security.Claims.ClaimsIdentity ci) { var claim = ci.Claims.Where(c => c.Type == "name").FirstOrDefault(); if (claim != null) { Audit.Agent[0].Name = claim.Value; } claim = ci.Claims.Where(c => c.Type == "sub").FirstOrDefault(); if (claim != null) { Audit.Agent[0].AltId = claim.Value; } if (ci.Claims.Any(c => c.Type == "author_only_access" && c.Value == "true")) { Audit.Agent[0].Role = new List <CodeableConcept> { new CodeableConcept(null, "author_only_access") }; } } } Audit.Agent[0].Requestor = true; Audit.Agent[0].Network = new AuditEvent.NetworkComponent() { Address = ipAddress, Type = AuditEvent.AuditEventAgentNetworkType.N2 }; Audit.Source = new AuditEvent.SourceComponent { Site = "Cloud", Identifier = new Identifier(null, actionExecutedContext.Request.RequestUri.GetLeftPart(UriPartial.Authority)) }; Audit.Source.Type.Add(new Coding() { System = "http://hl7.org/fhir/ValueSet/audit-source-type", Code = "3", Display = "Web Server" }); if (route.Values.ContainsKey("ResourceName") && route.Values.ContainsKey("id")) { string relativeUri = String.Format("{0}/{1}", route.Values["ResourceName"] as string, route.Values["id"] as string); if (route.Values.ContainsKey("vid")) { relativeUri += "/_history/" + route.Values["vid"] as string; } Audit.Entity = new List <AuditEvent.EntityComponent> { new AuditEvent.EntityComponent() { Name = actionExecutedContext.Request.RequestUri.ToString(), Reference = new ResourceReference() { Url = new Uri(relativeUri, UriKind.Relative) }, Type = new Coding() { System = "http://hl7.org/fhir/object-type", Code = "1", Display = "Person" } } }; if (actionExecutedContext.Request.Properties.ContainsKey(Attributes.ActionLogAttribute.ResourceIdentityKey)) { string reference = actionExecutedContext.Request.Properties[Attributes.ActionLogAttribute.ResourceIdentityKey] as string; if (!string.IsNullOrEmpty(reference)) { Audit.Entity[0].Reference.Reference = reference; } } } else { Audit.Entity = new List <AuditEvent.EntityComponent> { new AuditEvent.EntityComponent() { Name = actionExecutedContext.Request.RequestUri.ToString(), Description = baseUri == null ? owinContext.Request.Uri.OriginalString : owinContext.Request.Uri.OriginalString.Replace(baseUri, ""), Type = new Coding() { System = "http://hl7.org/fhir/object-type", Code = "1", Display = "Person" } } }; if (actionExecutedContext.Request.Properties.ContainsKey(Attributes.ActionLogAttribute.ResourceIdentityKey)) { string reference = actionExecutedContext.Request.Properties[Attributes.ActionLogAttribute.ResourceIdentityKey] as string; if (!string.IsNullOrEmpty(reference)) { Audit.Entity[0].Reference = new ResourceReference() { Reference = reference } } ; } } IHtmlGenerationSupport Narative = ICommonFactory.CreateFhirNarativeGenerationSupport(); Narative.NewValuePairList("Time", string.Format("{0} ({1:f3} sec)", dtStart, duration.TotalSeconds)); Narative.AppendValuePairList(actionExecutedContext.Request.Method.ToString(), string.Format("{0}", HttpUtility.HtmlEncode(baseUri == null ? owinContext.Request.Uri.OriginalString : owinContext.Request.Uri.OriginalString.Replace(baseUri, "")))); Narative.AppendValuePairList("BaseUri", baseUri); Narative.AppendValuePairList("From", ipAddress); if (owinContext.Authentication.User != null && owinContext.Authentication.User.Identity.IsAuthenticated) { Narative.AppendValuePairList("User", owinContext.Authentication.User.ToString()); } else { Narative.AppendValuePairList("User", "(anonymous)"); } if (Audit.Outcome != AuditEvent.AuditEventOutcome.N0) { Audit.OutcomeDesc = actionExecutedContext.Exception.Message; Narative.AppendValuePairList("Error", actionExecutedContext.Exception.Message); } Audit.Text = new Narrative { Div = Narative.Generate() }; // Add custom PyroHealth event data Audit.AddExtension("http://pyrohealth.net/extention/AuditEvent/TimeTaken", new FhirDecimal((decimal)duration.TotalMilliseconds)); if (IGlobalProperties.FhirAuditEventLogRequestData) { var requestDataObj = new AuditEvent.EntityComponent { Identifier = new Identifier(null, "RequestData"), Name = actionExecutedContext.Request.RequestUri.ToString(), Description = "Orginial Request Data", Type = new Coding() { System = "http://hl7.org/fhir/object-type", Code = "4", Display = "RequestData" }, Detail = new List <AuditEvent.DetailComponent>() }; var DetailComponent = new AuditEvent.DetailComponent(); requestDataObj.Detail.Add(DetailComponent); string RequestData = GetRequestData(actionExecutedContext); if (!string.IsNullOrWhiteSpace(RequestData)) { DetailComponent.Value = Encoding.UTF8.GetBytes(RequestData); Audit.Entity.Add(requestDataObj); } } if (IGlobalProperties.FhirAuditEventLogResponseData) { var responseDataObj = new AuditEvent.EntityComponent { Identifier = new Identifier(null, "ResponseData"), Name = actionExecutedContext.Request.RequestUri.ToString(), Description = "Orginial Response Data", Type = new Coding() { System = "http://hl7.org/fhir/object-type", Code = "4", Display = "ResponseData" }, Detail = new List <AuditEvent.DetailComponent>() }; var DetailComponent = new AuditEvent.DetailComponent(); responseDataObj.Detail.Add(DetailComponent); string ResponseData = GetResponseData(actionExecutedContext); if (!string.IsNullOrWhiteSpace(ResponseData)) { DetailComponent.Value = Encoding.UTF8.GetBytes(ResponseData); Audit.Entity.Add(responseDataObj); } } //Will only log if Debug logging is enabled. DebugLogRequestResource(actionExecutedContext); //Commit to Database Pyro.Common.RequestMetadata.IRequestMeta IRequestMeta = IRequestMetaFactory.CreateRequestMeta().Set($"{ResourceType.AuditEvent}"); IResourceServiceOutcome ResourceServiceOutcome = IResourceServices.Post(Audit, IRequestMeta); //IResourceServiceOutcome ResourceServiceOutcome = IResourceServices.SetResource(Audit, DtoRequestUri, RestEnum.CrudOperationType.Create); Transaction.Commit(); } catch (Exception Exec) { Logger.Log.Error(Exec, "ActionLogAttribute"); Transaction.Rollback(); } base.OnActionExecuted(actionExecutedContext); } }