Ejemplo n.º 1
0
        public void Various_urls_should_normalize(string input)
        {
            var result = DiscoveryEndpoint.ParseUrl(input);

            // test parse URL logic
            result.Url.Should().Be("https://server:123/.well-known/openid-configuration");
            result.Authority.Should().Be("https://server:123");
        }
Ejemplo n.º 2
0
        public void Custom_path_is_supported(string input, string documentPath)
        {
            var result = DiscoveryEndpoint.ParseUrl(input, documentPath);

            // test parse URL logic
            result.Url.Should().Be("https://server:123/strange-location/openid-configuration");
            result.Authority.Should().Be("https://server:123");
        }
        internal void ConfigureJwtBearer(JwtBearerOptions jwtOptions)
        {
            jwtOptions.Authority                  = Authority;
            jwtOptions.RequireHttpsMetadata       = RequireHttpsMetadata;
            jwtOptions.BackchannelTimeout         = BackChannelTimeouts;
            jwtOptions.RefreshOnIssuerKeyNotFound = true;
            jwtOptions.SaveToken                  = SaveToken;

            jwtOptions.Events = new JwtBearerEvents
            {
                OnMessageReceived = e =>
                {
                    e.Token = InternalTokenRetriever(e.Request);
                    return(JwtBearerEvents.MessageReceived(e));
                },

                OnTokenValidated       = e => JwtBearerEvents.TokenValidated(e),
                OnAuthenticationFailed = e => JwtBearerEvents.AuthenticationFailed(e),
                OnChallenge            = e => JwtBearerEvents.Challenge(e)
            };

            if (DiscoveryDocumentRefreshInterval.HasValue)
            {
                var parsedUrl = DiscoveryEndpoint.ParseUrl(Authority);

                var httpClient = new HttpClient(JwtBackChannelHandler ?? new HttpClientHandler())
                {
                    Timeout = BackChannelTimeouts,
                    MaxResponseContentBufferSize = 1024 * 1024 * 10 // 10 MB
                };

                var manager = new ConfigurationManager <OpenIdConnectConfiguration>(
                    parsedUrl.Url,
                    new OpenIdConnectConfigurationRetriever(),
                    new HttpDocumentRetriever(httpClient)
                {
                    RequireHttps = RequireHttpsMetadata
                })
                {
                    AutomaticRefreshInterval = DiscoveryDocumentRefreshInterval.Value
                };

                jwtOptions.ConfigurationManager = manager;
            }

            if (JwtBackChannelHandler != null)
            {
                jwtOptions.BackchannelHttpHandler = JwtBackChannelHandler;
            }

            // if API name is set, do a strict audience check for
            if (!string.IsNullOrWhiteSpace(ApiName) && !LegacyAudienceValidation)
            {
                jwtOptions.Audience = ApiName;
            }
            else
            {
                // no audience validation, rely on scope checks only
                jwtOptions.TokenValidationParameters.ValidateAudience = false;
            }

            jwtOptions.TokenValidationParameters.NameClaimType = NameClaimType;
            jwtOptions.TokenValidationParameters.RoleClaimType = RoleClaimType;

            if (JwtValidationClockSkew.HasValue)
            {
                jwtOptions.TokenValidationParameters.ClockSkew = JwtValidationClockSkew.Value;
            }

            if (InboundJwtClaimTypeMap != null)
            {
                var handler = new JwtSecurityTokenHandler
                {
                    InboundClaimTypeMap = InboundJwtClaimTypeMap
                };

                jwtOptions.SecurityTokenValidators.Clear();
                jwtOptions.SecurityTokenValidators.Add(handler);
            }
        }
Ejemplo n.º 4
0
    /// <summary>
    /// Sends a discovery document request
    /// </summary>
    /// <param name="client">The client.</param>
    /// <param name="request">The request.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns></returns>
    public static async Task <DiscoveryDocumentResponse> GetDiscoveryDocumentAsync(this HttpMessageInvoker client, DiscoveryDocumentRequest request, CancellationToken cancellationToken = default)
    {
        string address;

        if (request.Address.IsPresent())
        {
            address = request.Address;
        }
        else if (client is HttpClient httpClient)
        {
            address = httpClient.BaseAddress.AbsoluteUri;
        }
        else
        {
            throw new ArgumentException("An address is required.");
        }

        var parsed    = DiscoveryEndpoint.ParseUrl(address, request.Policy.DiscoveryDocumentPath);
        var authority = parsed.Authority;
        var url       = parsed.Url;

        if (request.Policy.Authority.IsMissing())
        {
            request.Policy.Authority = authority;
        }

        var jwkUrl = "";

        if (!DiscoveryEndpoint.IsSecureScheme(new Uri(url), request.Policy))
        {
            return(ProtocolResponse.FromException <DiscoveryDocumentResponse>(new InvalidOperationException("HTTPS required"), $"Error connecting to {url}. HTTPS required."));
        }

        try
        {
            var clone = request.Clone();

            clone.Method = HttpMethod.Get;
            clone.Prepare();

            clone.RequestUri = new Uri(url);

            var response = await client.SendAsync(clone, cancellationToken).ConfigureAwait();

            string responseContent = null;

            if (response.Content != null)
            {
                responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait();
            }

            if (!response.IsSuccessStatusCode)
            {
                return(await ProtocolResponse.FromHttpResponseAsync <DiscoveryDocumentResponse>(response, $"Error connecting to {url}: {response.ReasonPhrase}").ConfigureAwait());
            }

            var disco = await ProtocolResponse.FromHttpResponseAsync <DiscoveryDocumentResponse>(response, request.Policy).ConfigureAwait();

            if (disco.IsError)
            {
                return(disco);
            }

            try
            {
                jwkUrl = disco.JwksUri;
                if (jwkUrl != null)
                {
                    var jwkClone = request.Clone <JsonWebKeySetRequest>();
                    jwkClone.Method  = HttpMethod.Get;
                    jwkClone.Address = jwkUrl;
                    jwkClone.Prepare();

                    var jwkResponse = await client.GetJsonWebKeySetAsync(jwkClone, cancellationToken).ConfigureAwait();

                    if (jwkResponse.IsError)
                    {
                        return(await ProtocolResponse.FromHttpResponseAsync <DiscoveryDocumentResponse>(jwkResponse.HttpResponse, $"Error connecting to {jwkUrl}: {jwkResponse.HttpErrorReason}").ConfigureAwait());
                    }

                    disco.KeySet = jwkResponse.KeySet;
                }

                return(disco);
            }
            catch (Exception ex)
            {
                return(ProtocolResponse.FromException <DiscoveryDocumentResponse>(ex, $"Error connecting to {jwkUrl}. {ex.Message}."));
            }
        }
        catch (Exception ex)
        {
            return(ProtocolResponse.FromException <DiscoveryDocumentResponse>(ex, $"Error connecting to {url}. {ex.Message}."));
        }
    }
        public void Malformed_authority_url_should_throw(string input)
        {
            Action act = () => DiscoveryEndpoint.ParseUrl(input);

            act.Should().Throw <InvalidOperationException>().Where(e => e.Message.Equals("Malformed URL"));
        }