/// <summary>
        /// Retrieves a populated <see cref="OpenIdConnectConfiguration"/> given an address and an <see cref="IDocumentRetriever"/>.
        /// </summary>
        /// <param name="address">address of the discovery document.</param>
        /// <param name="retriever">the <see cref="IDocumentRetriever"/> to use to read the discovery document</param>
        /// <param name="cancel"><see cref="CancellationToken"/>.</param>
        /// <returns>A populated <see cref="OpenIdConnectConfiguration"/> instance.</returns>
        public static async Task <OpenIdConnectConfiguration> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw LogHelper.LogArgumentNullException(nameof(address));
            }

            if (retriever == null)
            {
                throw LogHelper.LogArgumentNullException(nameof(retriever));
            }

            string doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            LogHelper.LogVerbose(LogMessages.IDX21811, doc);
            OpenIdConnectConfiguration openIdConnectConfiguration = JsonConvert.DeserializeObject <OpenIdConnectConfiguration>(doc);

            if (!string.IsNullOrEmpty(openIdConnectConfiguration.JwksUri))
            {
                LogHelper.LogVerbose(LogMessages.IDX21812, openIdConnectConfiguration.JwksUri);
                string keys = await retriever.GetDocumentAsync(openIdConnectConfiguration.JwksUri, cancel).ConfigureAwait(false);

                LogHelper.LogVerbose(LogMessages.IDX21813, openIdConnectConfiguration.JwksUri);
                openIdConnectConfiguration.JsonWebKeySet = JsonConvert.DeserializeObject <JsonWebKeySet>(keys);
                foreach (SecurityKey key in openIdConnectConfiguration.JsonWebKeySet.GetSigningKeys())
                {
                    openIdConnectConfiguration.SigningKeys.Add(key);
                }
            }

            return(openIdConnectConfiguration);
        }
        /// <summary>
        /// Retrieves a populated <see cref="OpenIdConnectConfiguration"/> given an address and an <see cref="IDocumentRetriever"/>.
        /// </summary>
        /// <param name="address">address of the discovery document.</param>
        /// <param name="retriever">the <see cref="IDocumentRetriever"/> to use to read the discovery document</param>
        /// <param name="cancel"><see cref="CancellationToken"/>.</param>
        /// <returns>A populated <see cref="OpenIdConnectConfiguration"/> instance.</returns>
        public static async Task <OpenIdConnectConfiguration> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw new ArgumentNullException("address");
            }

            if (retriever == null)
            {
                throw new ArgumentNullException("retriever");
            }

            string doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            OpenIdConnectConfiguration openIdConnectConfiguration = new OpenIdConnectConfiguration(doc);

            if (!string.IsNullOrEmpty(openIdConnectConfiguration.JwksUri))
            {
                string keys = await retriever.GetDocumentAsync(openIdConnectConfiguration.JwksUri, cancel).ConfigureAwait(false);

                openIdConnectConfiguration.JsonWebKeySet = new JsonWebKeySet(keys);
                foreach (SecurityToken token in openIdConnectConfiguration.JsonWebKeySet.GetSigningTokens())
                {
                    openIdConnectConfiguration.SigningTokens.Add(token);
                }
            }

            return(openIdConnectConfiguration);
        }
예제 #3
0
        private async Task <MetadataBase> GetAsync(FederationPartyConfiguration context, IDocumentRetriever retriever, CancellationToken cancel)
        {
            this._metadataSerialiser.Validator.SetFederationPartyId(context.FederationPartyId);
            if (string.IsNullOrWhiteSpace(context.MetadataAddress))
            {
                throw new ArgumentNullException("address");
            }
            if (retriever == null)
            {
                throw new ArgumentNullException("retriever");
            }
            var str = await retriever.GetDocumentAsync(context.MetadataAddress, cancel);

            var document = str;

            str = null;

            using (XmlReader reader = XmlReader.Create(new StringReader(document), this._safeSettings))
            {
                var federationConfiguration = this._metadataSerialiser.Deserialise(reader);
                if (this.MetadataReceivedCallback != null)
                {
                    this.MetadataReceivedCallback(federationConfiguration);
                }
                return(federationConfiguration);
            }
        }
        /// <summary>
        /// Retrieves a populated <see cref="OpenIdConnectConfiguration"/> given an address and an <see cref="IDocumentRetriever"/>.
        /// </summary>
        /// <param name="address">address of the jwks uri.</param>
        /// <param name="retriever">the <see cref="IDocumentRetriever"/> to use to read the jwks</param>
        /// <param name="cancel"><see cref="CancellationToken"/>.</param>
        /// <returns>A populated <see cref="OpenIdConnectConfiguration"/> instance.</returns>
        public static async Task <OpenIdConnectConfiguration> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw LogHelper.LogArgumentNullException(nameof(address));
            }

            if (retriever == null)
            {
                throw LogHelper.LogArgumentNullException(nameof(retriever));
            }

            var doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            LogHelper.LogVerbose("IDX21811: Deserializing the string: '{0}' obtained from metadata endpoint into openIdConnectConfiguration object.", doc);
            var jwks = new JsonWebKeySet(doc);
            var openIdConnectConfiguration = new OpenIdConnectConfiguration()
            {
                JsonWebKeySet = jwks,
                JwksUri       = address,
            };

            foreach (var securityKey in jwks.GetSigningKeys())
            {
                openIdConnectConfiguration.SigningKeys.Add(securityKey);
            }

            return(openIdConnectConfiguration);
        }
        /// <summary>Retrieves a populated configuration given an address and an <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/>.</summary>
        /// <param name="address">Address of the discovery document.</param>
        /// <param name="retriever">The <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/> to use to read the discovery document.</param>
        /// <param name="cancel">A cancellation token that can be used by other objects or threads to receive notice of cancellation. <see cref="T:System.Threading.CancellationToken"/>.</param>
        /// <returns>
        /// A <see cref="Task{IssuerMetadata}"/> that, when completed, returns <see cref="IssuerMetadata"/> from the configuration.
        /// </returns>
        /// <exception cref="ArgumentNullException">address - Azure AD Issuer metadata address URL is required
        /// or retriever - No metadata document retriever is provided.</exception>
        public async Task <IssuerMetadata> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            string doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            IssuerMetadata issuerMetadata = JsonConvert.DeserializeObject <IssuerMetadata>(doc);

            return(issuerMetadata);
        }
예제 #6
0
        /// <summary>
        /// Retrieves a populated <see cref="WsFederationConfiguration"/> given an address and an <see cref="IDocumentRetriever"/>.
        /// </summary>
        /// <param name="address">address of the metadata document.</param>
        /// <param name="retriever">the <see cref="IDocumentRetriever"/> to use to read the metadata document</param>
        /// <param name="cancel"><see cref="CancellationToken"/>.</param>
        /// <returns>A populated <see cref="WsFederationConfiguration"/> instance.</returns>
        public static async Task <WsFederationConfiguration> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                LogHelper.Throw(string.Format(CultureInfo.InvariantCulture, LogMessages.IDX10000, GetType() + ": address"), typeof(ArgumentNullException), EventLevel.Verbose);
            }

            if (retriever == null)
            {
                LogHelper.Throw(string.Format(CultureInfo.InvariantCulture, LogMessages.IDX10000, GetType() + ": retriever"), typeof(ArgumentNullException), EventLevel.Verbose);
            }

            WsFederationConfiguration configuration = new WsFederationConfiguration();

            string document = await retriever.GetDocumentAsync(address, cancel);

            using (XmlReader metaDataReader = XmlReader.Create(new StringReader(document), SafeSettings))
            {
                var serializer = new MetadataSerializer {
                    CertificateValidationMode = X509CertificateValidationMode.None
                };

                MetadataBase metadataBase     = serializer.ReadMetadata(metaDataReader);
                var          entityDescriptor = (EntityDescriptor)metadataBase;

                if (!string.IsNullOrWhiteSpace(entityDescriptor.EntityId.Id))
                {
                    configuration.Issuer = entityDescriptor.EntityId.Id;
                }

                SecurityTokenServiceDescriptor stsd = entityDescriptor.RoleDescriptors.OfType <SecurityTokenServiceDescriptor>().First();
                if (stsd != null)
                {
                    configuration.TokenEndpoint = stsd.PassiveRequestorEndpoints.First().Uri.AbsoluteUri;
                    foreach (KeyDescriptor keyDescriptor in stsd.Keys)
                    {
                        if (keyDescriptor.KeyInfo != null && (keyDescriptor.Use == KeyType.Signing || keyDescriptor.Use == KeyType.Unspecified))
                        {
                            IdentityModelEventSource.Logger.WriteVerbose(LogMessages.IDX10807);
                            foreach (SecurityKeyIdentifierClause clause in keyDescriptor.KeyInfo)
                            {
                                X509RawDataKeyIdentifierClause x509Clause = clause as X509RawDataKeyIdentifierClause;
                                if (x509Clause != null)
                                {
                                    var key = new X509SecurityKey(new X509Certificate2(x509Clause.GetX509RawData()));
                                    configuration.SigningKeys.Add(key);
                                }
                            }
                        }
                    }
                }
            }

            return(configuration);
        }
        /// <summary>
        /// Retrieves the configuration document and deserializes it
        /// </summary>
        /// <param name="address">Url where the document is to be downloaded from</param>
        /// <param name="retriever">Engine that retrieves the document. Injected by ASP.NET Core at runtime</param>
        /// <param name="cancellationToken">Async process cancellation token</param>
        /// <returns>Deserialized issuer metadata</returns>
        public async Task <IssuerMetadata> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw new ArgumentNullException(nameof(address));
            }
            if (retriever == null)
            {
                throw new ArgumentNullException(nameof(retriever));
            }

            return(JsonConvert.DeserializeObject <IssuerMetadata>(await retriever.GetDocumentAsync(address, cancellationToken)));
        }
예제 #8
0
            /// <summary>
            /// Retrieves the OAuth2 introspection configuration from the specified address.
            /// </summary>
            /// <param name="address">The address of the discovery document.</param>
            /// <param name="retriever">The object used to retrieve the discovery document.</param>
            /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
            /// <returns>An <see cref="OAuthIntrospectionConfiguration"/> instance.</returns>
            public async Task <OAuthIntrospectionConfiguration> GetConfigurationAsync(
                [NotNull] string address, [NotNull] IDocumentRetriever retriever, CancellationToken cancellationToken)
            {
                if (string.IsNullOrEmpty(address))
                {
                    throw new ArgumentException("The address cannot be null or empty.", nameof(address));
                }

                if (retriever == null)
                {
                    throw new ArgumentNullException(nameof(retriever));
                }

                return(new OAuthIntrospectionConfiguration(await retriever.GetDocumentAsync(address, cancellationToken)));
            }
예제 #9
0
 private void GetDocument(string address, IDocumentRetriever docRetriever, ExpectedException ee)
 {
     try
     {
         string doc = docRetriever.GetDocumentAsync(address, CancellationToken.None).Result;
         ee.ProcessNoException();
     }
     catch (AggregateException ex)
     {
         ex.Handle((x) =>
         {
             ee.ProcessException(x);
             return(true);
         });
     }
 }
 public Task <string> GetDocumentAsync(string address, CancellationToken cancel)
 {
     if (string.Equals("primary", address))
     {
         return(Task.FromResult(_primaryDocument));
     }
     if (string.Equals("secondary", address) && !string.IsNullOrWhiteSpace(_secondaryDocument))
     {
         return(Task.FromResult(_secondaryDocument));
     }
     if (_fallback != null)
     {
         return(_fallback.GetDocumentAsync(address, cancel));
     }
     throw new IOException("Document not found: " + address);
 }
        /// <summary>Retrieves a populated configuration given an address and an <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/>.</summary>
        /// <param name="address">Address of the discovery document.</param>
        /// <param name="retriever">The <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/> to use to read the discovery document.</param>
        /// <param name="cancel">A cancellation token that can be used by other objects or threads to receive notice of cancellation. <see cref="T:System.Threading.CancellationToken"/>.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">address - Azure AD Issuer metadata address url is required
        /// or
        /// retriever - No metadata document retriever is provided</exception>
        public async Task <IssuerMetadata> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrEmpty(address))
            {
                throw new ArgumentNullException(nameof(address), $"Azure AD Issuer metadata address url is required");
            }

            if (retriever == null)
            {
                throw new ArgumentNullException(nameof(retriever), $"No metadata document retriever is provided");
            }

            var doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            return(JsonSerializer.Deserialize <IssuerMetadata>(doc));
        }
예제 #12
0
        public async Task <IDictionary <string, string[]> > GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            var res = await retriever.GetDocumentAsync(address, cancel);

            var obj = Newtonsoft.Json.JsonConvert.DeserializeObject <JObject>(res);

            if (obj != null && obj.HasValues && obj["keys"] != null)
            {
                var keys         = obj.SelectToken("keys").Value <JArray>();
                var endorsements = keys.Where(key => key["endorsements"] != null).Select(key => Tuple.Create(key.SelectToken("kid").Value <string>(), key.SelectToken("endorsements").Values <string>()));
                return(endorsements.Distinct(new EndorsementsComparer()).ToDictionary(item => item.Item1, item => item.Item2.ToArray()));
            }
            else
            {
                return(new Dictionary <string, string[]>());
            }
        }
        private static async Task <WsFederationConfiguration> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            var document = await retriever.GetDocumentAsync(address, cancel);

            var configuration = new WsFederationConfiguration();

            using (var sr = new StringReader(document))
                using (var xr = XmlReader.Create(sr, _settings))
                {
                    var serializer = new MetadataSerializer {
                        CertificateValidationMode = X509CertificateValidationMode.None
                    };
                    var entityDescriptor = serializer.ReadMetadata(xr) as EntityDescriptor;

                    if (entityDescriptor != null)
                    {
                        configuration.Issuer = entityDescriptor.EntityId.Id;

                        var idpssod = entityDescriptor.RoleDescriptors.OfType <IdentityProviderSingleSignOnDescriptor>().FirstOrDefault();

                        if (idpssod != null)
                        {
                            var redirectBinding = idpssod.SingleSignOnServices.FirstOrDefault(ssos => ssos.Binding == ProtocolBindings.HttpRedirect);

                            if (redirectBinding != null)
                            {
                                configuration.TokenEndpoint = redirectBinding.Location.OriginalString;
                            }

                            var keys = idpssod.Keys
                                       .Where(key => key.KeyInfo != null && (key.Use == KeyType.Signing || key.Use == KeyType.Unspecified))
                                       .SelectMany(key => key.KeyInfo.OfType <X509RawDataKeyIdentifierClause>())
                                       .Select(clause => new X509SecurityKey(new X509Certificate2(clause.GetX509RawData())));

                            foreach (var key in keys)
                            {
                                configuration.SigningKeys.Add(key);
                            }
                        }
                    }
                }

            return(configuration);
        }
예제 #14
0
        /// <summary>
        /// Retrieves a populated configuration given an address and a document retriever.
        /// </summary>
        /// <param name="address">Address of the discovery document.</param>
        /// <param name="retriever">The document retriever to use to read the discovery document.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        /// <remarks>If the activities are successfully sent, the task result contains
        /// a populated configuration.</remarks>
        public async Task <IDictionary <string, HashSet <string> > > GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancellationToken)
        {
            if (address == null)
            {
                throw new ArgumentNullException(nameof(address));
            }

            if (retriever == null)
            {
                throw new ArgumentNullException(nameof(retriever));
            }

            var jsonDocument = await retriever.GetDocumentAsync(address, cancellationToken).ConfigureAwait(false);

            var configurationRoot = JObject.Parse(jsonDocument);

            var keys = configurationRoot["keys"]?.Value <JArray>();

            if (keys == null)
            {
                return(new Dictionary <string, HashSet <string> >(0));
            }

            var results = new Dictionary <string, HashSet <string> >(keys.Count);

            foreach (var key in keys)
            {
                var keyId = key[AuthenticationConstants.KeyIdHeader]?.Value <string>();

                if (keyId != null
                    &&
                    !results.ContainsKey(keyId))
                {
                    var endorsementsToken = key["endorsements"];

                    if (endorsementsToken != null)
                    {
                        results.Add(keyId, new HashSet <string>(endorsementsToken.Values <string>()));
                    }
                }
            }

            return(results);
        }
        /// <summary>
        /// Retrieves a populated <see cref="WsFederationConfiguration"/> given an address and an <see cref="IDocumentRetriever"/>.
        /// </summary>
        /// <param name="address">address of the metadata document.</param>
        /// <param name="retriever">the <see cref="IDocumentRetriever"/> to use to read the metadata document</param>
        /// <param name="cancel"><see cref="CancellationToken"/>.</param>
        /// <returns>A populated <see cref="WsFederationConfiguration"/> instance.</returns>
        /// <exception cref="ArgumentNullException">if <paramref name="address"/> is null or empty.</exception>
        /// <exception cref="ArgumentNullException">if <paramref name="retriever"/> is null.</exception>
        public static async Task <WsFederationConfiguration> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrEmpty(address))
            {
                throw LogArgumentNullException(nameof(address));
            }

            if (retriever == null)
            {
                throw LogArgumentNullException(nameof(retriever));
            }

            string document = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            using (var metaDataReader = XmlReader.Create(new StringReader(document), SafeSettings))
            {
                return((new WsFederationMetadataSerializer()).ReadMetadata(metaDataReader));
            }
        }
예제 #16
0
        /// <summary>Retrieves a populated configuration given an address and an <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/>.</summary>
        /// <param name="address">Address of the discovery document.</param>
        /// <param name="retriever">The <see cref="T:Microsoft.IdentityModel.Protocols.IDocumentRetriever"/> to use to read the discovery document.</param>
        /// <param name="cancel">A cancellation token that can be used by other objects or threads to receive notice of cancellation. <see cref="T:System.Threading.CancellationToken"/>.</param>
        /// <returns>
        /// A <see cref="Task{IssuerMetadata}"/> that, when completed, returns <see cref="IssuerMetadata"/> from the configuration.
        /// </returns>
        /// <exception cref="ArgumentNullException">address - Azure AD Issuer metadata address URL is required
        /// or retriever - No metadata document retriever is provided.</exception>
        public async Task <IssuerMetadata> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrEmpty(address))
            {
                throw new ArgumentNullException(nameof(address), IDWebErrorMessage.IssuerMetadataUrlIsRequired);
            }

            if (retriever == null)
            {
                throw new ArgumentNullException(nameof(retriever), IDWebErrorMessage.NoMetadataDocumentRetrieverProvided);
            }

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            };

            string doc = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);

            return(JsonSerializer.Deserialize <IssuerMetadata>(doc, options) !); // Note: The analyzer says Deserialize can return null, but the method comment says it just throws exceptions.
        }
        private async Task <MetadataBase> GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw new ArgumentNullException("address");
            }
            if (retriever == null)
            {
                throw new ArgumentNullException("retriever");
            }
            var str = await retriever.GetDocumentAsync(address, cancel);

            var document = str;

            str = null;

            using (XmlReader reader = XmlReader.Create(new StringReader(document), this._safeSettings))
            {
                var federationConfiguration = this._metadataSerialiser.Deserialise(reader);
                return(federationConfiguration);
            }
        }
예제 #18
0
        public async Task <OpenIdConnectConfiguration> GetConfigurationAsync(string address,
                                                                             IDocumentRetriever retriever, CancellationToken cancel)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw LogHelper.LogArgumentNullException(nameof(address));
            }
            if (retriever == null)
            {
                throw LogHelper.LogArgumentNullException(nameof(retriever));
            }

            string jwks = "";

            try {
                jwks = await retriever.GetDocumentAsync(address, cancel).ConfigureAwait(false);
            } catch (System.Exception ex) {
                System.Console.WriteLine("Error: {0}", ex);
            }

            // If the keyset comes from Vault, it'll be under the data element in the response blob.
            // If it's from the auth service, it'll be a normal keyset.
            var keysetWrapper = JsonConvert.DeserializeObject <JsonWebKeySetWrapper>(jwks);
            var keyset        = keysetWrapper?.Keys ?? JsonConvert.DeserializeObject <JsonWebKeySet>(jwks);

            var openIdConnectConfiguration =
                new OpenIdConnectConfiguration {
                JsonWebKeySet = keyset
            };

            foreach (var signingKey in openIdConnectConfiguration.JsonWebKeySet.GetSigningKeys())
            {
                openIdConnectConfiguration.SigningKeys.Add(signingKey);
            }
            return(openIdConnectConfiguration);
        }
        /// <summary>
        /// Invoked to post configure a TOptions instance.
        /// </summary>
        /// <param name="name">The name of the options instance being configured.</param>
        /// <param name="options">The options instance to configure.</param>
        /// <exception cref="InvalidOperationException">
        /// Service Provider certificate could not be found.
        /// or
        /// Multiple Service Provider certificates were found, must only provide one.
        /// or
        /// The certificate for this service providerhas no private key.
        /// or
        /// The MetadataAddress must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.
        /// </exception>
        public void PostConfigure(string name, Saml2Options options)
        {
            options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;

            if (string.IsNullOrEmpty(options.SignOutScheme))
            {
                options.SignOutScheme = options.SignInScheme;
            }

            if (options.StateDataFormat == null)
            {
                var dataProtector = options.DataProtectionProvider.CreateProtector(
                    typeof(Saml2Handler).FullName, name, "v1");
                options.StateDataFormat = new PropertiesDataFormat(dataProtector);
            }
            var request = _httpContextAccessor.HttpContext.Request;

            if (options.ServiceProvider.AssertionConsumerServices != null)
            {
                foreach (var assertionConsumerService in options.ServiceProvider.AssertionConsumerServices)
                {
                    if (string.IsNullOrEmpty(assertionConsumerService.Location))
                    {
                        assertionConsumerService.Location = request.Scheme + "://" + request.Host.Value + options.CallbackPath;
                    }
                    else
                    {
                        Uri  uriAppUrlResult;
                        bool appProductionURLresult = Uri.TryCreate(assertionConsumerService.Location, UriKind.Absolute, out uriAppUrlResult) &&
                                                      (uriAppUrlResult.Scheme == Uri.UriSchemeHttp || uriAppUrlResult.Scheme == Uri.UriSchemeHttps);
                        if (!appProductionURLresult)
                        {
                            throw new InvalidOperationException("AssertionConsumerService is not a valid URL.");
                        }
                    }
                }
            }

            if (options.ServiceProvider.SingleLogoutServices != null)
            {
                foreach (var singleLogoutService in options.ServiceProvider.SingleLogoutServices)
                {
                    if (string.IsNullOrEmpty(singleLogoutService.Location))
                    {
                        singleLogoutService.Location = request.Scheme + "://" + request.Host.Value + options.SignOutPath;
                    }
                    else
                    {
                        Uri  uriAppUrlResult;
                        bool appProductionURLresult = Uri.TryCreate(singleLogoutService.Location, UriKind.Absolute, out uriAppUrlResult) &&
                                                      (uriAppUrlResult.Scheme == Uri.UriSchemeHttp || uriAppUrlResult.Scheme == Uri.UriSchemeHttps);
                        if (!appProductionURLresult)
                        {
                            throw new InvalidOperationException("SingleLogoutService is not a valid URL.");
                        }
                    }
                }
            }
            if (options.ServiceProvider.X509Certificate2 != null)
            {
                options.hasCertificate = true;
            }

            if (options.Backchannel == null)
            {
                options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
                options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("ASP.NET SamlCore handler");
                options.Backchannel.Timeout = options.BackchannelTimeout;
                options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
            }

            if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience))
            {
                options.TokenValidationParameters.ValidAudience = options.ServiceProvider.EntityId;
            }

            if (options.ConfigurationManager == null)
            {
                if (options.Configuration != null)
                {
                    options.ConfigurationManager = new StaticConfigurationManager <Saml2Configuration>(options.Configuration);
                }
                else if (!string.IsNullOrEmpty(options.MetadataAddress))
                {
                    Uri  uriResult;
                    bool result = Uri.TryCreate(options.MetadataAddress, UriKind.Absolute, out uriResult) &&
                                  (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);

                    if (result)
                    {
                        if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                        {
                            throw new InvalidOperationException("The MetadataAddress must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
                        }
                        options.ConfigurationManager = new ConfigurationManager <Saml2Configuration>(options.MetadataAddress, new Saml2ConfigurationRetriever(),
                                                                                                     new HttpDocumentRetriever(options.Backchannel)
                        {
                            RequireHttps = options.RequireHttpsMetadata
                        });
                    }
                    else
                    {
                        _idoc.GetDocumentAsync(options.MetadataAddress, default(CancellationToken));
                        options.ConfigurationManager = new ConfigurationManager <Saml2Configuration>(options.MetadataAddress, new Saml2ConfigurationRetriever(), _idoc);
                    }
                }
            }
            if (options.CreateMetadataFile)
            {
                //delete the metadata.xml if exists
                string[] xmlList = Directory.GetFiles(options.DefaultMetadataFolderLocation, "*.xml");
                foreach (string f in xmlList)
                {
                    if (f == options.DefaultMetadataFolderLocation + "\\" + options.DefaultMetadataFileName + ".xml")
                    {
                        File.Delete(f);
                    }
                }

                var xmlTemplate = options.ToXmlMetadata();

                //create xml document from string
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlTemplate);
                xmlDoc.PreserveWhitespace = true;
                xmlDoc.Save(options.DefaultMetadataFolderLocation + "\\" + options.DefaultMetadataFileName + ".xml");
            }
        }
        /// <summary>
        /// Invoked to post configure a TOptions instance.
        /// </summary>
        /// <param name="name">The name of the options instance being configured.</param>
        /// <param name="options">The options instance to configure.</param>
        /// <exception cref="InvalidOperationException">
        /// Service Provider certificate could not be found.
        /// or
        /// Multiple Service Provider certificates were found, must only provide one.
        /// or
        /// The certificate for this service providerhas no private key.
        /// or
        /// The MetadataAddress must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.
        /// </exception>
        public void PostConfigure(string name, Saml2Options options)
        {
            options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;

            if (string.IsNullOrEmpty(options.SignOutScheme))
            {
                options.SignOutScheme = options.SignInScheme;
            }

            if (options.StateDataFormat == null)
            {
                var dataProtector = options.DataProtectionProvider.CreateProtector(
                    typeof(Saml2Handler).FullName, name, "v1");
                options.StateDataFormat = new PropertiesDataFormat(dataProtector);
            }
            var request = _httpContextAccessor.HttpContext.Request;

            if (options.ServiceProvider.AssertionConsumerServices != null)
            {
                foreach (var assertionConsumerService in options.ServiceProvider.AssertionConsumerServices)
                {
                    if (string.IsNullOrEmpty(assertionConsumerService.Location))
                    {
                        assertionConsumerService.Location = request.Scheme + "://" + request.Host.Value + options.CallbackPath;
                    }
                    else
                    {
                        Uri  uriAppUrlResult;
                        bool appProductionURLresult = Uri.TryCreate(assertionConsumerService.Location, UriKind.Absolute, out uriAppUrlResult) &&
                                                      (uriAppUrlResult.Scheme == Uri.UriSchemeHttp || uriAppUrlResult.Scheme == Uri.UriSchemeHttps);
                        if (!appProductionURLresult)
                        {
                            throw new InvalidOperationException("AssertionConsumerService is not a valid URL.");
                        }
                    }
                }
            }

            if (options.ServiceProvider.SingleLogoutServices != null)
            {
                foreach (var singleLogoutService in options.ServiceProvider.SingleLogoutServices)
                {
                    if (string.IsNullOrEmpty(singleLogoutService.Location))
                    {
                        singleLogoutService.Location = request.Scheme + "://" + request.Host.Value + options.SignOutPath;
                    }
                    else
                    {
                        Uri  uriAppUrlResult;
                        bool appProductionURLresult = Uri.TryCreate(singleLogoutService.Location, UriKind.Absolute, out uriAppUrlResult) &&
                                                      (uriAppUrlResult.Scheme == Uri.UriSchemeHttp || uriAppUrlResult.Scheme == Uri.UriSchemeHttps);
                        if (!appProductionURLresult)
                        {
                            throw new InvalidOperationException("SingleLogoutService is not a valid URL.");
                        }
                    }
                }
            }
            if (options.ServiceProvider.X509Certificate2 != null)
            {
                options.hasCertificate = true;
            }

            if (options.Backchannel == null)
            {
                options.Backchannel = new HttpClient(options.BackchannelHttpHandler ?? new HttpClientHandler());
                options.Backchannel.DefaultRequestHeaders.UserAgent.ParseAdd("ASP.NET SamlCore handler");
                options.Backchannel.Timeout = options.BackchannelTimeout;
                options.Backchannel.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
            }

            if (string.IsNullOrEmpty(options.TokenValidationParameters.ValidAudience))
            {
                options.TokenValidationParameters.ValidAudience = options.ServiceProvider.EntityId;
            }

            if (options.ConfigurationManager == null)
            {
                if (options.Configuration != null)
                {
                    options.ConfigurationManager = new StaticConfigurationManager <Saml2Configuration>(options.Configuration);
                }
                else if (!string.IsNullOrEmpty(options.MetadataAddress))
                {
                    Uri  uriResult;
                    bool result = Uri.TryCreate(options.MetadataAddress, UriKind.Absolute, out uriResult) &&
                                  (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);

                    if (result)
                    {
                        if (options.RequireHttpsMetadata && !options.MetadataAddress.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                        {
                            throw new InvalidOperationException("The MetadataAddress must use HTTPS unless disabled for development by setting RequireHttpsMetadata=false.");
                        }
                        options.ConfigurationManager = new ConfigurationManager <Saml2Configuration>(options.MetadataAddress, new Saml2ConfigurationRetriever(),
                                                                                                     new HttpDocumentRetriever(options.Backchannel)
                        {
                            RequireHttps = options.RequireHttpsMetadata
                        });
                    }
                    else
                    {
                        _idoc.GetDocumentAsync(options.MetadataAddress, default(CancellationToken));
                        options.ConfigurationManager = new ConfigurationManager <Saml2Configuration>(options.MetadataAddress, new Saml2ConfigurationRetriever(), _idoc);
                    }
                }
            }
            if (options.CreateMetadataFile)
            {
                //delete the metadata.xml if exists
                string[] xmlList = Directory.GetFiles(options.DefaultMetadataFolderLocation, "*.xml");
                foreach (string f in xmlList)
                {
                    if (f == options.DefaultMetadataFolderLocation + "\\" + options.DefaultMetadataFileName + ".xml")
                    {
                        File.Delete(f);
                    }
                }

                //overwrite or create metadata.xml if set to true
                IndexedEndpointType[] AssertionConsumerService = options.ServiceProvider.AssertionConsumerServices;
                EndpointType[]        SingleLogoutServices     = options.ServiceProvider.SingleLogoutServices;

                Metadata.KeyDescriptorType[] KeyDescriptor = null;
                if (options.hasCertificate)
                {
                    KeyDescriptor = new Metadata.KeyDescriptorType[]
                    {
                        new Metadata.KeyDescriptorType()
                        {
                            useSpecified = true,
                            use          = KeyTypes.signing,
                            KeyInfo      = new Metadata.KeyInfoType()
                            {
                                ItemsElementName = new [] { Metadata.ItemsChoiceType2.X509Data },
                                Items            = new Metadata.X509DataType[]
                                {
                                    new Metadata.X509DataType()
                                    {
                                        Items            = new object[] { options.ServiceProvider.X509Certificate2.GetRawCertData() },
                                        ItemsElementName = new [] { Metadata.ItemsChoiceType.X509Certificate }
                                    }
                                }
                            }
                        },
                        new Metadata.KeyDescriptorType()
                        {
                            useSpecified = true,
                            use          = KeyTypes.encryption,
                            KeyInfo      = new Metadata.KeyInfoType()
                            {
                                ItemsElementName = new [] { Metadata.ItemsChoiceType2.X509Data },
                                Items            = new Metadata.X509DataType[]
                                {
                                    new Metadata.X509DataType()
                                    {
                                        Items            = new object[] { options.ServiceProvider.X509Certificate2.GetRawCertData() },
                                        ItemsElementName = new [] { Metadata.ItemsChoiceType.X509Certificate }
                                    }
                                }
                            }
                        }
                    };
                }
                var entityDescriptor = new EntityDescriptorType()
                {
                    entityID = options.ServiceProvider.EntityId,
                    Items    = new object[]
                    {
                        new SPSSODescriptorType()
                        {
                            NameIDFormat = new [] { Saml2Constants.NameIDFormats.Email },
                            protocolSupportEnumeration    = new [] { Saml2Constants.Namespaces.Protocol },
                            AuthnRequestsSignedSpecified  = true,
                            AuthnRequestsSigned           = options.hasCertificate,
                            WantAssertionsSignedSpecified = true,
                            WantAssertionsSigned          = options.WantAssertionsSigned,
                            KeyDescriptor       = KeyDescriptor,
                            SingleLogoutService = SingleLogoutServices,

                            AssertionConsumerService  = AssertionConsumerService,
                            AttributeConsumingService = new AttributeConsumingServiceType[]
                            {
                                new AttributeConsumingServiceType
                                {
                                    ServiceName = new localizedNameType[]
                                    {
                                        new localizedNameType()
                                        {
                                            Value = options.ServiceProvider.ServiceName,
                                            lang  = options.ServiceProvider.Language
                                        }
                                    },
                                    ServiceDescription = new localizedNameType[]
                                    {
                                        new localizedNameType()
                                        {
                                            Value = options.ServiceProvider.ServiceDescription,
                                            lang  = options.ServiceProvider.Language
                                        }
                                    },
                                    index              = 0,
                                    isDefault          = true,
                                    isDefaultSpecified = true,
                                    RequestedAttribute = new RequestedAttributeType[] //this doesnt work with ADFS
                                    {
                                        new RequestedAttributeType
                                        {
                                            isRequired          = true,
                                            isRequiredSpecified = true,
                                            NameFormat          = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
                                            Name         = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
                                            FriendlyName = "Name"
                                        },
                                        new RequestedAttributeType
                                        {
                                            isRequired          = true,
                                            isRequiredSpecified = true,
                                            NameFormat          = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
                                            Name         = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
                                            FriendlyName = "E-Mail-Adresses"
                                        },
                                        new RequestedAttributeType
                                        {
                                            isRequired          = true,
                                            isRequiredSpecified = true,
                                            NameFormat          = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
                                            Name         = "nameid:persistent",
                                            FriendlyName = "mail"
                                        }
                                    }
                                }
                            },
                            Organization = new OrganizationType()
                            {
                                OrganizationDisplayName = new localizedNameType[] {
                                    new localizedNameType
                                    {
                                        lang  = options.ServiceProvider.Language,
                                        Value = options.ServiceProvider.OrganizationDisplayName
                                    },
                                },
                                OrganizationName = new localizedNameType[] {
                                    new localizedNameType
                                    {
                                        lang  = options.ServiceProvider.Language,
                                        Value = options.ServiceProvider.OrganizationName
                                    },
                                },
                                OrganizationURL = new localizedURIType[] {
                                    new localizedURIType
                                    {
                                        lang  = options.ServiceProvider.Language,
                                        Value = options.ServiceProvider.OrganizationURL
                                    },
                                },
                            },
                        },
                    },
                    ContactPerson = new ContactType[]
                    {
                        new ContactType()
                        {
                            Company         = options.ServiceProvider.ContactPerson.Company,
                            GivenName       = options.ServiceProvider.ContactPerson.GivenName,
                            EmailAddress    = options.ServiceProvider.ContactPerson.EmailAddress,
                            contactType     = options.ServiceProvider.ContactPerson.contactType,
                            TelephoneNumber = options.ServiceProvider.ContactPerson.TelephoneNumber
                        }
                    }
                };

                //generate the sp metadata xml file
                string        xmlTemplate   = string.Empty;
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(EntityDescriptorType));
                using (MemoryStream memStm = new MemoryStream())
                {
                    xmlSerializer.Serialize(memStm, entityDescriptor);
                    memStm.Position = 0;
                    xmlTemplate     = new StreamReader(memStm).ReadToEnd();
                }

                //create xml document from string
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlTemplate);
                xmlDoc.PreserveWhitespace = true;
                xmlDoc.Save(options.DefaultMetadataFolderLocation + "\\" + options.DefaultMetadataFileName + ".xml");
            }
        }
        private async Task <OpenIdConnectConfiguration> GetAsync(string address, IDocumentRetriever retriever,
                                                                 CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                throw LogHelper.LogArgumentNullException(nameof(address));
            }

            if (retriever == null)
            {
                throw LogHelper.LogArgumentNullException(nameof(retriever));
            }

            var cacheObject = await _jdtRedisCacheProvider.TryGetStringValue(address, CancellationToken.None);

            var str1 = cacheObject.IsValid ? cacheObject.Response : string.Empty;

            if (string.IsNullOrEmpty(str1))
            {
                str1 = await retriever.GetDocumentAsync(address, cancellationToken).ConfigureAwait(false);

                await _jdtRedisCacheProvider.SetString(address, str1,
                                                       cancellationToken);
            }

            var contractResolver = new DefaultContractResolver {
                NamingStrategy = new SnakeCaseNamingStrategy()
            };
            var settings = new JsonSerializerSettings {
                ContractResolver = contractResolver
            };

            var openIdConnectConfiguration =
                JsonConvert.DeserializeObject <OpenIdConnectConfiguration>(str1, settings);

            if (openIdConnectConfiguration == null)
            {
                throw new InvalidOperationException("Unable to deserialize the OpenIdConnectConfiguration");
            }

            if (string.IsNullOrEmpty(openIdConnectConfiguration.JwksUri))
            {
                return(openIdConnectConfiguration);
            }

            _logger.Verbose("IDX21812: Retrieving json web keys from: '{JkwsUri}'",
                            (object)openIdConnectConfiguration.JwksUri);

            var jsonCacheObject = await _jdtRedisCacheProvider.TryGetStringValue(
                openIdConnectConfiguration.JwksUri, cancellationToken);

            var str2 = jsonCacheObject.IsValid ? jsonCacheObject.Response : string.Empty;

            if (string.IsNullOrEmpty(str2))
            {
                str2 = await retriever.GetDocumentAsync(openIdConnectConfiguration.JwksUri, cancellationToken)
                       .ConfigureAwait(false);

                await _jdtRedisCacheProvider.SetString(
                    openIdConnectConfiguration.JwksUri, str2, cancellationToken);
            }

            _logger.Verbose("IDX21813: Deserializing json web keys: '{JwksUri}'",
                            (object)openIdConnectConfiguration.JwksUri);

            openIdConnectConfiguration.JsonWebKeySet = JsonConvert.DeserializeObject <JsonWebKeySet>(str2);

            foreach (var signingKey in openIdConnectConfiguration.JsonWebKeySet
                     .GetSigningKeys())
            {
                openIdConnectConfiguration.SigningKeys.Add(signingKey);
            }

            return(openIdConnectConfiguration);
        }