public void Json_preferred_and_in_produces()
        {
            var result = ContentNegotiation.NegotiateAcceptHeader(ApplicationJson, DefaultProduces, logger: null);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(ApplicationJson);
        }
        public void StarStar_header_serves_first_produces()
        {
            var result = ContentNegotiation.NegotiateAcceptHeader(null, DefaultProduces, logger: null);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(DefaultProduces.First());
        }
        public void Form_urlencoded_is_valid_post_body_type()
        {
            var result = ContentNegotiation.DetectBodyType(FormUrlEncoded);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(FormUrlEncoded);
        }
        public void Json_is_valid_post_body_type()
        {
            var result = ContentNegotiation.DetectBodyType(ApplicationJson);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(ApplicationJson);
        }
        /// <summary>
        /// Redirects or responds to an unauthorized request.
        /// </summary>
        /// <remarks>Uses the Actions passed to the <see cref="RouteProtector"/> to execute this logic in a framework-agnostic way.</remarks>
        /// <param name="acceptHeader">The HTTP <c>Accept</c> header of this request.</param>
        /// <param name="requestPath">The OWIN request path of this request.</param>
        public void OnUnauthorized(string acceptHeader, string requestPath)
        {
            _deleteCookie(_configuration.Web.AccessTokenCookie);
            _deleteCookie(_configuration.Web.RefreshTokenCookie);

            var contentNegotiationResult = ContentNegotiation.NegotiateAcceptHeader(acceptHeader, _configuration.Web.Produces, _logger);

            bool isHtmlRequest = contentNegotiationResult.Success && contentNegotiationResult.ContentType == ContentType.Html;

            if (isHtmlRequest)
            {
                var redirectTokenBuilder = new StateTokenBuilder(_client, _configuration.Client.ApiKey)
                {
                    Path = requestPath
                };

                var loginUri = $"{_configuration.Web.Login.Uri}?{StringConstants.StateTokenName}={redirectTokenBuilder}";

                _setStatusCode(302);
                _redirect(loginUri);
            }
            else
            {
                _setStatusCode(401);
                _setHeader("WWW-Authenticate", $"Bearer realm=\"{_configuration.Application.Name}\"");
            }
        }
        public void Html_preferred_but_not_in_produces()
        {
            var producesOnlyJson = new string[] { ApplicationJson };

            var result = ContentNegotiation.NegotiateAcceptHeader("text/html", producesOnlyJson, logger: null);

            result.Success.Should().BeFalse();
        }
        public void Json_preferred_but_not_in_produces()
        {
            var producesOnlyHtml = new string[] { TextHtml };

            var result = ContentNegotiation.NegotiateAcceptHeader(ApplicationJson, producesOnlyHtml, logger: null);

            result.Success.Should().BeFalse();
        }
        public void Complex_scenario_1_is_html()
        {
            var headerValue = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            var result      = ContentNegotiation.NegotiateAcceptHeader(headerValue, DefaultProduces, logger: null);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(TextHtml);
        }
        public void Json_preferred_with_implicit_quality_factor()
        {
            var headerValue = "text/html; q=0.8, application/json";

            var result = ContentNegotiation.NegotiateAcceptHeader(headerValue, DefaultProduces, logger: null);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(ApplicationJson);
        }
        public void Html_preferred_with_higher_quality_factor()
        {
            var headerValue = "application/json; q=0.8, text/html;q=0.9";

            var result = ContentNegotiation.NegotiateAcceptHeader(headerValue, DefaultProduces, logger: null);

            result.Success.Should().BeTrue();
            result.ContentType.ToString().Should().Be(TextHtml);
        }
Beispiel #11
0
        public async Task <bool> InvokeAsync(IOwinEnvironment owinContext)
        {
            if (!_initialized)
            {
                throw new InvalidOperationException("Route has not been initialized.");
            }

            var acceptHeader             = owinContext.Request.Headers.GetString("Accept");
            var contentNegotiationResult = ContentNegotiation.NegotiateAcceptHeader(acceptHeader, _configuration.Web.Produces, _logger);

            if (!contentNegotiationResult.Success)
            {
                _logger.Trace($"Content negotiation failed for request {owinContext.Request.Path}. Skipping", nameof(InvokeAsync));
                return(false);
            }

            try
            {
                return(await HandleRequestAsync(owinContext, _client, contentNegotiationResult, owinContext.CancellationToken));
            }
            catch (ResourceException rex)
            {
                if (contentNegotiationResult.ContentType == ContentType.Json)
                {
                    // Sanitize Stormpath API errors
                    await Error.CreateFromApiError(owinContext, rex, owinContext.CancellationToken);

                    return(true);
                }
                else
                {
                    // todo handle framework errors
                    _logger.Error(rex, source: nameof(InvokeAsync));
                    throw;
                }
            }
            catch (Exception ex)
            {
                if (contentNegotiationResult.ContentType == ContentType.Json)
                {
                    // Sanitize framework-level errors
                    await Error.Create(owinContext, 400, ex.Message, owinContext.CancellationToken);

                    return(true);
                }
                else
                {
                    // todo handle framework errors
                    _logger.Error(ex, source: nameof(InvokeAsync));
                    throw;
                }
            }
        }
Beispiel #12
0
        public void TestContentNegotiation(string accept, string acceptable, bool result)
        {
            var headerDict = new HeaderDictionary();

            headerDict.Add(KeyValuePair.Create <string, StringValues>("Accept", accept));
            var mockRequest = new Mock <HttpRequest>();

            mockRequest.Setup(x => x.Headers).Returns(headerDict);

            var acc = ContentNegotiation.IsAcceptable(mockRequest.Object, acceptable);

            Assert.Equal(result, acc);
        }
Beispiel #13
0
        protected virtual Task <bool> PostAsync(IOwinEnvironment context, IClient client, ContentNegotiationResult contentNegotiationResult, CancellationToken cancellationToken)
        {
            var rawBodyContentType             = context.Request.Headers.GetString("Content-Type");
            var bodyContentTypeDetectionResult = ContentNegotiation.DetectBodyType(rawBodyContentType);

            if (!bodyContentTypeDetectionResult.Success)
            {
                throw new Exception($"The Content-Type '{rawBodyContentType}' is invalid.");
            }

            if (contentNegotiationResult.ContentType == ContentType.Json)
            {
                return(PostJsonAsync(context, client, bodyContentTypeDetectionResult.ContentType, cancellationToken));
            }

            if (contentNegotiationResult.ContentType == ContentType.Html)
            {
                return(PostHtmlAsync(context, client, bodyContentTypeDetectionResult.ContentType, cancellationToken));
            }

            // Do nothing and pass on to next middleware.
            return(Task.FromResult(false));
        }
        public void TextHtml_is_valid_post_body_type()
        {
            var result = ContentNegotiation.DetectBodyType(TextHtml);

            result.Success.Should().BeFalse();
        }
        public void TextPlain_is_valid_post_body_type()
        {
            var result = ContentNegotiation.DetectBodyType("text/plain");

            result.Success.Should().BeFalse();
        }
        public void Unsupported_header_fails()
        {
            var result = ContentNegotiation.NegotiateAcceptHeader("foo/bar", DefaultProduces, logger: null);

            result.Success.Should().BeFalse();
        }
 public static void Configure(HttpConfiguration httpConfiguration)
 {
     ContentNegotiation.Configure(httpConfiguration);
     Formatters.Configure(httpConfiguration);
     Routing.Configure(httpConfiguration);
 }
Beispiel #18
0
        protected override async Task <bool> PostAsync(IOwinEnvironment context, IClient client, ContentNegotiationResult contentNegotiationResult, CancellationToken cancellationToken)
        {
            Caching.AddDoNotCacheHeaders(context);

            var rawBodyContentType             = context.Request.Headers.GetString("Content-Type");
            var bodyContentTypeDetectionResult = ContentNegotiation.DetectBodyType(rawBodyContentType);

            var isValidContentType = bodyContentTypeDetectionResult.Success && bodyContentTypeDetectionResult.ContentType == ContentType.FormUrlEncoded;

            if (!isValidContentType)
            {
                await Error.Create <OauthInvalidRequest>(context, cancellationToken);

                return(true);
            }

            var requestBody = await context.Request.GetBodyAsStringAsync(cancellationToken);

            var formData = FormContentParser.Parse(requestBody, _logger);

            var grantType = formData.GetString("grant_type");

            if (string.IsNullOrEmpty(grantType))
            {
                await Error.Create <OauthInvalidRequest>(context, cancellationToken);

                return(true);
            }

            try
            {
                if (grantType.Equals("client_credentials", StringComparison.OrdinalIgnoreCase) &&
                    _configuration.Web.Oauth2.Client_Credentials.Enabled)
                {
                    await ExecuteClientCredentialsFlow(context, client, cancellationToken);

                    return(true);
                }

                if (grantType.Equals("password", StringComparison.OrdinalIgnoreCase) &&
                    _configuration.Web.Oauth2.Password.Enabled)
                {
                    var username = WebUtility.UrlDecode(formData.GetString("username"));
                    var password = WebUtility.UrlDecode(formData.GetString("password"));
                    await ExecutePasswordFlow(context, client, username, password, cancellationToken);

                    return(true);
                }

                if (grantType.Equals("refresh_token", StringComparison.OrdinalIgnoreCase) &&
                    _configuration.Web.Oauth2.Password.Enabled)
                {
                    var refreshToken = WebUtility.UrlDecode(formData.GetString("refresh_token"));
                    await ExecuteRefreshFlow(context, client, refreshToken, cancellationToken);

                    return(true);
                }
            }
            catch (ResourceException rex)
            {
                // Special handling of API errors for the OAuth route
                return(await Error.Create(context, new OauthError(rex.Message, rex.GetProperty("error")), cancellationToken));
            }

            return(await Error.Create <OauthUnsupportedGrant>(context, cancellationToken));
        }
Beispiel #19
0
        public static void AddJwtAuth(this IServiceCollection services, JwtSettings settings)
        {
            services.AddAuthentication(x => {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x => {
                x.RequireHttpsMetadata      = false;
                x.SaveToken                 = true;
                var jwtSharedKey            = System.Text.Encoding.UTF8.GetBytes(settings.Secret);
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = new SymmetricSecurityKey(jwtSharedKey),
                    ValidateIssuer           = true,
                    ValidIssuer      = settings.Issuer,
                    ValidateAudience = false
                };
                x.Events = new JwtBearerEvents
                {
                    OnChallenge = c =>
                    {
                        // if this is a browser request the auth-redirect process should be started
                        if (ContentNegotiation.IsAcceptable(c.Request, "text/html"))
                        {
                            return(Task.FromException(new LoginChallengeException("Browser login challenge start")));
                        }
                        return(Task.CompletedTask);
                    },
                    OnTokenValidated = c =>
                    {
                        if (c.Principal.Identity.IsAuthenticated)
                        {
                            // after authentication is performed ensure that the user
                            // has the necessary rights to access the resources
                            var user      = c.Principal.Get();
                            var principal = Authorization.IsAuthorized(c.Principal, settings.Claims, settings.Issuer);
                            if (principal == null)
                            {
                                return(Task.FromException(new AuthorizationException("Browser login challenge start")));
                            }
                            c.Principal = principal;
                            return(Task.FromResult(true));
                        }
                        return(Task.FromResult(false));
                    },
                    OnMessageReceived = c =>
                    {
                        if (string.IsNullOrEmpty(c.Token))
                        {
                            // the token was not received from the "expected location"
                            // fetch the token from the cookie instead!
                            var jwtCookiePayload = c.Request.Cookies[settings.CookieName];
                            if (!string.IsNullOrEmpty(jwtCookiePayload))
                            {
                                c.Token = jwtCookiePayload;
                            }
                        }

                        if (string.IsNullOrEmpty(c.Token))
                        {
                            return(Task.FromResult(false));
                        }

                        return(Task.FromResult(true));
                    }
                };
            });
        }