Example #1
0
#pragma warning disable CA1054 // Uri parameters should not be strings: We don't want Uri throwing exceptions here, we'd rather have invalid returnURls thrown around.
        public IntegrationsController(
            UserManager <WCAUser> userManager,
            IMediator mediator,
            IOptions <WCACoreSettings> settingsAccessor,
            IHttpClientFactory httpClientFactory,
            WCASignInManager signInManager,
            IClock clock,
            IExtendedPexaService pEXAService,
            IActionstepService actionstepService,
            IGlobalXService globalXService)
        {
            if (settingsAccessor is null)
            {
                throw new ArgumentNullException(nameof(settingsAccessor));
            }

            _userManager        = userManager;
            _mediator           = mediator;
            _httpClientFactory  = httpClientFactory;
            _actionstepSettings = settingsAccessor.Value.ActionstepSettings;
            _pexaSettings       = settingsAccessor.Value.PEXASettings;
            _globalXOptions     = settingsAccessor.Value.GlobalXOptions;
            _signInManager      = signInManager;
            _clock             = clock;
            _pEXAService       = pEXAService;
            _actionstepService = actionstepService;
            _globalXService    = globalXService;
        }
Example #2
0
        public void NoErrorsIfNoNameAvailable()
        {
            var claimsPrincipal = new ClaimsPrincipal();
            var user            = new WCAUser();

            WCASignInManager.SetFirstAndLastNameIfMissing(user, claimsPrincipal, NullLogger.Instance);
            Assert.Null(user.FirstName);
            Assert.Null(user.LastName);
        }
Example #3
0
        public void NameIsSetWithSingleWord()
        {
            const string firstName = "Name";
            var          identity  = new ClaimsIdentity();

            identity.AddClaim(new Claim(ActionstepJwtClaimTypes.Name, firstName));
            var claimsPrincipal = new ClaimsPrincipal(identity);
            var user            = new WCAUser();

            WCASignInManager.SetFirstAndLastNameIfMissing(user, claimsPrincipal, NullLogger.Instance);
            Assert.Equal(firstName, user.FirstName);
            Assert.Null(user.LastName);
        }
Example #4
0
        public void NameIsSetWithTwoThreeWords()
        {
            const string firstName  = "Firstname";
            const string middleName = "Middlename";
            const string lastName   = "Lastname";
            var          identity   = new ClaimsIdentity();

            identity.AddClaim(new Claim(ActionstepJwtClaimTypes.Name, $"{firstName} {middleName} {lastName}"));
            var claimsPrincipal = new ClaimsPrincipal(identity);
            var user            = new WCAUser();

            WCASignInManager.SetFirstAndLastNameIfMissing(user, claimsPrincipal, NullLogger.Instance);
            Assert.Equal(firstName, user.FirstName);
            Assert.Equal(lastName, user.LastName);
        }
Example #5
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplicationInsightsTelemetry(options => { options.DeveloperMode = _env.IsDevelopment(); });

            Trace.TraceInformation("WCA Startup: Entering ConfigureServices");

            services.AddFeatureManagement()
            .AddFeatureFilter <OrgKeyFilter>()
            .AddFeatureFilter <UserFilter>();
            services.AddOptions();
            services.AddLogging();
            services.Configure <AppSettings>(Configuration);
            services.Configure <ActionstepSettings>(Configuration.GetSection(nameof(WCACoreSettings)).GetSection(nameof(ActionstepSettings)));
            services.Configure <GlobalXOptions>(Configuration.GetSection(nameof(WCACoreSettings)).GetSection(nameof(GlobalXOptions)));
            appSettings = Configuration.Get <AppSettings>();

            services.AddWCACore(o =>
            {
                o.Configuration = Configuration;
                o.AutoMapperProfileAssemblyMarkerTypes.Add(typeof(WebAutoMapperProfile));
                o.IsDevelopment = _env.IsDevelopment();
            });

            AddWCADataProtection(services, appSettings.WCACoreSettings);

            services.AddScoped <WCADbContextTransactionFilter>();

            // Use a custom signin manager that automatically persists external login information
            services.AddScoped <SignInManager <WCAUser>, WCASignInManager>();
            services.AddScoped <WCASignInManager>();

            services.AddMvc(options =>
            {
                // Require authorization across the application
                var authorizePolicy = new AuthorizationPolicyBuilder(
                    IdentityConstants.ApplicationScheme,
                    "ActionstepJwt")
                                      .RequireAuthenticatedUser()
                                      .Build();
                options.Filters.Add(new AuthorizeFilter(authorizePolicy));

                options.Filters.Add <AutoValidateAntiforgeryTokenAttribute>();
                options.Filters.Add <ApiExceptionFilter>();
            })
            .AddNewtonsoftJson(options => {
                options.SerializerSettings.Converters.Add(new StringEnumConverter());
            })
            .AddFluentValidation(options =>
            {
                options.RegisterValidatorsFromAssemblyContaining <AddOrUpdateActionstepCredential.ValidatorCollection>();
            });

            // Swagger currently only to be used in development. Further work
            // is required to clean this up before we expose documentation publicly.
            services.AddSwaggerDocument(config =>
            {
                config.DocumentName = "v0.1";
                config.PostProcess  = document =>
                {
                    document.Info.Version     = "v0.1";
                    document.Info.Title       = "WorkCloud API";
                    document.Info.Description = "WorkCloud integrations and services.";
                    document.Info.Contact     = new NSwag.OpenApiContact
                    {
                        Name  = "WorkCloud Support",
                        Email = "*****@*****.**",
                        Url   = "https://www.workcloud.support/"
                    };
                };
            });

            services.AddRazorPages(options =>
            {
                options.Conventions.AuthorizeAreaFolder("Admin", "/", AllowAdminSitePolicyName);
            });

            // Add application services.
            // TODO: Refactor AccountController stuff to use SendGrid, or
            //       implement IEmailSender and ISmsSender
            // services.AddTransient<IEmailSender, AuthMessageSender>();
            // services.AddTransient<ISmsSender, AuthMessageSender>();

            // Configure authentication middleware
            services.AddIdentity <WCAUser, IdentityRole>(options =>
            {
                options.User.RequireUniqueEmail        = true;
                options.ClaimsIdentity.UserIdClaimType = "KonektaUserID";
            })
            .AddEntityFrameworkStores <WCADbContext>();

            services.ConfigureActionstepJwtOptions()
            .Configure <ILogger <WCASignInManager> >((options, logger) =>
            {
                options.Audience = appSettings.WCACoreSettings.ActionstepSettings.ValidTokenAudience;
                options.Events.OnTokenValidated = context => WCASignInManager.SignInWithActionstepJwt(context, logger);
            });

            services.ConfigureActionstepLoginOptions();

            services.ConfigureApplicationCookie(o =>
            {
                const int days        = 30;
                o.SlidingExpiration   = true;
                var validCookieTime   = new TimeSpan(days, 0, 0, 0, 0);
                o.Cookie.MaxAge       = validCookieTime;
                o.ExpireTimeSpan      = validCookieTime;
                o.LoginPath           = new PathString("/Identity/Account/Login");
                o.LogoutPath          = new PathString("/Identity/Account/Logout");
                o.AccessDeniedPath    = new PathString("/Identity/Account/AccessDenied");
                o.Cookie.SecurePolicy = CookieSecurePolicy.Always;

                // SameSite must be none so that it works in the Actionstep iframe.
                o.Cookie.SameSite = SameSiteMode.None;
            });

            services.AddAuthentication(IdentityConstants.ApplicationScheme)
            .AddActionstepJwt()
            .AddActionstepLogin();

            services.AddAuthorization(options =>
            {
                options.AddPolicy(AllowAdminSitePolicyName, policy =>
                                  policy.RequireRole(
                                      SecurityRoles.AllowAdminSite.ToString(),
                                      SecurityRoles.GlobalAdministrator.ToString()));
            });

            // Add application services.
            services.AddTransient <IStampDutyService, StampDutyService>();

            // Configure antiforgery to accept token in header
            services.AddAntiforgery(options =>
            {
                options.HeaderName = "X-XSRF-Token";
                options.SuppressXFrameOptionsHeader = true;
                options.Cookie.SecurePolicy         = CookieSecurePolicy.Always;

                // Also check Origin header?

                // SameSite must be none so that it works in the Actionstep iframe.
                options.Cookie.SameSite = SameSiteMode.None;
            });

            services.AddCors();

#pragma warning disable CA2000 // Dispose objects before losing scope: Not disposing because this is added as a singleton
            services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
#pragma warning restore CA2000 // Dispose objects before losing scope

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "client-app/build";
            });

            Trace.TraceInformation("WCA Startup: Leaving ConfigureServices");
        }