Пример #1
0
        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;
 }
Пример #3
0
 public UserService(
     IReferenceDataRepository referenceDataRepository,
     IUserRepository userRepository,
     IOptionsMonitor <AdfsOptions> options)
 {
     _referenceDataRepository = referenceDataRepository;
     _userRepository          = userRepository;
     _config = options.CurrentValue;
 }
Пример #4
0
        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.")));
                    }
                };
            });
        }
Пример #5
0
        /// <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));
        }
Пример #6
0
        /// <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);
        });
    }