private static async Task <bool> IsAParticipantOrPatient(JToken resource, FHIRClient fhirClient, IEnumerable <string> knownresourceIdentities, Dictionary <string, bool> porcache, IHeaderDictionary auditheaders)
        {
            string patientId   = null;
            string encounterId = null;
            JToken patient     = null;
            JToken encounter   = null;

            string rt = (string)resource["resourceType"];

            //Check for Patient resource or load patient resource from subject member
            if (rt.Equals("Patient"))
            {
                patient   = resource;
                patientId = rt + "/" + (string)resource["id"];
            }
            if (patient == null)
            {
                patientId = (string)resource?["subject"]?["reference"];
                if (string.IsNullOrEmpty(patientId))
                {
                    patientId = (string)resource?["patient"]?["reference"];
                }
            }
            if (rt.Equals("Encounter"))
            {
                encounter   = resource;
                encounterId = rt + "/" + (string)resource["id"];
                patientId   = (string)resource?["subject"]?["reference"];
            }
            if (encounter == null)
            {
                encounterId = (string)resource?["encounter"]?["reference"];
            }
            //If no patient or encounter records present assume not tied to patient do not filter;
            if (patientId == null && encounterId == null)
            {
                return(true);
            }
            //See if patientId is in POR Cache
            if (!string.IsNullOrEmpty(patientId) && porcache.ContainsKey(patientId))
            {
                return(porcache[patientId]);
            }
            if (!string.IsNullOrEmpty(encounterId) && porcache.ContainsKey(encounterId))
            {
                return(porcache[encounterId]);
            }
            //Load the patient if needed
            if (patient == null)
            {
                if (!string.IsNullOrEmpty(patientId))
                {
                    var pat = await fhirClient.LoadResource(patientId, null, false, auditheaders);

                    JObject temp = JObject.Parse((string)pat.Content);
                    if (temp != null && ((string)temp["resourceType"]).Equals("Patient"))
                    {
                        patient = temp;
                    }
                    else
                    {
                        porcache[patientId] = false;
                        return(false);
                    }
                }
                else if (!string.IsNullOrEmpty(encounterId) && patient == null)
                {
                    var enc = await fhirClient.LoadResource(encounterId, null, false, auditheaders);

                    if (enc != null)
                    {
                        JObject temp = JObject.Parse((string)enc.Content);
                        if (temp != null && ((string)temp["resourceType"]).Equals("Encounter") && (string)temp["subject"]?["reference"] != null)
                        {
                            patientId = (string)temp["subject"]?["reference"];
                            var pat = await fhirClient.LoadResource(patientId, null, false, auditheaders);

                            JObject temp1 = JObject.Parse((string)pat.Content);
                            if (temp1 != null && ((string)temp1["resourceType"]).Equals("Patient"))
                            {
                                patient = temp1;
                            }
                            else
                            {
                                porcache[patientId] = false;
                                return(false);
                            }
                        }
                        else
                        {
                            porcache[encounterId] = false;
                            return(false);
                        }
                    }
                }
                else
                {
                    //Cannot Determine/Find a Patient or Encounter reference assume it's not a patient reference
                    return(true);
                }
            }


            foreach (string rid in knownresourceIdentities)
            {
                if (rid.StartsWith("Patient"))
                {
                    string pid = rid;
                    if (pid.Equals(patientId))
                    {
                        porcache[patientId] = true;
                        if (!string.IsNullOrEmpty(encounterId))
                        {
                            porcache[encounterId] = true;
                        }
                        return(true);
                    }
                }
                else if (rid.StartsWith("Practitioner"))
                {
                    if (patient["generalPractitioner"] != null)
                    {
                        var gp_s = from gp in patient["generalPractitioner"]
                                   where (string)gp["reference"] == rid
                                   select(string) gp["reference"];

                        if (gp_s != null && gp_s.Count() > 0)
                        {
                            porcache[patientId] = true;
                            if (!string.IsNullOrEmpty(encounterId))
                            {
                                porcache[encounterId] = true;
                            }
                            return(true);
                        }
                    }
                    string pid     = rid.Split("/")[1];
                    string patid   = (string)patient["id"];
                    var    porencs = await fhirClient.LoadResource("Encounter", $"patient={patid}&participant={pid}", false, auditheaders);

                    if (porencs != null)
                    {
                        JObject temp2 = JObject.Parse((string)porencs.Content);
                        if (temp2 != null && ((string)temp2["resourceType"]).Equals("Bundle"))
                        {
                            JArray entries = (JArray)temp2["entry"];
                            if (entries != null && entries.Count > 0)
                            {
                                porcache[patientId] = true;
                                if (!string.IsNullOrEmpty(encounterId))
                                {
                                    porcache[encounterId] = true;
                                }
                                return(true);
                            }
                        }
                    }
                }
            }
            porcache[patientId] = false;
            if (!string.IsNullOrEmpty(encounterId))
            {
                porcache[encounterId] = false;
            }
            return(false);
        }
Esempio n. 2
0
        private bool denyAccess(JToken resource, FHIRClient fhirclient, IDatabase cache, List <string> associations, string consentcat, IHeaderDictionary headers)
        {
            string patientId = null;
            string rt        = resource.FHIRResourceType();

            //Check for Patient resource or load patient resource id from subject/patient member
            if (rt.Equals("Patient"))
            {
                patientId = rt + "/" + (string)resource["id"];
            }
            if (patientId == null)
            {
                patientId = (string)resource?["subject"]?["reference"];
                if (string.IsNullOrEmpty(patientId) || !patientId.StartsWith("Patient"))
                {
                    patientId = (string)resource?["patient"]?["reference"];
                }
            }
            //If no patient id present assume not tied to patient do not filter;
            if (string.IsNullOrEmpty(patientId))
            {
                return(false);
            }
            //Load Cache if needed
            List <string> denyactors = ((string)cache.StringGet($"{PATIENT_DENY_ACTORS_PREFIX}{patientId}")).DeSerializeList <string>();

            if (denyactors == null)
            {
                //Fetch and Cache Deny access Consent Information
                var pid         = patientId.Split("/")[1];
                var consentrecs = fhirclient.LoadResource("Consent", "patient=" + pid + "&category=" + consentcat, true, headers);
                var result      = (JObject)consentrecs.Content;
                if (result.FHIRResourceType().Equals("Bundle"))
                {
                    JArray entries = (JArray)result["entry"];
                    if (!entries.IsNullOrEmpty())
                    {
                        denyactors = new List <string>();
                        foreach (JToken tok in entries)
                        {
                            var r = tok["resource"];
                            if (!r["provision"].IsNullOrEmpty())
                            {
                                //Check enforceemnt period
                                if (isEnforced(r["provision"]["period"]))
                                {
                                    string type = (string)r["provision"]["type"];
                                    //Load deny provisions only

                                    if (type != null && type.Equals("deny"))
                                    {
                                        //Load actor references to deny
                                        JArray actors = (JArray)r["provision"]["actors"];
                                        if (!actors.IsNullOrEmpty())
                                        {
                                            foreach (JToken actor in actors)
                                            {
                                                denyactors.Add((string)actor["reference"]);
                                            }
                                        }
                                        else
                                        {
                                            //Nobody specified so everybody is denied access this trumps all opt out advise
                                            denyactors.Clear();
                                            denyactors.Add("*");
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        denyactors = new List <string>();
                    }
                    cache.StringSet($"{PATIENT_DENY_ACTORS_PREFIX}{patientId}", denyactors.Distinct().ToList().SerializeList(), TimeSpan.FromHours(Utils.GetIntEnvironmentVariable("CONSENT_CACHE_TTL_MINUTES", "60")));
                }
            }
            //If there is an empty actor array that means there is no deny provision specified so return false to allow access
            if (denyactors.Count == 0)
            {
                return(false);
            }
            //It there is a wildcard in first entry then everyone is denied return true
            if (denyactors.First().Equals("*"))
            {
                return(true);
            }
            //Check for intersection of denied actors and associations of current user if found access will be denied
            return(associations.Select(x => x)
                   .Intersect(denyactors)
                   .Any());
        }
Esempio n. 3
0
        /* Opt-out: Default is for health information of patients to be included automatically, but the patient can opt out completely.
         * Note: This is an access only policy, it does not prevent updates to the medical record as these could be valid */
        public ProxyProcessResult Process(FHIRResponse response, HttpRequest req, ILogger log, ClaimsPrincipal principal, string res, string id, string hist, string vid)
        {
            FHIRResponse fr = response;

            if (!req.Method.Equals("GET"))
            {
                return(new ProxyProcessResult(true, "", "", fr));
            }
            //Load the consent category code from settings
            string consent_category = System.Environment.GetEnvironmentVariable("CONSENT_OPTOUT_CATEGORY");

            if (string.IsNullOrEmpty(consent_category))
            {
                log.LogWarning("ConsentOptOutFilter: No value for CONSENT_OPTOUT_CATEGORY in settings...Filter will not execute");
                return(new ProxyProcessResult(true, "", "", fr));
            }
            JObject result = (fr == null ? null : JObject.Parse(fr.ToString()));

            if (fr == null)
            {
                log.LogInformation("ConsentOptOutFilter: No FHIR Response found in context...Nothing to filter");
                return(new ProxyProcessResult());
            }
            //Administrator is allowed access
            if (Utils.inServerAccessRole(req, "A"))
            {
                return(new ProxyProcessResult(true, "", "", fr));
            }
            ClaimsIdentity ci     = (ClaimsIdentity)principal.Identity;
            string         aadten = ci.Tenant();
            string         name   = principal.Identity.Name;
            //We'll need FHIRClient to check server
            FHIRClient    fhirClient   = FHIRClientFactory.getClient(log);
            var           cache        = Utils.RedisConnection.GetDatabase();
            List <string> associations = ((string)cache.StringGet($"{ASSOCIATION_CACHE_PREFIX}{aadten}-{name}")).DeSerializeList <string>();

            if (associations == null)
            {
                //Load Associations if not in cache
                associations = new List <string>();
                var table = Utils.getTable();
                //Practioner
                var practitioner = Utils.getLinkEntity(table, "Practitioner", aadten + "-" + name);
                if (practitioner != null)
                {
                    associations.Add(practitioner.PartitionKey + "/" + practitioner.LinkedResourceId);
                    //Load organization from PractionerRoles
                    var prs = fhirClient.LoadResource("PractitionerRole", "practitioner=" + practitioner.LinkedResourceId, true, req.Headers);
                    var ro  = (JObject)prs.Content;
                    if (ro.FHIRResourceType().Equals("Bundle"))
                    {
                        JArray entries = (JArray)ro["entry"];
                        if (!entries.IsNullOrEmpty())
                        {
                            foreach (JToken tok in entries)
                            {
                                associations.Add(tok["resource"].FHIRReferenceId());
                                if (!tok["resource"]["organization"].IsNullOrEmpty() && !tok["resource"]["organization"]["reference"].IsNullOrEmpty())
                                {
                                    associations.Add((string)tok["resource"]["organization"]["reference"]);
                                }
                            }
                        }
                    }
                }
                //RealtedPerson
                var related = Utils.getLinkEntity(table, "RelatedPerson", aadten + "-" + name);
                if (related != null)
                {
                    associations.Add(related.PartitionKey + "/" + related.LinkedResourceId);
                }

                cache.StringSet($"{ASSOCIATION_CACHE_PREFIX}{aadten}-{name}", associations.Distinct().ToList().SerializeList(), TimeSpan.FromMinutes(Utils.GetIntEnvironmentVariable("CONSENT_CACHE_TTL_MINUTES", "60")));
            }

            //Loop through results load any consent records and validate no opt-out default is to allow
            if (result.FHIRResourceType().Equals("Bundle"))
            {
                JArray entries = (JArray)result["entry"];
                if (!entries.IsNullOrEmpty())
                {
                    foreach (JToken tok in entries)
                    {
                        if (denyAccess(tok["resource"], fhirClient, cache, associations, consent_category, req.Headers))
                        {
                            JObject denyObj = new JObject();
                            denyObj["resourceType"]   = tok["resource"].FHIRResourceType();
                            denyObj["id"]             = tok["resource"].FHIRResourceId();
                            denyObj["text"]           = new JObject();
                            denyObj["text"]["status"] = "generated";
                            denyObj["text"]["div"]    = "<div xmlns =\"http://www.w3.org/1999/xhtml\"><p>Patient has withheld access to this resource</p></div>";
                            tok["resource"]           = denyObj;
                        }
                    }
                }
            }
            else if (!result.FHIRResourceType().Equals("OperationalOutcome"))
            {
                if (denyAccess(result, fhirClient, cache, associations, consent_category, req.Headers))
                {
                    fr.Content    = Utils.genOOErrResponse("access-denied", $"The patient has withheld access to this resource: {res + (id == null ? "" : "/" + id)}");
                    fr.StatusCode = System.Net.HttpStatusCode.Unauthorized;
                    return(new ProxyProcessResult(false, "access-denied", "", fr));
                }
            }
            fr.Content = result.ToString();
            return(new ProxyProcessResult(true, "", "", fr));
        }
Esempio n. 4
0
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <object> result)
        {
            var    activity = await result as Activity;
            string msg      = activity.Text.Trim().ToLower();

            if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg == "start again" || msg == "restart" || msg == "leave" || msg == "reset" || msg == "bye" || msg == "goodbye")
            {
                context.PrivateConversationData.Clear();
                await context.PostAsync($"Ending your session...Dont' forget to delete your conversation for privacy!");

                context.Done("");
            }
            else
            {
                model.Patient pat = null;
                // Within the code body set your variable
                string     fhirserver       = CloudConfigurationManager.GetSetting("FHIRServerAddress");
                string     fhirtenant       = CloudConfigurationManager.GetSetting("FHIRAADTenant");
                string     fhirclientid     = CloudConfigurationManager.GetSetting("FHIRClientId");
                string     fhirclientsecret = CloudConfigurationManager.GetSetting("FHIRClientSecret");
                FHIRClient fhirclient       = new FHIRClient(fhirserver, fhirtenant, fhirclientid, fhirclientsecret);
                var        rslt             = (model.Bundle)fhirclient.LoadResource("Patient", "identifier=http://fhirbot.org|" + activity.Text.Trim());
                if (rslt != null && rslt.Entry != null && rslt.Entry.Count > 0)
                {
                    pat = (model.Patient)rslt.Entry.FirstOrDefault().Resource;
                    if (pat != null)
                    {
                        var fbid = pat.Identifier.Single(ident => ident.System == "http://fhirbot.org");
                        if (fbid != null)
                        {
                            var period = fbid.Period;
                            var now    = model.FhirDateTime.Now();
                            if (period != null && (now > period.EndElement))
                            {
                                //Use Period Expired remove the token from the patient and update db
                                pat.Identifier.Remove(fbid);
                                fhirclient.SaveResource(pat);
                                pat = null;
                                context.PrivateConversationData.Clear();
                            }
                        }
                    }
                }
                if (pat != null)
                {
                    // Set BotUserData
                    context.PrivateConversationData.SetValue <string>(
                        "id", pat.Id);
                    context.PrivateConversationData.SetValue <string>(
                        "name", pat.Name[0].Text);
                    context.PrivateConversationData.SetValue <DateTime?>(
                        "sessionstart", DateTime.Now);
                    context.PrivateConversationData.SetValue <string>("bearertoken", fhirclient.BearerToken);
                    context.PrivateConversationData.SetValue <string>("fhirserver", fhirserver);
                    context.Done(pat.Name[0].Text);
                }
                else
                {
                    context.Fail(new InvalidPINException("Not a valid PIN Code"));
                }
            }
        }