public async Task ValidateLogonAsync(long tenantId, LogonModel model) { // Do initial model checks (valid email, password required etc) _modelValidator.Validate(model); // Get user given email address string email = model.Email.Trim(); AuthenticationState state = await _authenticationRepository.ReadAuthenticationStateAsync(tenantId, email); // The first condition that causes an invalid user is when user not found due to an invalid email address entered. In this case, state is null. if (state == null) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserCredentialsInvalidMessage)); } // If user has not been confirmed, they must first set their password before they can be validated if (!state.Confirmed) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserUnconfirmedMessage)); } // User may have been disabled by an administrator, in which case it will not be possible to validate account if (!state.Enabled) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserDisabledMessage)); } // If account locked out, check to see when last password failure occured. If lockout duration period expired, undo the lockout. if (state.LockedOut) { TimeSpan lockOutDuration = _authenticationConfigurationService.GetLockOutDuration(tenantId); if ((DateTime.UtcNow - (DateTime)state.LastPasswordFailure) > lockOutDuration) { await UnlockAsync(tenantId, email, state); } else { throw new UserLockedOutException(new ValidationError(null, AuthenticationResource.LogonUserLockedOutMessage)); } } // Finally, check password entered is correct and if not register a password failure which may lock user out byte[] userPasswordSalt = _encryptionService.GetBytes(state.PasswordSalt); byte[] userPasswordSaltedHash = _encryptionService.GetBytes(state.PasswordSaltedHash); byte[] logonPasswordSaltedHash = _encryptionService.EncryptPassword(model.Password, userPasswordSalt); if (!_encryptionService.ByteArraysEqual(logonPasswordSaltedHash, userPasswordSaltedHash)) { await RegisterPasswordFailureAsync(tenantId, email, state); if (state.LockedOut) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserLockedOutMessage)); } else { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserCredentialsInvalidMessage)); } } }
/// <summary> /// Performs main validation of supplied user credentials. If user credentials not valid, a validation error exception will be thrown by this method. /// </summary> /// <param name="model">User credentials to validate.</param> /// <param name="keyPrefix">Validation key prefix.</param> public void ValidateLogon(LogonModel model, string keyPrefix = null) { // Do initial model checks (valid email, password required etc) _modelValidator.Validate(model, keyPrefix); // Get user given email address User user = _userRepository.ReadUserByEmail(model.TenantId, model.Email.Trim().ToLower()); // The first condition that causes an invalid user is when user not found due to an invalid email address entered. In this case, user is null. if (user == null) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserCredentialsInvalidMessage, keyPrefix)); } // If user has not been confirmed, they must first set their password before they can be validated. if (!user.Confirmed) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserUnconfirmedMessage, keyPrefix)); } // User may have been disabled by an administrator, in which case it will not be possible to validate account. if (!user.Enabled) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserDisabledMessage, keyPrefix)); } // If account locked out, check to see when last password failure occured. If lockout duration period expired, we can undo the lockout. if (user.LockedOut) { TimeSpan lockOutDuration = _authenticationConfigurationService.GetLockOutDuration(model.TenantId); if ((DateTime.UtcNow - (DateTime)user.LastPasswordFailure) > lockOutDuration) { // Clear password failures associated with a user and sets user's locked out flag to false user.LockedOut = false; user.LastPasswordFailure = null; user.PasswordFailures = 0; // Do the update _userRepository.UpdateUser(user); } else { throw new UserLockedOutException(new ValidationError(null, AuthenticationResource.LogonUserLockedOutMessage, keyPrefix)); } } // Finally, check password entered is correct and if not register a password failure which may lock user out byte[] userPasswordSalt = _stringService.GetBytes(user.PasswordSalt); byte[] userPasswordSaltedHash = _stringService.GetBytes(user.PasswordSaltedHash); byte[] logonPasswordSaltedHash = _securityService.EncryptPassword(model.Password, userPasswordSalt); if (!_stringService.ByteArraysEqual(logonPasswordSaltedHash, userPasswordSaltedHash)) { RegisterPasswordFailure(user); if (user.LockedOut) { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserLockedOutMessage, keyPrefix)); } else { throw new ValidationErrorException(new ValidationError(null, AuthenticationResource.LogonUserCredentialsInvalidMessage, keyPrefix)); } } }