Exemple #1
0
        private void AddServices(IServiceCollection services)
        {
            services.AddRazorPages(o =>
            {
                o.Conventions
                .AuthorizeFolder("/", MsftAuthorizationPolicyName)
                .AllowAnonymousToPage("/Index")
                .AllowAnonymousToPage("/Status")
                .AllowAnonymousToPage("/Routes")
                .AllowAnonymousToPage("/Error");
                o.RootDirectory = "/Pages";
            });

            services.AddControllers()
            .AddGitHubWebHooks();

            services.AddApplicationInsightsTelemetry(Configuration.GetSection("ApplicationInsights").Bind);
            services.Configure <LoggerFilterOptions>(o =>
            {
                // This handler is added by 'AddApplicationInsightsTelemetry' above and hard limits
                // and reporting below "warning", which basically kills all logging
                // Remove it, we already configured the filters in Program.cs
                o.Rules.Remove(o.Rules.FirstOrDefault(r =>
                                                      r.ProviderName ==
                                                      "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider"));

                // These two categories log a lot of noise at "Information", let's raise them to warning
                o.Rules.Add(new LoggerFilterRule(null, "Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter", LogLevel.Warning, null));
                o.Rules.Add(new LoggerFilterRule(null, "Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter", LogLevel.Warning, null));
            });

            services.AddAuthentication("contextual")
            .AddPolicyScheme("contextual", "Contextual Scheme",
                             o => { o.ForwardDefaultSelector = context =>
                                    {
                                        if (context.Request.Path.StartsWithSegments("/api/webhooks"))
                                        {
                                            return("nothing");
                                        }
                                        if (context.Request.Path.StartsWithSegments("/api"))
                                        {
                                            return("github-token");
                                        }

                                        return(IdentityConstants.ApplicationScheme);
                                    }; })
            .AddGitHubOAuth(Configuration.GetSection("GitHubAuthentication"), GitHubScheme)
            .AddScheme <NothingOptions, NothingHandler>("nothing", o => { })
            .AddScheme <UserTokenOptions, GitHubUserTokenHandler>("github-token", o => { })
            .AddCookie(IdentityConstants.ApplicationScheme,
                       o =>
            {
                o.ExpireTimeSpan     = TimeSpan.FromMinutes(30);
                o.SlidingExpiration  = true;
                o.Cookie.IsEssential = true;
                o.LoginPath          = "/signin";
                o.LogoutPath         = "/signout";
                o.ReturnUrlParameter = "r";
                o.Events             = new CookieAuthenticationEvents
                {
                    OnValidatePrincipal = async ctx =>
                    {
                        GitHubClaimResolver resolver =
                            ctx.HttpContext.RequestServices.GetRequiredService <GitHubClaimResolver>();
                        ClaimsIdentity identity = ctx.Principal.Identities.FirstOrDefault();
                        identity?.AddClaims(await resolver.GetMembershipClaims(resolver.GetAccessToken(ctx.Principal)));
                    },
                };
            })
            .AddExternalCookie()
            ;
            services.AddAzureTableTokenStore(o => Configuration.GetSection("AzureTableTokenStore").Bind(o));
            services.AddAuthorization(
                options =>
            {
                options.AddPolicy(
                    MsftAuthorizationPolicyName,
                    policy =>
                {
                    policy.RequireAuthenticatedUser();
                    if (!Env.IsDevelopment())
                    {
                        policy.RequireRole(GitHubClaimResolver.GetTeamRole("dotnet", "dnceng"), GitHubClaimResolver.GetTeamRole("dotnet", "bots-high"));
                    }
                });
            });
            services.AddKustoIngest(options => Configuration.GetSection("Kusto").Bind(options));

            services.AddScoped <SimpleSigninMiddleware>();
            services.AddGitHubTokenProvider();
            services.AddSingleton <IInstallationLookup, InMemoryCacheInstallationLookup>();

            services.AddSingleton <ZenHubClient>();
            services.AddSingleton <IGitHubApplicationClientFactory, GitHubApplicationClientFactory>();
            services.AddSingleton <IGitHubClientFactory, GitHubClientFactory>();
            services.AddSingleton <ITimelineIssueTriage, TimelineIssueTriage>();
            services.AddSingleton <ExponentialRetry>();
            services.AddSingleton <ISystemClock, SystemClock>();
            services.AddSingleton <Microsoft.Extensions.Internal.ISystemClock, Microsoft.Extensions.Internal.SystemClock>();
            services.AddHttpClient();
            services.AddHealthReporting(
                b =>
            {
                b.AddLogging();
                b.AddAzureTable((o, p) => o.WriteSasUri = p.GetRequiredService <IConfiguration>()["HealthTableUri"]);
            });

            services.AddScoped <ITeamMentionForwarder, TeamMentionForwarder>();
        }
        private void AddServices(IServiceCollection services)
        {
            services.AddRazorPages(o =>
            {
                o.Conventions
                .AuthorizeFolder("/", MsftAuthorizationPolicyName)
                .AllowAnonymousToPage("/Index")
                .AllowAnonymousToPage("/Status")
                .AllowAnonymousToPage("/Error");
                o.RootDirectory = "/Pages";
            });

            services.AddControllers()
            .AddGitHubWebHooks();

            services.AddApplicationInsightsTelemetry(Configuration.GetSection("ApplicationInsights").Bind);
            services.Configure <LoggerFilterOptions>(o =>
            {
                // This handler is added by 'AddApplicationInsightsTelemetry' above and hard limits
                // and reporting below "warning", which basically kills all logging
                // Remove it, we already configured the filters in Program.cs
                o.Rules.Remove(o.Rules.FirstOrDefault(r =>
                                                      r.ProviderName ==
                                                      "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider"));
            });

            services.AddAuthentication("contextual")
            .AddPolicyScheme("contextual", "Contextual Scheme",
                             o => { o.ForwardDefaultSelector = context =>
                                    {
                                        if (context.Request.Path.StartsWithSegments("/api"))
                                        {
                                            return("github-token");
                                        }

                                        return(IdentityConstants.ApplicationScheme);
                                    }; })
            .AddGitHubOAuth(Configuration.GetSection("GitHubAuthentication"), GitHubScheme)
            .AddScheme <UserTokenOptions, GitHubUserTokenHandler>("github-token", o => { })
            .AddCookie(IdentityConstants.ApplicationScheme,
                       o =>
            {
                o.ExpireTimeSpan     = TimeSpan.FromDays(7);
                o.SlidingExpiration  = true;
                o.Cookie.IsEssential = true;
                o.LoginPath          = "/signin";
                o.LogoutPath         = "/signout";
                o.ReturnUrlParameter = "r";
                o.Events             = new CookieAuthenticationEvents
                {
                    OnValidatePrincipal = async ctx =>
                    {
                        GitHubClaimResolver resolver =
                            ctx.HttpContext.RequestServices.GetRequiredService <GitHubClaimResolver>();
                        ClaimsIdentity identity = ctx.Principal.Identities.FirstOrDefault();
                        identity?.AddClaims(await resolver.GetMembershipClaims(resolver.GetAccessToken(ctx.Principal)));
                    },
                };
            })
            .AddExternalCookie()
            ;
            services.AddAzureTableTokenStore(o => Configuration.GetSection("AzureTableTokenStore").Bind(o));
            services.AddAuthorization(
                options =>
            {
                options.AddPolicy(
                    MsftAuthorizationPolicyName,
                    policy =>
                {
                    policy.RequireAuthenticatedUser();
                    if (!Env.IsDevelopment())
                    {
                        policy.RequireRole(GitHubClaimResolver.GetTeamRole("dotnet", "dnceng"), GitHubClaimResolver.GetTeamRole("dotnet", "bots-high"));
                    }
                });
            });
            services.AddKustoIngest(options => Configuration.GetSection("Kusto").Bind(options));

            services.AddScoped <SimpleSigninMiddleware>();
            services.AddGitHubTokenProvider();
            services.AddSingleton <IInstallationLookup, InMemoryCacheInstallationLookup>();

            services.AddSingleton <ZenHubClient>();
            services.AddSingleton <IGitHubApplicationClientFactory, GitHubApplicationClientFactory>();
            services.AddSingleton <IGitHubClientFactory, GitHubClientFactory>();
        }
        private void ConfigureAuthServices(IServiceCollection services)
        {
            services.AddIdentity <ApplicationUser, IdentityRole <int> >(
                options => { options.Lockout.AllowedForNewUsers = false; })
            .AddEntityFrameworkStores <BuildAssetRegistryContext>();

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = options.DefaultChallengeScheme = options.DefaultScheme = "Contextual";
                options.DefaultSignInScheme       = IdentityConstants.ExternalScheme;
            })
            .AddPolicyScheme("Contextual", "Contextual",
                             policyOptions => { policyOptions.ForwardDefaultSelector = ctx => ctx.Request.Path.StartsWithSegments("/api") ? PersonalAccessTokenDefaults.AuthenticationScheme : IdentityConstants.ApplicationScheme; })
            .AddGitHubOAuth(Configuration.GetSection("GitHubAuthentication"), GitHubScheme)
            .AddPersonalAccessToken <ApplicationUser>(
                options =>
            {
                options.Events = new PersonalAccessTokenEvents <ApplicationUser>
                {
                    OnSetTokenHash = async context =>
                    {
                        var dbContext = context.HttpContext.RequestServices
                                        .GetRequiredService <BuildAssetRegistryContext>();
                        int userId = context.User.Id;
                        var token  = new ApplicationUserPersonalAccessToken
                        {
                            ApplicationUserId = userId,
                            Name    = context.Name,
                            Hash    = context.Hash,
                            Created = DateTimeOffset.UtcNow
                        };
                        await dbContext.Set <ApplicationUserPersonalAccessToken>().AddAsync(token);
                        await dbContext.SaveChangesAsync();

                        return(token.Id);
                    },
                    OnGetTokenHash = async context =>
                    {
                        var dbContext = context.HttpContext.RequestServices
                                        .GetRequiredService <BuildAssetRegistryContext>();
                        ApplicationUserPersonalAccessToken token = await dbContext
                                                                   .Set <ApplicationUserPersonalAccessToken>()
                                                                   .Where(t => t.Id == context.TokenId)
                                                                   .Include(t => t.ApplicationUser)
                                                                   .FirstOrDefaultAsync();
                        if (token != null)
                        {
                            context.Success(token.Hash, token.ApplicationUser);
                        }
                    },
                    OnValidatePrincipal = async context =>
                    {
                        ApplicationUser user = context.User;
                        var dbContext        = context.HttpContext.RequestServices
                                               .GetRequiredService <BuildAssetRegistryContext>();
                        var userManager = context.HttpContext.RequestServices
                                          .GetRequiredService <UserManager <ApplicationUser> >();
                        var signInManager = context.HttpContext.RequestServices
                                            .GetRequiredService <SignInManager <ApplicationUser> >();
                        var gitHubClaimResolver = context.HttpContext.RequestServices
                                                  .GetRequiredService <GitHubClaimResolver>();

                        await UpdateUserIfNeededAsync(user, dbContext, userManager, signInManager, gitHubClaimResolver);

                        ClaimsPrincipal principal = await signInManager.CreateUserPrincipalAsync(user);
                        context.ReplacePrincipal(principal);
                    }
                };
            });
            services.ConfigureExternalCookie(
                options =>
            {
                options.ExpireTimeSpan     = TimeSpan.FromMinutes(30);
                options.ReturnUrlParameter = "returnUrl";
                options.LoginPath          = "/Account/SignIn";
                options.Events             = new CookieAuthenticationEvents
                {
                    OnRedirectToLogin = ctx =>
                    {
                        if (ctx.Request.Path.StartsWithSegments("/api"))
                        {
                            ctx.Response.StatusCode = 401;
                            return(Task.CompletedTask);
                        }

                        ctx.Response.Redirect(ctx.RedirectUri);
                        return(Task.CompletedTask);
                    },
                    OnRedirectToAccessDenied = ctx =>
                    {
                        ctx.Response.StatusCode = 403;
                        return(Task.CompletedTask);
                    },
                };
            });
            services.ConfigureApplicationCookie(
                options =>
            {
                options.ExpireTimeSpan     = LoginCookieLifetime;
                options.SlidingExpiration  = true;
                options.ReturnUrlParameter = "returnUrl";
                options.LoginPath          = "/Account/SignIn";
                options.Events             = new CookieAuthenticationEvents
                {
                    OnSigningIn = async ctx =>
                    {
                        var dbContext = ctx.HttpContext.RequestServices
                                        .GetRequiredService <BuildAssetRegistryContext>();
                        var signInManager = ctx.HttpContext.RequestServices
                                            .GetRequiredService <SignInManager <ApplicationUser> >();
                        var userManager = ctx.HttpContext.RequestServices
                                          .GetRequiredService <UserManager <ApplicationUser> >();
                        ExternalLoginInfo info = await signInManager.GetExternalLoginInfoAsync();

                        var user = await userManager.GetUserAsync(ctx.Principal);
                        await UpdateUserTokenAsync(dbContext, userManager, user, info);

                        IdentityOptions identityOptions = ctx.HttpContext.RequestServices
                                                          .GetRequiredService <IOptions <IdentityOptions> >()
                                                          .Value;

                        // replace the ClaimsPrincipal we are about to serialize to the cookie with a reference
                        Claim claim = ctx.Principal.Claims.First(
                            c => c.Type == identityOptions.ClaimsIdentity.UserIdClaimType);
                        Claim[] claims = { claim };
                        var identity   = new ClaimsIdentity(claims, IdentityConstants.ApplicationScheme);
                        ctx.Principal  = new ClaimsPrincipal(identity);
                    },
                    OnValidatePrincipal = async ctx =>
                    {
                        var dbContext = ctx.HttpContext.RequestServices
                                        .GetRequiredService <BuildAssetRegistryContext>();
                        var userManager = ctx.HttpContext.RequestServices
                                          .GetRequiredService <UserManager <ApplicationUser> >();
                        var signInManager = ctx.HttpContext.RequestServices
                                            .GetRequiredService <SignInManager <ApplicationUser> >();
                        var gitHubClaimResolver = ctx.HttpContext.RequestServices
                                                  .GetRequiredService <GitHubClaimResolver>();

                        // extract the userId from the ClaimsPrincipal and read the user from the Db
                        ApplicationUser user = await userManager.GetUserAsync(ctx.Principal);
                        if (user == null)
                        {
                            ctx.RejectPrincipal();
                        }
                        else
                        {
                            await UpdateUserIfNeededAsync(user, dbContext, userManager, signInManager, gitHubClaimResolver);

                            ClaimsPrincipal principal = await signInManager.CreateUserPrincipalAsync(user);
                            ctx.ReplacePrincipal(principal);
                        }
                    }
                };
            });

            services.AddAuthorization(
                options =>
            {
                options.AddPolicy(
                    MsftAuthorizationPolicyName,
                    policy =>
                {
                    policy.RequireAuthenticatedUser();
                    if (!HostingEnvironment.IsDevelopment())
                    {
                        policy.RequireRole(GitHubClaimResolver.GetTeamRole("dotnet", "dnceng"), GitHubClaimResolver.GetTeamRole("dotnet", "arcade-contrib"));
                    }
                });
            });

            services.Configure <MvcOptions>(
                options =>
            {
                options.Conventions.Add(new DefaultAuthorizeActionModelConvention(MsftAuthorizationPolicyName));
            });
        }