Beispiel #1
0
        //TODO: Need to follow more of this for http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/ dealing with AudienceStores

        //another interesting one https://blog.jayway.com/2014/09/25/securing-asp-net-web-api-endpoints-using-owin-oauth-2-0-and-claims/

        /// <summary>
        /// Configures Umbraco to issue and process authentication tokens
        /// </summary>
        /// <param name="app"></param>
        /// <param name="authServerProviderOptions"></param>
        /// <remarks>
        /// This is a very simple implementation of token authentication, the expiry below is for a single day and with
        /// this implementation there is no way to force expire tokens on the server however given the code below and the additional
        /// callbacks that can be registered for the BackOfficeAuthServerProvider these types of things could be implemented. Additionally the
        /// BackOfficeAuthServerProvider could be overridden to include this functionality instead of coding the logic into the callbacks.
        /// </remarks>
        /// <example>
        ///
        /// An example of using this implementation is to use the UmbracoStandardOwinSetup and execute this extension method as follows:
        ///
        /// <![CDATA[
        ///
        ///   public override void Configuration(IAppBuilder app)
        ///   {
        ///       //ensure the default options are configured
        ///       base.Configuration(app);
        ///
        ///       //configure token auth
        ///       app.UseUmbracoBackOfficeTokenAuth();
        ///   }
        ///
        /// ]]>
        ///
        /// Then be sure to read the details in UmbracoStandardOwinSetup on how to configure Owin to startup using it.
        /// </example>
        public static void UseUmbracoTokenAuthentication(this IAppBuilder app, UmbracoAuthorizationServerProviderOptions authServerProviderOptions = null)
        {
            authServerProviderOptions = authServerProviderOptions ?? new UmbracoAuthorizationServerProviderOptions();

            //if a secret is supplied then
            var base64Key = Convert.ToBase64String(
                Encoding.UTF8.GetBytes(
                    authServerProviderOptions.Secret));

            var tokenProvider = new SymmetricKeyIssuerSecurityTokenProvider(
                AuthorizationPolicies.UmbracoRestApiIssuer,
                base64Key);

            var oAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                //generally you wouldn't allow this unless on SSL!
                AllowInsecureHttp         = authServerProviderOptions.AllowInsecureHttp,
                TokenEndpointPath         = new PathString(authServerProviderOptions.AuthEndpoint),
                AuthenticationType        = AuthorizationPolicies.UmbracoRestApiTokenAuthenticationType,
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new UmbracoAuthorizationServerProvider(authServerProviderOptions)
            };

            oAuthServerOptions.AccessTokenFormat = new JwtFormatWriter(
                oAuthServerOptions,
                tokenProvider.Issuer,
                authServerProviderOptions.Audience,
                base64Key);

            // Token Generation
            app.UseOAuthAuthorizationServer(oAuthServerOptions);
            app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
            {
                AllowedAudiences             = new[] { authServerProviderOptions.Audience },
                IssuerSecurityTokenProviders = new[] { tokenProvider },

                Provider = new OAuthBearerAuthenticationProvider
                {
                    OnApplyChallenge   = context => { return(Task.FromResult(0)); },
                    OnRequestToken     = context => { return(Task.FromResult(0)); },
                    OnValidateIdentity = context =>
                    {
                        //ensure that the rest api claim is added to the ticket if everything is validated
                        if (context.IsValidated)
                        {
                            context.Ticket.Identity.AddClaim(new Claim(AuthorizationPolicies.UmbracoRestApiClaimType, "true", ClaimValueTypes.Boolean, AuthorizationPolicies.UmbracoRestApiIssuer));
                        }
                        return(Task.FromResult(0));
                    }
                }
            });
        }
        public async Task Get_Token()
        {
            var startup = new TestStartup(
                //This will be invoked before the controller is created so we can modify these mocked services,
                (testServices) =>
            {
            });

            var authServerOptions = new UmbracoAuthorizationServerProviderOptions
            {
                Secret            = "abcdefghijklmnopqrstuvwxyz12345678909876543210",
                Audience          = "test",
                AllowInsecureHttp = true
            };

            using (var server = TestServer.Create(app =>
            {
                ConfigureUserManager(app, new ClaimsIdentity(new[] { new Claim("test", "test") }), startup.ApplicationContext);
                app.UseUmbracoTokenAuthentication(authServerOptions);
                var httpConfig = startup.UseTestWebApiConfiguration(app);
                app.UseUmbracoRestApi(startup.ApplicationContext, new UmbracoRestApiOptions
                {
                    //customize the authz policies, in this case we want to allow everything
                    CustomAuthorizationPolicyCallback = (policyName, defaultPolicy) => (builder => builder.RequireAssertion(context => true))
                });
                app.UseWebApi(httpConfig);
            }))
            {
                var request = new HttpRequestMessage
                {
                    RequestUri = new Uri($"http://testserver{authServerOptions.AuthEndpoint}"),
                    Method     = HttpMethod.Post,
                    Content    = new StringContent(
                        "grant_type=password&username=YOURUSERNAME&password=YOURPASSWORD",
                        Encoding.UTF8,
                        "application/x-www-form-urlencoded")
                };

                //add the origin so Cors kicks in!
                request.Headers.Add("Origin", "http://localhost:12061");
                Console.WriteLine(request);
                var result = await server.HttpClient.SendAsync(request);

                Console.WriteLine(result);

                var json  = await((StreamContent)result.Content).ReadAsStringAsync();
                var djson = JsonConvert.DeserializeObject <JObject>(json);
                Console.Write(JsonConvert.SerializeObject(djson, Formatting.Indented));

                Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);

                Assert.IsTrue(result.Headers.Contains("Access-Control-Allow-Origin"));
                var acao = result.Headers.GetValues("Access-Control-Allow-Origin");
                Assert.AreEqual(1, acao.Count());

                //looks like the mvc cors default is to allow the request domain instea of *
                Assert.AreEqual("http://localhost:12061", acao.First());

                Assert.IsNotNull(djson["access_token"].Value <string>());
                Assert.AreEqual("bearer", djson["token_type"].Value <string>());
                Assert.IsNotNull(djson["expires_in"].Value <string>());
            }
        }
        public async Task Use_Token()
        {
            var startup = new TestStartup(
                //This will be invoked before the controller is created so we can modify these mocked services,
                (testServices) =>
            {
            });

            var authServerOptions = new UmbracoAuthorizationServerProviderOptions
            {
                Secret            = "abcdefghijklmnopqrstuvwxyz12345678909876543210",
                Audience          = "test",
                AllowInsecureHttp = true
            };

            using (var server = TestServer.Create(app =>
            {
                ConfigureUserManager(app,
                                     //For published content we can have a normal ClaimsIdentity
                                     new ClaimsIdentity(new[]
                {
                    new Claim(AuthorizationPolicies.UmbracoRestApiClaimType, "true", ClaimValueTypes.Boolean, AuthorizationPolicies.UmbracoRestApiIssuer),

                    new Claim(ClaimTypes.Locality, "en-US", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(ClaimTypes.GivenName, "Admin", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(ClaimTypes.Name, "*****@*****.**", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(ClaimTypes.NameIdentifier, "0", ClaimValueTypes.Integer, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(Constants.Security.AllowedApplicationsClaimType, "content", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(Constants.Security.StartContentNodeIdClaimType, "[-1]", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                    new Claim(Constants.Security.StartMediaNodeIdClaimType, "[-1]", ClaimValueTypes.String, AuthorizationPolicies.UmbracoRestApiIssuer),
                }), startup.ApplicationContext);

                app.UseUmbracoTokenAuthentication(authServerOptions);
                var httpConfig = startup.UseTestWebApiConfiguration(app);
                app.UseUmbracoRestApi(startup.ApplicationContext, new UmbracoRestApiOptions
                {
                    //customize the authz policies, in this case we want to allow everything
                    CustomAuthorizationPolicyCallback = (policyName, defaultPolicy) => (builder => builder.RequireAssertion(context => true))
                });
                app.UseWebApi(httpConfig);
            }))
            {
                var tokenRequest = new HttpRequestMessage
                {
                    RequestUri = new Uri($"http://testserver{authServerOptions.AuthEndpoint}"),
                    Method     = HttpMethod.Post,
                    Content    = new StringContent(
                        "grant_type=password&username=YOURUSERNAME&password=YOURPASSWORD",
                        Encoding.UTF8,
                        "application/x-www-form-urlencoded")
                };

                //add the origin so Cors kicks in!
                tokenRequest.Headers.Add("Origin", "http://localhost:12061");
                Console.WriteLine(tokenRequest);
                var result = await server.HttpClient.SendAsync(tokenRequest);

                Console.WriteLine(result);
                var json  = await((StreamContent)result.Content).ReadAsStringAsync();
                var djson = JsonConvert.DeserializeObject <JObject>(json);
                Console.Write(JsonConvert.SerializeObject(djson, Formatting.Indented));
                Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
                var token = djson["access_token"].Value <string>();


                //Now we can use the token

                var accessRequest = new HttpRequestMessage
                {
                    RequestUri = new Uri($"http://testserver/umbraco/rest/v1/{RouteConstants.ContentSegment}"),
                    Method     = HttpMethod.Get,
                    Headers    = { Authorization = new AuthenticationHeaderValue("Bearer", token) }
                };

                accessRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/hal+json"));
                accessRequest.Headers.Add("Access-Control-Request-Headers", "accept, authorization");
                accessRequest.Headers.Add("Access-Control-Request-Method", "GET");
                accessRequest.Headers.Add("Origin", "http://localhost:12061");
                accessRequest.Headers.Add("Referer", "http://localhost:12061/browser.html");

                Console.WriteLine(accessRequest);
                result = await server.HttpClient.SendAsync(accessRequest);

                Console.WriteLine(result);

                json = await((StreamContent)result.Content).ReadAsStringAsync();
                Console.Write(JsonConvert.SerializeObject(JsonConvert.DeserializeObject(json), Formatting.Indented));

                Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
            }
        }