public ISmartScopeOutcome ProcessScopes(PyroSearchParameters PyroSearchParameters, FHIRAllTypes ServiceResourceType, bool Read, bool Write) { ISmartScopeOutcome SmartScopeOutcome = new SmartScopeOutcome() { ScopesOK = false }; // If FHIRApiAuthentication = false then no need to check and scopes, ScopesOK! if (!IGlobalProperties.FHIRApiAuthentication) { SmartScopeOutcome.ScopesOK = true; return(SmartScopeOutcome); } SmartEnum.Action SmartAction = GetActionEnum(Read, Write); if (System.Threading.Thread.CurrentPrincipal != null && System.Threading.Thread.CurrentPrincipal is ClaimsPrincipal Principal) { //Get Client Id, we need to log this somewere, maybe FHIR AuditEventy? System.Security.Claims.Claim ClientClaim = Principal.Claims.SingleOrDefault(x => x.Type == ClientIdName); //Get tye scopes List <System.Security.Claims.Claim> ScopeClaim = Principal.Claims.Where(x => x.Type == ScopeName).ToList(); //This should be injected ScopeParse ScopeParse = new ScopeParse(); List <ISmartScope> ScopeList = new List <ISmartScope>(); foreach (var ScopeString in ScopeClaim) { ISmartScope SmartScope = new SmartScope(); if (ScopeParse.Parse(ScopeString.Value, out SmartScope)) { ScopeList.Add(SmartScope); } else { string Message = $"Unable to parse the SMART on FHIR scope given. Scope was {ScopeString.Value}"; var OpOut = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Exception, Message); throw new Common.Exceptions.PyroException(System.Net.HttpStatusCode.InternalServerError, OpOut, Message); } } IEnumerable <ISmartScope> FoundScopesList = ScopeList.Where(x => x.Resource == ServiceResourceType && (x.Action == SmartAction || x.Action == SmartEnum.Action.All)); if (FoundScopesList.Count() > 0) { if (PyroSearchParameters.IncludeList != null && PyroSearchParameters.IncludeList.Count > 0) { foreach (var Include in PyroSearchParameters.IncludeList) { FoundScopesList = ScopeList.Where(x => x.Resource == Include.SourceResourceType && (x.Action == SmartAction || x.Action == SmartEnum.Action.All)); if (FoundScopesList.Count() == 0) { //Reject string Message = $"You do not have permission to access the {Include.SourceResourceType.GetLiteral()} Resource type found within your include or revinclude search parameters."; var OpOut = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Forbidden, Message); SmartScopeOutcome.OperationOutcome = OpOut; SmartScopeOutcome.ScopesOK = false; return(SmartScopeOutcome); } } } var SearchParametersThatHaveChainParametersList = PyroSearchParameters.SearchParametersList.Where(x => x.ChainedSearchParameter != null); if (SearchParametersThatHaveChainParametersList != null && SearchParametersThatHaveChainParametersList.Count() > 0) { foreach (ISearchParameterBase Chain in SearchParametersThatHaveChainParametersList) { string ResourceWithNoScopeAccess = RecursiveChainScoped(Chain, ScopeList, SmartAction); if (!string.IsNullOrWhiteSpace(ResourceWithNoScopeAccess)) { //Reject string Message = $"You do not have permission to access {ResourceWithNoScopeAccess} resources types which was one of the resources types within your chained search parameter."; var OpOut = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Forbidden, Message); SmartScopeOutcome.OperationOutcome = OpOut; SmartScopeOutcome.ScopesOK = false; return(SmartScopeOutcome); } } } //ALL GOOD! We have a scope for the resource and action. all ok. SmartScopeOutcome.ScopesOK = true; return(SmartScopeOutcome); } else { string Message = string.Empty; if (SmartAction == SmartEnum.Action.All) { Message = $"You do not have permission to access Resources {ServiceResourceType.GetLiteral()} types for Read or Write."; } else if (SmartAction == SmartEnum.Action.Read) { Message = $"You do not have permission to access Resources {ServiceResourceType.GetLiteral()} types for Read."; } else if (SmartAction == SmartEnum.Action.Read) { Message = $"You do not have permission to access Resources {ServiceResourceType.GetLiteral()} types for Write."; } var OpOut = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Forbidden, Message); SmartScopeOutcome.OperationOutcome = OpOut; SmartScopeOutcome.ScopesOK = false; return(SmartScopeOutcome); } } else { //System.Threading.Thread.CurrentPrincipal was null string Message = "Internal Server Error: System.Threading.Thread.CurrentPrincipal was null"; var OpOut = Common.Tools.FhirOperationOutcomeSupport.Create(OperationOutcome.IssueSeverity.Error, OperationOutcome.IssueType.Exception, Message); throw new Common.Exceptions.PyroException(System.Net.HttpStatusCode.InternalServerError, OpOut, Message); } }
private static string GetScopeString(SmartEnum.Entity Entity, string Resource, SmartEnum.Action Action) { //user/*.write string ScopeString = string.Empty; if (Entity == SmartEnum.Entity.Patient) { ScopeString += KeyWord.Patient; } else if (Entity == SmartEnum.Entity.User) { ScopeString += KeyWord.User; } else { throw new FormatException($"Unkown Smart Scope Entity of {Entity.ToString()}"); } ScopeString += KeyWord.SlashDelimiter; if (!String.IsNullOrWhiteSpace(Resource)) { ScopeString += Resource; } else { throw new FormatException($"Unkown Smart Scope Resource of {Resource}"); } ScopeString += KeyWord.DotDelimiter; if (Action == SmartEnum.Action.Read) { ScopeString += KeyWord.Read; } else if (Action == SmartEnum.Action.Write) { ScopeString += KeyWord.Write; } else if (Action == SmartEnum.Action.All) { ScopeString += KeyWord.All; } else { throw new FormatException($"Unkown Smart Scope Action of {Action.ToString()}"); } return(ScopeString); }
private string RecursiveChainScoped(ISearchParameterBase ParentChain, List <ISmartScope> ScopeList, SmartEnum.Action SmartAction) { IEnumerable <ISmartScope> FoundScopesList = ScopeList.Where(x => x.Resource.GetLiteral() == ParentChain.Resource && (x.Action == SmartAction || x.Action == SmartEnum.Action.All)); if (FoundScopesList.Count() > 0) { if (ParentChain.ChainedSearchParameter != null) { //Test the next search parameter return(RecursiveChainScoped(ParentChain.ChainedSearchParameter, ScopeList, SmartAction)); } else { //If the scopes are fine and allowed then we return empty string as suscess return(string.Empty); } } else { //If we are unable to find a scope for a given resource type we return the Resource name for error reporting. return(ParentChain.Resource); } }
//Support Methods private static string[] GetAllResourcesScopeStringList(SmartEnum.Entity Entity, SmartEnum.Action Action) { string[] ScopeList = new string[ModelInfo.SupportedResources.Count]; for (int i = 0; i < ModelInfo.SupportedResources.Count; i++) { ScopeList[i] = GetScopeString(Entity, ModelInfo.SupportedResources[i], Action); } return(ScopeList); }