Beispiel #1
0
        public static ListedCapabilityStatement TryAddRestInteraction(this ListedCapabilityStatement statement, ResourceType resourceType, CapabilityStatement.TypeRestfulInteraction interaction)
        {
            EnsureArg.IsNotNull(statement, nameof(statement));

            statement.BuildRestResourceComponent(resourceType, builder =>
            {
                var hasInteraction = builder
                                     .Interaction
                                     .FirstOrDefault(x => x.Code == interaction);

                if (hasInteraction == null)
                {
                    builder
                    .Interaction
                    .Add(new CapabilityStatement.ResourceInteractionComponent
                    {
                        Code = interaction,
                    });
                }
            });

            return(statement);
        }
        public static CapabilityStatement Intersect(this ListedCapabilityStatement system, CapabilityStatement configured, bool strictConfig)
        {
            EnsureArg.IsNotNull(system, nameof(system));
            EnsureArg.IsNotNull(configured, nameof(configured));

            var issues = new List <string>();

            var intersecting = new CapabilityStatement
            {
                // System wide values
                Id           = system.Id,
                Url          = system.Url?.OriginalString,
                Version      = system.Version,
                Name         = system.Name,
                Experimental = system.Experimental,
                Publisher    = system.Publisher,
                Software     = system.Software,
                FhirVersion  = system.FhirVersion,
                Contact      = new List <ContactDetail> {
                    new ContactDetail {
                        Telecom = system.Telecom?.Select(x => new ContactPoint(x.System, x.Use, x.Value)).ToList()
                    }
                },

                // Intersections with user configured values
                Kind          = system.Kind.IntersectEnum(configured.Kind, issues, "Kind"),
                Status        = system.Status.IntersectEnum(configured.Status, issues, "Status"),
                AcceptUnknown = system.AcceptUnknown.IntersectEnum(configured.AcceptUnknown, issues, "AcceptUknown"),
                Format        = system.Format?.IntersectList(configured.Format, x => x, issues, "Format"),
            };

            DateTimeOffset cDate;

            if (DateTimeOffset.TryParse(configured.Date, out cDate))
            {
                intersecting.Date = cDate.ToString("o", CultureInfo.InvariantCulture);
            }

            if (system.Rest.Any() && configured.Rest.Any())
            {
                // Only a single rest node is currently supported
                if (system.Rest.Count() > 1 || configured.Rest.Count > 1)
                {
                    throw new NotSupportedException(Core.Resources.CapabilityStatementSingleRestItem);
                }

                var systemRest     = system.Rest.Single();
                var configuredRest = configured.Rest.Single();

                var rest = new CapabilityStatement.RestComponent
                {
                    Mode          = systemRest.Mode.IntersectEnum(configuredRest.Mode, issues, "Rest.Mode"),
                    Documentation = systemRest.Documentation,
                    Security      = systemRest.Security,
                    Interaction   = systemRest.Interaction?.IntersectList(configuredRest.Interaction, x => x.Code, issues, $"Rest.Interaction"),
                    SearchParam   = systemRest.SearchParam?.IntersectList(configuredRest.SearchParam, x => x.Name, issues, $"Rest.SearchParam"),
                    Operation     = systemRest.Operation?.IntersectList(configuredRest.Operation, x => x.Name, issues, $"Rest.Operation"),
                };

                intersecting.Rest.Add(rest);

                var systemComponents = systemRest.Resource.Where(x => configuredRest.Resource.Select(r => r.Type).Contains(x.Type));
                foreach (var systemComponent in systemComponents)
                {
                    var configuredComponent = configuredRest.Resource.Single(x => x.Type == systemComponent.Type);

                    // If the system has been set to support include, then build the possible include params from the search parameters
                    if (system.SupportsInclude)
                    {
                        systemComponent.SearchInclude = systemComponent.SearchParam.Where(sp => sp.Type == SearchParamType.Reference).Select(sp => $"{systemComponent.Type.ToString()}.{sp.Name}").ToList();
                    }

                    var interaction = new CapabilityStatement.ResourceComponent
                    {
                        // System predefined values
                        Type = systemComponent.Type,

                        // User configurable override
                        Profile = configuredComponent.Profile ?? systemComponent.Profile,

                        // Boolean intersections
                        ReadHistory       = systemComponent.ReadHistory.IntersectBool(configuredComponent.ReadHistory, issues, $"Rest.Resource['{systemComponent.Type}'].ReadHistory"),
                        UpdateCreate      = systemComponent.UpdateCreate.IntersectBool(configuredComponent.UpdateCreate, issues, $"Rest.Resource['{systemComponent.Type}'.UpdateCreate"),
                        ConditionalCreate = systemComponent.ConditionalCreate.IntersectBool(configuredComponent.ConditionalCreate, issues, $"Rest.Resource['{systemComponent.Type}'].ConditionalCreate"),
                        ConditionalUpdate = systemComponent.ConditionalUpdate.IntersectBool(configuredComponent.ConditionalUpdate, issues, $"Rest.Resource['{systemComponent.Type}'].ConditionalUpdate"),

                        // List intersections
                        SearchInclude    = system.SupportsInclude ? systemComponent.SearchInclude.IntersectList(configuredComponent.SearchInclude, x => x, issues, $"Rest.Resource['{systemComponent.Type}'].SearchInclude").ToList() : Enumerable.Empty <string>(),
                        SearchRevInclude = systemComponent.SearchRevInclude.IntersectList(configuredComponent.SearchRevInclude, x => x, issues, $"Rest.Resource['{systemComponent.Type}'].SearchRevInclude").ToList(),
                        Interaction      = systemComponent.Interaction.IntersectList(configuredComponent.Interaction, x => x.Code, issues, $"Rest.Resource['{systemComponent.Type}'].Interaction"),
                        ReferencePolicy  = systemComponent.ReferencePolicy.IntersectList(configuredComponent.ReferencePolicy, x => x, issues, $"Rest.Resource['{systemComponent.Type}'].ReferencePolicy"),
                        SearchParam      = systemComponent.SearchParam.IntersectList(configuredComponent.SearchParam, x => string.Concat(x.Name, x.Type), issues, $"Rest.Resource['{systemComponent.Type}'].SearchParam"),

                        // Listed Enumerations intersections
                        Versioning        = systemComponent.Versioning.IntersectEnum(configuredComponent.Versioning, issues, $"Rest.Resource['{systemComponent.Type}'].Versioning"),
                        ConditionalRead   = systemComponent.ConditionalRead.IntersectEnum(configuredComponent.ConditionalRead, issues, $"Rest.Resource['{systemComponent.Type}'].ConditionalRead"),
                        ConditionalDelete = systemComponent.ConditionalDelete.IntersectEnum(configuredComponent.ConditionalDelete, issues, $"Rest.Resource['{systemComponent.Type}'].ConditionalDelete"),
                    };

                    rest.Resource.Add(interaction);
                }

                rest.Resource = rest.Resource.OrderBy(x => x.Type.ToString()).ToList();
            }

            if (strictConfig && issues.Any())
            {
                throw new UnsupportedConfigurationException(Core.Resources.UnsupportedConfigurationMessage, issues.Select(i => new OperationOutcomeIssue(OperationOutcomeConstants.IssueSeverity.Error, OperationOutcomeConstants.IssueType.Exception, i)).ToArray());
            }

            return(intersecting);
        }
        public static ListedCapabilityStatement AddOAuthSecurityService(this ListedCapabilityStatement statement, string authority, IHttpClientFactory httpClientFactory, ILogger logger)
        {
            EnsureArg.IsNotNull(statement, nameof(statement));
            EnsureArg.IsNotNull(authority, nameof(authority));
            EnsureArg.IsNotNull(httpClientFactory, nameof(httpClientFactory));

            var restComponent = statement.GetListedRestComponent();
            var security      = restComponent.Security ?? new CapabilityStatement.SecurityComponent();

            security.Service.Add(Constants.RestfulSecurityServiceOAuth);

            var openIdConfigurationUrl = $"{authority}/.well-known/openid-configuration";

            HttpResponseMessage openIdConfigurationResponse;

            using (var httpClient = httpClientFactory.CreateClient())
            {
                try
                {
                    openIdConfigurationResponse = httpClient.GetAsync(new Uri(openIdConfigurationUrl)).GetAwaiter().GetResult();
                }
                catch (Exception ex)
                {
                    logger.LogWarning(ex, $"There was an exception while attempting to read the OpenId Configuration from \"{openIdConfigurationUrl}\".");
                    throw new OpenIdConfigurationException();
                }
            }

            if (openIdConfigurationResponse.IsSuccessStatusCode)
            {
                var openIdConfiguration = JObject.Parse(openIdConfigurationResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult());

                string tokenEndpoint, authorizationEndpoint;

                try
                {
                    tokenEndpoint         = openIdConfiguration["token_endpoint"].Value <string>();
                    authorizationEndpoint = openIdConfiguration["authorization_endpoint"].Value <string>();
                }
                catch (Exception ex)
                {
                    logger.LogWarning(ex, $"There was an exception while attempting to read the endpoints from \"{openIdConfigurationUrl}\".");
                    throw new OpenIdConfigurationException();
                }

                var smartExtension = new Extension()
                {
                    Url       = Constants.SmartOAuthUriExtension,
                    Extension = new List <Extension>
                    {
                        new Extension(Constants.SmartOAuthUriExtensionToken, new FhirUri(tokenEndpoint)),
                        new Extension(Constants.SmartOAuthUriExtensionAuthorize, new FhirUri(authorizationEndpoint)),
                    },
                };

                security.Extension.Add(smartExtension);
            }
            else
            {
                logger.LogWarning($"The OpenId Configuration request from \"{openIdConfigurationUrl}\" returned an {openIdConfigurationResponse.StatusCode} status code.");
                throw new OpenIdConfigurationException();
            }

            restComponent.Security = security;
            return(statement);
        }