コード例 #1
0
    public void HandlesNonAmbiguousAndValidTimeWhenSchedulingJobs()
    {
        DateTime ambiguousDateTime = DateTime.Parse("11/01/2020 12:30:00");

        Assert.That(ScheduledBackgroundJobBootstrapper.MakeUtcCronTime(ambiguousDateTime.Year, ambiguousDateTime.Month, ambiguousDateTime.Day, ambiguousDateTime.Hour, ambiguousDateTime.Minute), Is.EqualTo(DateTime.Parse("11/01/2020 20:30:00")),
                    "Given an non-ambiguous and valid time, time remains the same local time before converting to UTC");
    }
コード例 #2
0
    public void HandlesinvalidDaylightSavingsTimeWhenSchedulingJobs()
    {
        DateTime invalidDateTime = DateTime.Parse("03/08/2020 02:15:00");

        Assert.That(TimeZoneInfo.Local.IsInvalidTime(invalidDateTime), "This test requires an invalid time.");
        Assert.That(ScheduledBackgroundJobBootstrapper.MakeUtcCronTime(invalidDateTime.Year, invalidDateTime.Month, invalidDateTime.Day, invalidDateTime.Hour, invalidDateTime.Minute), Is.EqualTo(DateTime.Parse("03/08/2020 10:16:00")),
                    "Given an invalid time, move the local time ahead 1 hour and 1 minute before converting to UTC");
    }
コード例 #3
0
    public void HandlesAmbiguousDaylightSavingsTimeWhenSchedulingJobs()
    {
        DateTime ambiguousDateTime = DateTime.Parse("11/01/2020 01:15:00");

        Assert.That(TimeZoneInfo.Local.IsAmbiguousTime(ambiguousDateTime), "This test requires an ambiguous time.");
        Assert.That(ScheduledBackgroundJobBootstrapper.MakeUtcCronTime(ambiguousDateTime.Year, ambiguousDateTime.Month, ambiguousDateTime.Day, ambiguousDateTime.Hour, ambiguousDateTime.Minute), Is.EqualTo(DateTime.Parse("11/01/2020 10:16:00")),
                    "Given an ambiguous time, move the local time ahead 1 hour and 1 minute before converting to UTC");
    }
コード例 #4
0
 /// <summary>
 /// Function required by <see cref="OwinStartupAttribute"/>
 /// </summary>
 public void Configuration(IAppBuilder app)
 {
     ConfigureHttpsProtocolForOutboundWebClientConnections();
     ConfigureApplicationAuthorization(app);
     ScheduledBackgroundJobBootstrapper.ConfigureHangfireAndScheduledBackgroundJobs(app);
 }
コード例 #5
0
ファイル: Startup.cs プロジェクト: sitkatech/neptune
        /// <summary>
        /// Function required by <see cref="OwinStartupAttribute"/>
        /// </summary>
        public void Configuration(IAppBuilder app)
        {
            SitkaHttpApplication.Logger.Info("Owin Startup");

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Cookies",
                CookieDomain       = CookieDomain,
                CookieManager      = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager(),
                CookieName         = $"{NeptuneWebConfiguration.KeystoneOpenIDClientId}_{NeptuneWebConfiguration.NeptuneEnvironment.NeptuneEnvironmentType}"
            });

            //Needed (at least in development) to allow Neptune to talk to upgraded keystone
            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

            //Most of the new openID for mvc pieces came from here https://www.scottbrady91.com/ASPNET/Refreshing-your-Legacy-ASPNET-IdentityServer-Client-Applications
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId              = NeptuneWebConfiguration.KeystoneOpenIDClientId,
                Authority             = NeptuneWebConfiguration.KeystoneOpenIDUrl,
                RedirectUri           = SitkaRoute <AccountController> .BuildAbsoluteUrlHttpsFromExpression(c => c.LogOn(), NeptuneWebConfiguration.CanonicalHostNameRoot), // this has to match the keystone client redirect uri
                PostLogoutRedirectUri = $"https://{NeptuneWebConfiguration.CanonicalHostNameRoot}/",                                                                        // OpenID is super picky about this; url must match what Keystone has EXACTLY (Trailing slash and all)
                ResponseType          = "code",
                Scope                      = "openid profile offline_access keystone",
                UseTokenLifetime           = false,
                SignInAsAuthenticationType = "Cookies",
                //ClientSecret = NeptuneWebConfiguration.KeystoneOpenIDClientSecret,
                CallbackPath = new PathString("/Account/LogOn"),

                RequireHttpsMetadata = false,
                RedeemCode           = true,
                SaveTokens           = true,
                ResponseMode         = "query",

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = (context) =>
                    {
                        if ((context.Exception.Message.StartsWith("OICE_20004") || context.Exception.Message.Contains("IDX10311")))
                        {
                            context.SkipToNextMiddleware();
                            return(Task.FromResult(0));
                        }

                        return(Task.FromResult(0));
                    },
                    SecurityTokenValidated = n =>
                    {
                        var claimsIdentity = n.AuthenticationTicket.Identity;
                        claimsIdentity.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

                        if (n.ProtocolMessage.Code != null)
                        {
                            claimsIdentity.AddClaim(new Claim("code", n.ProtocolMessage.Code));
                        }

                        if (n.ProtocolMessage.AccessToken != null)
                        {
                            claimsIdentity.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
                        }

                        //map name claim to default name type
                        claimsIdentity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", claimsIdentity.FindFirst(KeystoneOpenIDClaimTypes.Name).Value.ToString()));

                        if (claimsIdentity.IsAuthenticated) // we have a token and we can determine the person.
                        {
                            KeystoneOpenIDUtilities.OpenIDClaimHandler(SyncLocalAccountStore, claimsIdentity);
                        }

                        return(Task.FromResult(0));
                    },
                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Authentication)
                        {
                            // generate code verifier and code challenge
                            var codeVerifier = CryptoRandom.CreateUniqueId(32);

                            string codeChallenge;
                            using (var sha256 = SHA256.Create())
                            {
                                var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                                codeChallenge      = Base64Url.Encode(challengeBytes);
                            }

                            // set code_challenge parameter on authorization request
                            n.ProtocolMessage.SetParameter("code_challenge", codeChallenge);
                            n.ProtocolMessage.SetParameter("code_challenge_method", "S256");

                            // remember code verifier in cookie (adapted from OWIN nonce cookie)
                            // see: https://github.com/scottbrady91/Blog-Example-Classes/blob/master/AspNetFrameworkPkce/ScottBrady91.BlogExampleCode.AspNetPkce/Startup.cs#L85
                            RememberCodeVerifier(n, codeVerifier);
                        }

                        //https://identityserver.github.io/Documentation/docsv2/overview/mvcGettingStarted.html#adding-logout
                        if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect
                            .OpenIdConnectRequestType.Logout)
                        {
                            var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                            if (idTokenHint != null)
                            {
                                n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }
                        }

                        return(Task.CompletedTask);
                    },
                    AuthorizationCodeReceived = n =>
                    {
                        // get code verifier from cookie
                        // see: https://github.com/scottbrady91/Blog-Example-Classes/blob/master/AspNetFrameworkPkce/ScottBrady91.BlogExampleCode.AspNetPkce/Startup.cs#L102
                        var codeVerifier = RetrieveCodeVerifier(n);

                        // attach code_verifier on token request
                        n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier);

                        return(Task.CompletedTask);
                    }
                }
            });

            ScheduledBackgroundJobBootstrapper.ConfigureHangfireAndScheduledBackgroundJobs(app);
        }
コード例 #6
0
        /// <summary>
        ///     Function required by <see cref="OwinStartupAttribute" />
        /// </summary>
        public void Configuration(IAppBuilder app)
        {
            SitkaHttpApplication.Logger.Info("Owin Startup - Start Configuration");
            app.Use((ctx, next) =>
            {
                // Trying a lock here to prevent sporadic "Collection was modified; enumeration operation may not execute." error.
                lock (BranchBuildLock)
                {
                    var branch = app.New();
                    JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary <string, string>();

                    // Specify TLS 1.2 for Rest API calls
                    ServicePointManager.Expect100Continue = true;
                    ServicePointManager.SecurityProtocol  = SecurityProtocolType.Tls12;

                    var tenant = GetTenantFromUrl(ctx.Request);
                    HttpRequestStorage.Tenant = tenant;
                    if (!tenant.TenantEnabled)
                    {
                        throw new SitkaDisplayErrorException($"Tenant {tenant.TenantName} is disabled; cannot show site");
                    }

                    var canonicalHostNameForEnvironment = FirmaWebConfiguration.FirmaEnvironment.GetCanonicalHostNameForEnvironment(tenant);
                    var tenantAttributes   = MultiTenantHelpers.GetTenantAttributeFromCache();
                    var cookieSecureOption = FirmaWebConfiguration.RedirectToHttps
                        ? CookieSecureOption.Always
                        : CookieSecureOption.Never;
                    branch.UseCookieAuthentication(new CookieAuthenticationOptions
                    {
                        AuthenticationType = CookieAuthenticationType,
                        CookieManager      = new SystemWebChunkingCookieManager(),
                        CookieName         = ClaimsIdentityHelper.GetAuthenticationApplicationCookieName(tenant),
                        CookieSecure       = cookieSecureOption
                    });


                    switch (FirmaWebConfiguration.AuthenticationType)
                    {
                    case AuthenticationType.KeystoneAuth:
                        branch.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
                        {
                            Authority                  = FirmaWebConfiguration.KeystoneOpenIDUrl,
                            ResponseType               = "id_token token",
                            Scope                      = "openid all_claims keystone",
                            UseTokenLifetime           = false,
                            SignInAsAuthenticationType = CookieAuthenticationType,
                            CallbackPath               = new PathString("/Account/LogOn"),
                            ClientId                   = tenantAttributes.KeystoneOpenIDClientIdentifier,
                            ClientSecret               = tenantAttributes.KeystoneOpenIDClientSecret,
                            RedirectUri                =
                                $"https://{canonicalHostNameForEnvironment}/Account/LogOn", // this has to match the keystone client redirect uri
                            PostLogoutRedirectUri =
                                $"https://{canonicalHostNameForEnvironment}/",              // OpenID is super picky about this; url must match what Keystone has EXACTLY (Trailing slash and all)

                            Notifications = new OpenIdConnectAuthenticationNotifications
                            {
                                AuthenticationFailed = (context) =>
                                {
                                    SitkaHttpApplication.Logger.Info($"Owin Startup - Configuration - AuthenticationFailed AuthType:{FirmaWebConfiguration.AuthenticationType}");
                                    if ((context.Exception.Message.StartsWith("OICE_20004") ||
                                         context.Exception.Message.Contains("IDX10311")))
                                    {
                                        context.SkipToNextMiddleware();
                                        return(Task.FromResult(0));
                                    }

                                    return(Task.FromResult(0));
                                },
                                SecurityTokenValidated = n =>
                                {
                                    HttpRequestStorage.Tenant = GetTenantFromUrl(n.Request);
                                    SitkaHttpApplication.Logger.Info(
                                        $"In SecurityTokenValidated: TenantID {HttpRequestStorage.Tenant.TenantID}, Url: {n.Request.Uri.ToString()}, AuthType:{FirmaWebConfiguration.AuthenticationType}");

                                    var claimsIdentity = n.AuthenticationTicket.Identity;
                                    claimsIdentity.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

                                    if (n.ProtocolMessage.Code != null)
                                    {
                                        claimsIdentity.AddClaim(new Claim("code", n.ProtocolMessage.Code));
                                    }

                                    if (n.ProtocolMessage.AccessToken != null)
                                    {
                                        claimsIdentity.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
                                    }

                                    //map name claim to default name type
                                    claimsIdentity.AddClaim(new Claim(
                                                                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
                                                                claimsIdentity.FindFirst(KeystoneOpenIDClaimTypes.Name).Value.ToString()));

                                    if (claimsIdentity.IsAuthenticated)     // we have a token and we can determine the person.
                                    {
                                        KeystoneOpenIDUtilities.OpenIDClaimHandler(SyncLocalAccountStore, claimsIdentity);
                                    }

                                    return(Task.FromResult(0));
                                },
                                RedirectToIdentityProvider = n =>
                                {
                                    SitkaHttpApplication.Logger.Info($"Owin Startup - Configuration - RedirectToIdentityProvider AuthType:{FirmaWebConfiguration.AuthenticationType}, RequestType:{n.ProtocolMessage.RequestType}");
                                    //n.ProtocolMessage.RedirectUri = GetHomePage(); // dynamic home page for multiple subdomains
                                    //n.ProtocolMessage.PostLogoutRedirectUri = GetOuterPage(); // dynamic landing page for multiple subdomains
                                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                                    {
                                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                                        if (idTokenHint != null)
                                        {
                                            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                                        }
                                    }
                                    else if (n.ProtocolMessage.RequestType ==
                                             OpenIdConnectRequestType.AuthenticationRequest)
                                    {
                                        var httpContextBase = GetHttpContext(n);
                                        var referrer        = httpContextBase.Request.UrlReferrer;
                                        if (referrer != null && referrer.Host == canonicalHostNameForEnvironment)
                                        {
                                            n.Response.Cookies.Append("ReturnURL", referrer.PathAndQuery);
                                        }
                                    }

                                    return(Task.FromResult(0));
                                }
                            }
                        });
                        break;

                    case AuthenticationType.LocalAuth:
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }


                    // we have to do this per tenant so needs to belong here
                    branch.UseHangfireDashboard("/hangfire", new DashboardOptions
                    {
                        Authorization = new[] { new HangfireFirmaWebAuthorizationFilter() }
                    });
                    return(branch.Build()(ctx.Environment));
                }
            });

            ScheduledBackgroundJobBootstrapper.ConfigureHangfireAndScheduledBackgroundJobs(app);
        }