public Task SignInAsync(string userAreaCode, int userId, bool rememberUser)
        {
            if (userAreaCode == null)
            {
                throw new ArgumentNullException(nameof(userAreaCode));
            }
            if (userId < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(userId));
            }

            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(userAreaCode);

            EntityNotFoundException.ThrowIfNull(userArea, userAreaCode);
            var isAmbientUserArea = IsAmbientUserArea(userArea);

            lock (_lock)
            {
                _userIdCache[userArea.UserAreaCode] = userId;

                if (isAmbientUserArea)
                {
                    _userIdCache[AMBIENT_USER_AREA_KEY] = userId;
                }
            }

            return(Task.CompletedTask);
        }
        private void ValidateUserArea(string userAreaCode)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(userAreaCode);

            if (!userArea.AllowPasswordSignIn)
            {
                throw new InvalidOperationException($"Cannot reset the password because the {userArea.Name} user area does not allow password sign in.");
            }

            if (!userArea.UseEmailAsUsername)
            {
                throw new InvalidOperationException($"Cannot reset the password because the {userArea.Name} user area does not require email addresses.");
            }
        }
Example #3
0
        public string FormatUsernameForLookup(string userAreaCode, string username)
        {
            var userAreaDefinition = _userAreaDefinitionRepository.GetRequiredByCode(userAreaCode);
            var usernameUniquifier = CreateServiceForUserArea <IUsernameUniquifier>(userAreaCode, typeof(IUsernameUniquifier <>));

            if (userAreaDefinition.UseEmailAsUsername)
            {
                var emailAddressNormalizer = CreateServiceForUserArea <IEmailAddressNormalizer>(userAreaDefinition, typeof(IEmailAddressNormalizer <>));
                username = emailAddressNormalizer.Normalize(username);
            }

            var result = usernameUniquifier.Uniquify(username);

            return(result);
        }
        /// <summary>
        /// Validates that the username contains only the characters permitted by the
        /// <see cref="UsernameOptions"/> configuration settings.
        /// </summary>
        protected virtual ValidationError ValidateAllowedCharacters(IUsernameValidationContext context)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(context.UserAreaCode);

            // Bypass format validation for email-based usernames
            if (userArea.UseEmailAsUsername)
            {
                return(null);
            }

            var options           = _userAreaDefinitionRepository.GetOptionsByCode(context.UserAreaCode).Username;
            var invalidCharacters = UsernameCharacterValidator.GetInvalidCharacters(context.Username.NormalizedUsername, options);

            if (!invalidCharacters.Any())
            {
                return(null);
            }

            // Be careful here, because we're handling user input. Any message should be escaped when
            // rendered, but to be safe we'll only include a single invalid character
            return(UserValidationErrors
                   .Username
                   .InvalidCharacters
                   .Customize()
                   .WithMessageFormatParameters(invalidCharacters.First().ToString())
                   .WithProperties(context.PropertyName)
                   .Create());
        }
Example #5
0
        /// <summary>
        /// Validates that the email is not already registered with another user.
        /// </summary>
        protected virtual async Task <ValidationError> ValidateUniqueAsync(IEmailAddressValidationContext context)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(context.UserAreaCode);
            var options  = _userAreaDefinitionRepository.GetOptionsByCode(context.UserAreaCode).EmailAddress;

            if (!options.RequireUnique && !userArea.UseEmailAsUsername)
            {
                return(null);
            }

            var query = new IsUserEmailAddressUniqueQuery()
            {
                Email        = context.Email.UniqueEmailAddress,
                UserAreaCode = context.UserAreaCode
            };

            if (context.UserId.HasValue)
            {
                query.UserId = context.UserId.Value;
            }

            var isUnique = await _domainRepository
                           .WithContext(context.ExecutionContext)
                           .ExecuteQueryAsync(query);

            if (isUnique)
            {
                return(null);
            }

            return(UserValidationErrors
                   .EmailAddress
                   .NotUnique
                   .Create(context.PropertyName));
        }
        public virtual TModel Map <TModel>(User dbUser)
            where TModel : UserMicroSummary, new()
        {
            if (dbUser == null)
            {
                return(null);
            }

            var user = new TModel()
            {
                UserId        = dbUser.UserId,
                DisplayName   = dbUser.DisplayName,
                AccountStatus = MapAccountStatus(dbUser)
            };

            var userArea = _userAreaRepository.GetRequiredByCode(dbUser.UserAreaCode);

            EntityNotFoundException.ThrowIfNull(userArea, dbUser.UserAreaCode);

            user.UserArea = new UserAreaMicroSummary()
            {
                UserAreaCode = dbUser.UserAreaCode,
                Name         = userArea.Name
            };

            return(user);
        }
        public EntityAccessRuleSet Map <TAccessRule>(IEntityAccessRestrictable <TAccessRule> entity)
            where TAccessRule : IEntityAccessRule
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            MissingIncludeException.ThrowIfNull(entity, e => e.AccessRules);

            if (!entity.AccessRules.Any())
            {
                // no rules, so return null rather than an empty ruleset
                return(null);
            }

            var violationAction = EnumParser.ParseOrNull <AccessRuleViolationAction>(entity.AccessRuleViolationActionId);

            if (violationAction == null)
            {
                _logger.LogWarning(
                    "AccessRuleViolationAction of value {AccessRuleViolationAction} could not be parsed on rule type {TAccessRule}.",
                    entity.AccessRuleViolationActionId,
                    typeof(TAccessRule).Name
                    );
            }


            var result = new EntityAccessRuleSet()
            {
                ViolationAction = violationAction ?? AccessRuleViolationAction.Error
            };

            if (!string.IsNullOrWhiteSpace(entity.UserAreaCodeForSignInRedirect))
            {
                var userArea = _userAreaDefinitionRepository.GetRequiredByCode(entity.UserAreaCodeForSignInRedirect);
                result.UserAreaCodeForSignInRedirect = userArea.UserAreaCode;
            }

            result.AccessRules = entity
                                 .AccessRules
                                 .OrderByDefault()
                                 .Select(r => MapAccessRule(r))
                                 .ToArray();

            return(result);
        }
        private void ValidateUserArea(AddUserWithTemporaryPasswordCommand command)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(command.UserAreaCode);

            if (!userArea.AllowPasswordSignIn)
            {
                throw new InvalidOperationException(nameof(AddUserWithTemporaryPasswordCommand) + " must be used with a user area that supports password based sign in.");
            }
        }
        public IAccountRecoveryTemplateBuilderContext CreateAccountRecoveryContext(UserSummary user, string token)
        {
            var definition       = _userAreaDefinitionRepository.GetRequiredByCode(user.UserArea.UserAreaCode);
            var options          = _userAreaDefinitionRepository.GetOptionsByCode(user.UserArea.UserAreaCode).AccountRecovery;
            var isCofoundryAdmin = definition is CofoundryAdminUserArea;

            var context = new AccountRecoveryTemplateBuilderContext()
            {
                User  = user,
                Token = token,
                DefaultTemplateFactory = AccountRecoveryTemplateFactory
            };

            // Can be null to allow a custom IDefaultMailTemplateBuilder implementation to the path explicitly
            if (options.RecoveryUrlBase != null)
            {
                context.RecoveryUrlPath = _authorizedTaskTokenUrlHelper.MakeUrl(options.RecoveryUrlBase, token);
            }

            return(context);
        }
Example #10
0
        public async Task SignInAsync(string userAreaCode, int userId, bool rememberUser)
        {
            if (userAreaCode == null)
            {
                throw new ArgumentNullException(nameof(userAreaCode));
            }
            if (userId < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(userId));
            }
            ValidateHttpContext("sign in a user");

            var userArea      = _userAreaDefinitionRepository.GetRequiredByCode(userAreaCode);
            var userPrincipal = await CreateUserPrincipal(userId, userArea);

            var scheme = AuthenticationSchemeNames.UserArea(userArea.UserAreaCode);

            if (rememberUser)
            {
                var authProperties = new AuthenticationProperties()
                {
                    IsPersistent = true
                };
                await _httpContextAccessor.HttpContext.SignInAsync(scheme, userPrincipal, authProperties);
            }
            else
            {
                await _httpContextAccessor.HttpContext.SignInAsync(scheme, userPrincipal);
            }

            await _inMemoryUserSessionService.SignInAsync(userAreaCode, userId, rememberUser);

            if (_signedOutUserAreas.Contains(userAreaCode))
            {
                // signed out and back in during the same request: odd but let's handle it.
                _signedOutUserAreas.Remove(userAreaCode);
            }
        }
Example #11
0
        private void ValidateUserArea(ValidateUserAccountRecoveryByEmailQuery query)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(query.UserAreaCode);

            if (!userArea.AllowPasswordSignIn)
            {
                throw new InvalidAccountRecoveryRequestException(query, "Cannot update the password to account in a user area that does not allow password sign in.");
            }

            if (!userArea.UseEmailAsUsername)
            {
                throw new InvalidAccountRecoveryRequestException(query, $"Cannot reset the password because the {userArea.Name} user area does not require email addresses.");
            }
        }
Example #12
0
        private async Task ValidatePasswordAsync(User user, CompleteUserAccountRecoveryViaEmailCommand command, IExecutionContext executionContext)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(command.UserAreaCode);

            _passwordUpdateCommandHelper.ValidateUserArea(userArea);

            var context = NewPasswordValidationContext.MapFromUser(user);

            context.Password         = command.NewPassword;
            context.PropertyName     = nameof(command.NewPassword);
            context.ExecutionContext = executionContext;

            await _newPasswordValidationService.ValidateAsync(context);
        }
Example #13
0
        private async Task ValidatePasswordAsync(UpdateCurrentUserPasswordCommand command, User user, IExecutionContext executionContext)
        {
            var userArea = _userAreaRepository.GetRequiredByCode(user.UserAreaCode);

            _passwordUpdateCommandHelper.ValidateUserArea(userArea);

            var context = NewPasswordValidationContext.MapFromUser(user);

            context.CurrentPassword  = command.OldPassword;
            context.Password         = command.NewPassword;
            context.PropertyName     = nameof(command.NewPassword);
            context.ExecutionContext = executionContext;

            await _newPasswordValidationService.ValidateAsync(context);
        }
        public string GetSignInUrl(UserSummary user)
        {
            string signInPath;

            if (user.UserArea.UserAreaCode == CofoundryAdminUserArea.Code)
            {
                signInPath = "/" + _adminSettings.DirectoryName;
            }
            else
            {
                var options = _userAreaDefinitionRepository.GetRequiredByCode(user.UserArea.UserAreaCode);
                signInPath = options.SignInPath;
            }

            return(_siteUrlResolver.MakeAbsolute(signInPath));
        }
Example #15
0
        public async Task ExecuteAsync(UpdateUserAccountVerificationStatusCommand command, IExecutionContext executionContext)
        {
            var user = await GetUserAsync(command.UserId);

            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(user.UserAreaCode);

            ValidatePermissions(userArea, executionContext);
            var hasVerificationStatusChanged = UpdateAccountVerifiedStatus(command, user, executionContext);

            await _dbContext.SaveChangesAsync();

            if (hasVerificationStatusChanged)
            {
                await _domainRepository.Transactions().QueueCompletionTaskAsync(() => OnTransactionComplete(user, command));
            }
        }
        /// <summary>
        /// Maps an EF Role record from the db into an RoleDetails
        /// object. If the db record is null then null is returned.
        /// </summary>
        /// <param name="dbRole">Role record from the database.</param>
        public virtual RoleDetails Map(Role dbRole)
        {
            if (dbRole == null)
            {
                return(null);
            }

            var role = new RoleDetails()
            {
                IsAnonymousRole  = dbRole.RoleCode == AnonymousRole.Code && dbRole.UserAreaCode == CofoundryAdminUserArea.Code,
                IsSuperAdminRole = dbRole.RoleCode == SuperAdminRole.Code && dbRole.UserAreaCode == CofoundryAdminUserArea.Code,
                RoleId           = dbRole.RoleId,
                RoleCode         = dbRole.RoleCode,
                Title            = dbRole.Title
            };

            var userArea = _userAreaRepository.GetRequiredByCode(dbRole.UserAreaCode);

            role.UserArea = new UserAreaMicroSummary()
            {
                UserAreaCode = dbRole.UserAreaCode,
                Name         = userArea.Name
            };

            if (role.IsSuperAdminRole)
            {
                // Grant super users all permissions
                role.Permissions = _permissionRepository.GetAll().ToArray();
            }
            else
            {
                var permissions = new List <IPermission>(dbRole.RolePermissions.Count);

                foreach (var dbPermission in dbRole.RolePermissions.Select(rp => rp.Permission))
                {
                    var permission = _permissionRepository.GetByCode(dbPermission.PermissionCode, dbPermission.EntityDefinitionCode);
                    if (permission != null)
                    {
                        permissions.Add(permission);
                    }
                }

                role.Permissions = permissions.ToArray();
            }

            return(role);
        }
        public virtual UserSummary Map(User dbUser)
        {
            if (dbUser == null)
            {
                return(null);
            }

            if (dbUser.Role == null)
            {
                throw new ArgumentException("dbUser.Role must be included in the query to map to use the UserSummaryMapper");
            }

            var user = _userMicroSummaryMapper.Map <UserSummary>(dbUser);

            user.Email          = dbUser.Email;
            user.FirstName      = dbUser.FirstName;
            user.LastName       = dbUser.LastName;
            user.Username       = dbUser.Username;
            user.LastSignInDate = dbUser.LastSignInDate;

            user.AuditData = new CreateAuditData()
            {
                CreateDate = dbUser.CreateDate
            };

            if (dbUser.Creator != null)
            {
                user.AuditData.Creator = _userMicroSummaryMapper.Map(dbUser.Creator);
            }

            var userArea = _userAreaRepository.GetRequiredByCode(dbUser.UserAreaCode);

            EntityNotFoundException.ThrowIfNull(userArea, dbUser.UserAreaCode);

            user.UserArea = new UserAreaMicroSummary()
            {
                UserAreaCode = dbUser.UserAreaCode,
                Name         = userArea.Name
            };

            user.Role = _roleMicroSummaryMapper.Map(dbUser.Role);

            return(user);
        }
        public async Task ExecuteAsync(EnsureUserAreaExistsCommand command, IExecutionContext executionContext)
        {
            var userArea = _userAreaRepository.GetRequiredByCode(command.UserAreaCode);

            EntityNotFoundException.ThrowIfNull(userArea, command.UserAreaCode);

            var dbUserArea = await _dbContext
                             .UserAreas
                             .SingleOrDefaultAsync(a => a.UserAreaCode == userArea.UserAreaCode);

            if (dbUserArea == null)
            {
                dbUserArea = new UserArea();
                dbUserArea.UserAreaCode = userArea.UserAreaCode;
                dbUserArea.Name         = userArea.Name;

                _dbContext.UserAreas.Add(dbUserArea);
            }
        }
        public async Task <ValidationQueryResult> ExecuteAsync(ValidateUsernameQuery query, IExecutionContext executionContext)
        {
            var userArea         = _userAreaDefinitionRepository.GetRequiredByCode(query.UserAreaCode);
            var formattingResult = _userDataFormatter.FormatUsername(userArea, query.Username);

            var context = new UsernameValidationContext()
            {
                Username         = formattingResult,
                ExecutionContext = executionContext,
                PropertyName     = nameof(query.Username),
                UserAreaCode     = userArea.UserAreaCode,
                UserId           = query.UserId
            };

            var errors = await _usernameValidator.GetErrorsAsync(context);

            var result = new ValidationQueryResult(errors.FirstOrDefault());

            return(result);
        }
Example #20
0
        private async Task ValidatePasswordAsync(
            UpdateUserPasswordByUserIdCommand command,
            User user,
            IExecutionContext executionContext
            )
        {
            await _userCommandPermissionsHelper.ThrowIfCannotManageSuperAdminAsync(user, executionContext);

            var userArea = _userAreaRepository.GetRequiredByCode(user.UserAreaCode);

            _passwordUpdateCommandHelper.ValidateUserArea(userArea);
            _passwordUpdateCommandHelper.ValidatePermissions(userArea, executionContext);

            var context = NewPasswordValidationContext.MapFromUser(user);

            context.Password         = command.NewPassword;
            context.PropertyName     = nameof(command.NewPassword);
            context.ExecutionContext = executionContext;

            await _newPasswordValidationService.ValidateAsync(context);
        }
Example #21
0
        public async Task <JsonResult> Post([FromBody] AddUserCommand command)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(command.UserAreaCode);

            if (userArea.AllowPasswordSignIn)
            {
                return(await _apiResponseHelper.RunCommandAsync(new AddUserWithTemporaryPasswordCommand()
                {
                    Email = command.Email,
                    FirstName = command.FirstName,
                    LastName = command.LastName,
                    RoleCode = command.RoleCode,
                    RoleId = command.RoleId,
                    UserAreaCode = command.UserAreaCode,
                    Username = command.Username,
                    DisplayName = command.DisplayName
                }));
            }

            return(await _apiResponseHelper.RunCommandAsync(command));
        }
Example #22
0
        public IUserMailTemplateBuilder Create(string userAreaDefinitionCode)
        {
            var userAreaDefinition = _userAreaDefinitionRepository.GetRequiredByCode(userAreaDefinitionCode);

            EntityNotFoundException.ThrowIfNull(userAreaDefinition, userAreaDefinitionCode);

            // Try and find a factory registered for the specific user area
            var definitionType = userAreaDefinition.GetType();
            var factoryType    = typeof(IUserMailTemplateBuilder <>).MakeGenericType(definitionType);
            var factory        = _serviceProvider.GetService(factoryType);

            if (factory != null)
            {
                return((IUserMailTemplateBuilder)factory);
            }

            var defaultBuilderType = typeof(IDefaultUserMailTemplateBuilder <>).MakeGenericType(definitionType);

            // for other user areas fall back to the default builder
            return((IUserMailTemplateBuilder)_serviceProvider.GetRequiredService(defaultBuilderType));
        }
Example #23
0
        public async Task ExecuteAsync(AddUserCommand command, IExecutionContext executionContext)
        {
            var userArea   = _userAreaRepository.GetRequiredByCode(command.UserAreaCode);
            var dbUserArea = await GetUserAreaAsync(userArea);

            var role = await GetAndValidateRoleAsync(command, executionContext);

            var user = new User()
            {
                FirstName              = command.FirstName?.Trim(),
                LastName               = command.LastName?.Trim(),
                RequirePasswordChange  = command.RequirePasswordChange,
                LastPasswordChangeDate = executionContext.ExecutionDate,
                AccountVerifiedDate    = command.IsAccountVerified ? executionContext.ExecutionDate : (DateTime?)null,
                CreateDate             = executionContext.ExecutionDate,
                Role          = role,
                UserArea      = dbUserArea,
                CreatorId     = executionContext.UserContext.UserId,
                SecurityStamp = _securityStampGenerator.Generate()
            };

            if (!command.IsActive)
            {
                user.DeactivatedDate = executionContext.ExecutionDate;
            }

            await _userUpdateCommandHelper.UpdateEmailAndUsernameAsync(command.Email, command.Username, user, executionContext);

            await ValidatePasswordAsync(userArea, user, command, executionContext);

            SetPassword(user, command, userArea);
            SetDisplayName(command, user);

            _dbContext.Users.Add(user);
            await _dbContext.SaveChangesAsync();

            await _transactionScopeFactory.QueueCompletionTaskAsync(_dbContext, () => OnTransactionComplete(userArea, user));

            command.OutputUserId = user.UserId;
        }
        public PasswordVerificationResult VerifyPassword(User user, string password)
        {
            if (user == null)
            {
                return(PasswordVerificationResult.Failed);
            }

            var userArea = _userAreaRepository.GetRequiredByCode(user.UserAreaCode);

            if (!userArea.AllowPasswordSignIn)
            {
                throw new InvalidOperationException("This user is not permitted to log in with a password.");
            }

            if (String.IsNullOrWhiteSpace(user.Password) || !user.PasswordHashVersion.HasValue)
            {
                throw new InvalidOperationException("Cannot authenticate via password because the specified account does not have a password set.");
            }

            var result = _cryptographyService.Verify(password, user.Password, user.PasswordHashVersion.Value);

            return(result);
        }
Example #25
0
        public virtual RoleMicroSummary Map(Role dbRole)
        {
            if (dbRole == null)
            {
                return(null);
            }

            var role = new RoleMicroSummary()
            {
                RoleId = dbRole.RoleId,
                Title  = dbRole.Title
            };

            var userArea = _userAreaRepository.GetRequiredByCode(dbRole.UserAreaCode);

            role.UserArea = new UserAreaMicroSummary()
            {
                UserAreaCode = dbRole.UserAreaCode,
                Name         = userArea.Name
            };

            return(role);
        }
Example #26
0
        public UserContext Map(User dbUser)
        {
            if (dbUser == null)
            {
                return(null);
            }

            if (dbUser.Role == null)
            {
                throw new ArgumentException("User role is null. Ensure this has been included in the query.", nameof(dbUser));
            }

            var cx = new UserContext();

            cx.IsPasswordChangeRequired = dbUser.RequirePasswordChange;
            cx.IsAccountVerified        = dbUser.AccountVerifiedDate.HasValue;
            cx.RoleId   = dbUser.RoleId;
            cx.RoleCode = dbUser.Role.RoleCode;
            cx.UserId   = dbUser.UserId;
            cx.UserArea = _userAreaRepository.GetRequiredByCode(dbUser.UserAreaCode);

            return(cx);
        }
        public IPasswordPolicy Create(string userAreaCode)
        {
            var userArea = _userAreaDefinitionRepository.GetRequiredByCode(userAreaCode);

            return(Create(userArea));
        }