public AdDirectoryService(LdapSettings settings, AdfsOptions adOptions) { // TODO NTBS-1672 run a DNS query that does the foollwing: // dig +short -t srv _ldap._tcp.SP4-0JG._sites.dc._msdcs.phe.gov.uk // dig +short -t srv _ldap._tcp.dc._msdcs.caduceus.local // and pick a dc to request _settings = settings; _adOptions = adOptions; _connection = new LdapConnection(); Log.Information($"Connecting to AD: {settings.AdAddressName}:{settings.Port}"); _connection.Connect(settings.AdAddressName, settings.Port); var withOrWithout = string.IsNullOrEmpty(settings.Password) ? "without" : "with"; Log.Information($"Binding: {settings.UserIdentifier} {withOrWithout} a password"); _connection.Bind(GetDistinguishedName(settings.UserIdentifier), settings.Password); if (_connection.Bound) { Log.Information("Bind completed"); } else { var bindingException = new ApplicationException("Binding to LDAP failed"); Log.Error(bindingException, "Aborting LDAP connection"); throw bindingException; } }
public AdDirectoryServiceServiceFactory( IOptions <LdapSettings> LdapSettings, IOptions <AdfsOptions> adfsOptions) { this._ldapSettings = LdapSettings.Value; this._adfsOptions = adfsOptions.Value; }
public UserService( IReferenceDataRepository referenceDataRepository, IUserRepository userRepository, IOptionsMonitor <AdfsOptions> options) { _referenceDataRepository = referenceDataRepository; _userRepository = userRepository; _config = options.CurrentValue; }
private static void SetupHttpBasicAuth(IServiceCollection services, IConfigurationSection httpBasicAuthConfig, IConfigurationSection adfsConfig) { var adfsOptions = new AdfsOptions(); adfsConfig.Bind(adfsOptions); services .AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme) .AddBasicAuthentication( options => { options.Realm = "Basic Realm"; options.Events = new BasicAuthenticationEvents { OnValidatePrincipal = context => { if ((context.UserName.ToLower() == httpBasicAuthConfig["Username"].ToLower()) && (context.Password == httpBasicAuthConfig["Password"])) { string groupAdmin = adfsOptions.AdminUserGroup; string groupDev = adfsOptions.DevGroup ?? adfsOptions.NationalTeamAdGroup; var claims = new List <Claim> { new Claim(ClaimTypes.Name, context.UserName, context.Options.ClaimsIssuer), new Claim(ClaimTypes.Role, adfsOptions.BaseUserGroup, ClaimValueTypes.String), new Claim(ClaimTypes.Role, groupAdmin, ClaimValueTypes.String), new Claim(ClaimTypes.Role, groupDev, ClaimValueTypes.String) }; var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity( claims, BasicAuthenticationDefaults.AuthenticationScheme)); var ticket = new AuthenticationTicket( claimsPrincipal, new AuthenticationProperties(), BasicAuthenticationDefaults.AuthenticationScheme); context.Principal = claimsPrincipal; // Returning the ticket, though it doesn't seem to be used (at least in the initial // logic) - hence setting the Principal above, too. return(Task.FromResult(AuthenticateResult.Success(ticket))); } return(Task.FromResult(AuthenticateResult.Fail("Authentication really failed."))); } }; }); }
/// <summary> /// Adds the <see cref="AdfsMiddleware"/> middleware to the specified <see cref="IAppBuilder"/>, which enables Adfs 3.0's OAuth2 capabilities. /// </summary> /// <param name="app">The <see cref="IAppBuilder"/> to add the middleware to.</param> /// <param name="configureOptions">An action delegate to configure the provided <see cref="AdfsOptions"/>.</param> /// <returns>A reference to this instance after the operation has completed.</returns> public static IAppBuilder UseAdfsOAuth2Authentication(this IAppBuilder app, Action <AdfsOptions> configureOptions) { if (app == null) { throw new ArgumentNullException("app"); } var options = new AdfsOptions(); if (configureOptions != null) { configureOptions(options); } return(app.UseAdfsOAuth2Authentication(options)); }
/// <summary> /// Authenticate users using Adfs 3.0's OAuth2 endpoints /// </summary> /// <param name="app">The <see cref="IAppBuilder"/> passed to the configuration method</param> /// <param name="options">Middleware configuration options</param> /// <returns>The updated <see cref="IAppBuilder"/></returns> public static IAppBuilder UseAdfsOAuth2Authentication(this IAppBuilder app, AdfsOptions options) { if (app == null) { throw new ArgumentNullException("app"); } if (options == null) { throw new ArgumentNullException("options"); } app.Use(typeof(AdfsMiddleware), app, options); return(app); }
public static void ConfigureServices(WebApplicationBuilder builder) { var services = builder.Services; // This was helpful for identifying issues with ADFS login - but shouldn't be on usually // IdentityModelEventSource.ShowPII = true; services.Configure <ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.All; options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); // Configuration services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddHsts(options => { options.MaxAge = TimeSpan.FromSeconds(63072000); // Two years }); var adConfig = builder.Configuration.GetSection("AdOptions"); var adfsConfig = builder.Configuration.GetSection("AdfsOptions"); var azureAdConfig = builder.Configuration.GetSection("AzureAdOptions"); var applicationInsightsConfig = builder.Configuration.GetSection("ApplicationInsightsOptions"); var adOptions = new AdOptions(); var adfsOptions = new AdfsOptions(); var azureAdOptions = new AzureAdOptions(); var applicationInsightsOptions = new ApplicationInsightsOptions(); adConfig.Bind(adOptions); adfsConfig.Bind(adfsOptions); azureAdConfig.Bind(azureAdOptions); applicationInsightsConfig.Bind(applicationInsightsOptions); services.Configure <AdOptions>(adConfig); services.Configure <AdfsOptions>(adfsConfig); services.Configure <AzureAdOptions>(azureAdConfig); services.Configure <LdapSettings>(builder.Configuration.GetSection("LdapSettings")); services.Configure <MigrationConfig>(builder.Configuration.GetSection("MigrationConfig")); // Plugin services if (builder.Environment.IsEnvironment("CI")) { services.AddDistributedMemoryCache(); } else { services.AddDistributedSqlServerCache(options => { options.ConnectionString = builder.Configuration.GetConnectionString("ntbsContext"); options.SchemaName = "dbo"; options.TableName = "SessionState"; }); } services.AddSession(options => { options.Cookie.IsEssential = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; }); // select authentication method var httpBasicAuthConfig = builder.Configuration.GetSection("HttpBasicAuth"); var basicAuthEnabled = httpBasicAuthConfig.GetValue("Enabled", false); var azureAdAuthEnabled = azureAdOptions.Enabled; Log.Information($"Basic Auth Enabled: {basicAuthEnabled}"); Log.Information($"Azure Ad Auth Enabled: {azureAdAuthEnabled}"); var baseUserGroupRole = adOptions.BaseUserGroup; if (adOptions.UseDummyAuth) { UseDummyAuth(services); } else if (basicAuthEnabled) { UseHttpBasicAuth(services, httpBasicAuthConfig, adOptions); } else if (azureAdAuthEnabled) { UseAzureAdAuthentication(services, adOptions, azureAdOptions); } else { UseAdfsAuthentication(services, adOptions, adfsOptions); } services.AddControllersWithViews(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .RequireRole(baseUserGroupRole) .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }).AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); services.AddRazorPages(options => { options.Conventions.AllowAnonymousToPage("/Account/AccessDenied"); options.Conventions.AllowAnonymousToPage("/Logout"); options.Conventions.AllowAnonymousToPage("/PostLogout"); }); services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => { policy.RequireRole(builder.Configuration.GetSection("AdOptions")["AdminUserGroup"]); }); }); SetupHangfire(builder); var auditDbConnectionString = builder.Configuration.GetConnectionString("auditContext"); if (!builder.Environment.IsEnvironment("CI")) { // DB Contexts services.AddDbContext <NtbsContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("ntbsContext")) ); services.AddSingleton <NtbsContextDesignTimeFactory>(); services.AddDbContext <AuditDatabaseContext>(options => options.UseSqlServer(auditDbConnectionString) ); // Add a DbContext for Data Protection key storage services.AddDbContext <KeysContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("keysContext"))); services.AddDataProtection().PersistKeysToDbContext <KeysContext>(); } // Repositories services.AddScoped <INotificationRepository, NotificationRepository>(); services.AddScoped <IReferenceDataRepository, ReferenceDataRepository>(); services.AddScoped <IAlertRepository, AlertRepository>(); services.AddScoped <INotificationImportRepository, NotificationImportRepository>(); services.AddScoped <IMigratedNotificationsMarker, MigratedNotificationsMarker>(); services.AddScoped <INotificationImportHelper, NotificationImportHelper>(); services.AddScoped <IMigrationRepository, MigrationRepository>(); services.AddScoped <IItemRepository <ManualTestResult>, TestResultRepository>(); services.AddScoped <IItemRepository <SocialContextVenue>, SocialContextVenueRepository>(); services.AddScoped <IItemRepository <SocialContextAddress>, SocialContextAddressRepository>(); services.AddScoped <ITreatmentEventRepository, TreatmentEventRepository>(); services.AddScoped <IItemRepository <MBovisExposureToKnownCase>, MBovisExposureToKnownCaseRepository>(); services .AddScoped <IItemRepository <MBovisUnpasteurisedMilkConsumption>, MBovisUnpasteurisedMilkConsumptionRepository>(); services.AddScoped <IItemRepository <MBovisOccupationExposure>, MBovisOccupationExposureRepository>(); services.AddScoped <IItemRepository <MBovisAnimalExposure>, MBovisAnimalExposureRepository>(); services.AddScoped <IUserRepository, UserRepository>(); services.AddScoped <IDataQualityRepository, DataQualityRepository>(); services.AddScoped <IDrugResistanceProfileRepository, DrugResistanceProfileRepository>(); // Services services.AddScoped <INotificationService, NotificationService>(); services.AddScoped <IAlertService, AlertService>(); services.AddScoped <INotificationMapper, NotificationMapper>(); services.AddScoped <IImportLogger, ImportLogger>(); services.AddScoped <INotificationImportService, NotificationImportService>(); services.AddScoped <IImportValidator, ImportValidator>(); services.AddScoped <ISearchService, SearchService>(); services.AddScoped <IAuditService, AuditService>(); services.AddScoped <INotificationChangesService, NotificationChangesService>(); services.AddScoped <IUserService, UserService>(); services.AddScoped <IPostcodeService, PostcodeService>(); services.AddScoped <ntbs_service.Services.IAuthorizationService, AuthorizationService>(); services.AddScoped <ILegacySearchService, LegacySearchService>(); services.AddScoped <IAdDirectoryServiceFactory, AdDirectoryServiceFactory>(); services.AddScoped <IEnhancedSurveillanceAlertsService, EnhancedSurveillanceAlertsService>(); services.AddScoped <IUserSearchService, UserSearchService>(); services.AddScoped <IServiceDirectoryService, ServiceDirectoryService>(); services.AddScoped <IClusterImportService, ClusterImportService>(); services.AddScoped <ISpecimenImportService, SpecimenImportService>(); services.AddScoped <ICaseManagerImportService, CaseManagerImportService>(); services.AddScoped <IAdUserService, AdUserService>(); services.AddScoped <IExternalLinksService, ExternalLinksService>(); services.AddScoped <ITreatmentEventMapper, TreatmentEventMapper>(); services.AddScoped <IUserHelper, UserHelper>(); services.AddScoped <ILogService, LogService>(); services.AddScoped <ITableCountsRepository, TableCountsRepository>(); services.AddScoped <IExternalStoredProcedureRepository, ExternalStoredProcedureRepository>(); AddAuditService(builder, auditDbConnectionString); AddReferenceLabResultServices(builder); AddNotificationClusterRepository(builder); AddReportingServices(builder); AddMicrosoftGraphServices(services, azureAdOptions); AddAdImportService(builder, azureAdOptions); AddApplicationInsightsMonitoring(services, applicationInsightsOptions); }
private static void UseAdfsAuthentication(IServiceCollection services, AdOptions adOptions, AdfsOptions adfsOptions) { var authSetup = services .AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { options.CallbackPath = "/Index"; options.SkipUnrecognizedRequests = true; options.MetadataAddress = adfsOptions.AdfsUrl + "/FederationMetadata/2007-06/FederationMetadata.xml"; options.Wtrealm = adfsOptions.Wtrealm; options.CorrelationCookie.SameSite = SameSiteMode.None; options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always; /* * Below event handler is to prevent stale logins from showing a 500 error screen, instead to force * back to the landing page - and cause a re-challenge or continue if already authenticated. * https://community.auth0.com/t/asp-net-core-2-intermittent-correlation-failed-errors/11918/14 */ options.Events.OnRemoteFailure += context => { if (context.Failure.Message == "Correlation failed.") { context.HandleResponse(); context.Response.Redirect("/"); } return(Task.CompletedTask); }; options.Events.OnSecurityTokenValidated += async context => { var username = context.Principal.Username(); if (username != null) { var userService = context.HttpContext.RequestServices.GetRequiredService <IUserService>(); await userService.RecordUserLoginAsync(username); } }; }) .AddCookie(options => { options.ForwardAuthenticate = null; options.SlidingExpiration = false; options.ExpireTimeSpan = TimeSpan.FromMinutes(adOptions.MaxSessionCookieLifetimeInMinutes); }); }