Fixed issue #791 - User can't login after to many failed logins even if password gets resetted.
This commit is contained in:
parent
0c97b9a401
commit
d8d88968e9
5 changed files with 75 additions and 14 deletions
|
@ -711,7 +711,7 @@ curl http://localhost/api/v1/users/password_reset_verify.json -v -u #{login}:#{p
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
user = User.password_reset_check(params[:token])
|
user = User.by_reset_token(params[:token])
|
||||||
end
|
end
|
||||||
if user
|
if user
|
||||||
render json: { message: 'ok', user_login: user.login }, status: :ok
|
render json: { message: 'ok', user_login: user.login }, status: :ok
|
||||||
|
|
|
@ -39,7 +39,7 @@ class User < ApplicationModel
|
||||||
|
|
||||||
before_validation :check_name, :check_email, :check_login, :ensure_password
|
before_validation :check_name, :check_email, :check_login, :ensure_password
|
||||||
before_create :check_preferences_default, :validate_roles, :domain_based_assignment, :set_locale
|
before_create :check_preferences_default, :validate_roles, :domain_based_assignment, :set_locale
|
||||||
before_update :check_preferences_default, :validate_roles
|
before_update :check_preferences_default, :validate_roles, :reset_login_failed
|
||||||
after_create :avatar_for_email_check
|
after_create :avatar_for_email_check
|
||||||
after_update :avatar_for_email_check
|
after_update :avatar_for_email_check
|
||||||
after_destroy :avatar_destroy
|
after_destroy :avatar_destroy
|
||||||
|
@ -490,9 +490,9 @@ returns
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
check reset password token
|
returns the User instance for a given password token if found
|
||||||
|
|
||||||
result = User.password_reset_check(token)
|
result = User.by_reset_token(token)
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
|
||||||
|
@ -500,15 +500,8 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.password_reset_check(token)
|
def self.by_reset_token(token)
|
||||||
user = Token.check(action: 'PasswordReset', name: token)
|
Token.check(action: 'PasswordReset', name: token)
|
||||||
|
|
||||||
# reset login failed if token is valid
|
|
||||||
if user
|
|
||||||
user.login_failed = 0
|
|
||||||
user.save
|
|
||||||
end
|
|
||||||
user
|
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
@ -526,7 +519,7 @@ returns
|
||||||
def self.password_reset_via_token(token, password)
|
def self.password_reset_via_token(token, password)
|
||||||
|
|
||||||
# check token
|
# check token
|
||||||
user = Token.check(action: 'PasswordReset', name: token)
|
user = by_reset_token(token)
|
||||||
return if !user
|
return if !user
|
||||||
|
|
||||||
# reset password
|
# reset password
|
||||||
|
@ -938,4 +931,11 @@ returns
|
||||||
self.password = password_was
|
self.password = password_was
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# reset login_failed if password is changed
|
||||||
|
def reset_login_failed
|
||||||
|
return if !changes
|
||||||
|
return if !changes['password']
|
||||||
|
self.login_failed = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
9
spec/factories/token.rb
Normal file
9
spec/factories/token.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
FactoryGirl.define do
|
||||||
|
factory :token do
|
||||||
|
user_id { FactoryGirl.create(:user).id }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :token_password_reset, parent: :token do
|
||||||
|
action 'PasswordReset'
|
||||||
|
end
|
||||||
|
end
|
|
@ -13,10 +13,15 @@ FactoryGirl.define do
|
||||||
email { generate(:email) }
|
email { generate(:email) }
|
||||||
password 'zammad'
|
password 'zammad'
|
||||||
active true
|
active true
|
||||||
|
login_failed 0
|
||||||
updated_by_id 1
|
updated_by_id 1
|
||||||
created_by_id 1
|
created_by_id 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :user_login_failed, parent: :user do
|
||||||
|
login_failed { (Setting.get('password_max_login_failed').to_i || 10) + 1 }
|
||||||
|
end
|
||||||
|
|
||||||
factory :user_legacy_password_sha2, parent: :user do
|
factory :user_legacy_password_sha2, parent: :user do
|
||||||
after(:build) { |user| user.class.skip_callback(:validation, :before, :ensure_password) }
|
after(:build) { |user| user.class.skip_callback(:validation, :before, :ensure_password) }
|
||||||
password '{sha2}dd9c764fa7ea18cd992c8600006d3dc3ac983d1ba22e9ba2d71f6207456be0ba' # zammad
|
password '{sha2}dd9c764fa7ea18cd992c8600006d3dc3ac983d1ba22e9ba2d71f6207456be0ba' # zammad
|
||||||
|
|
47
spec/models/user_spec.rb
Normal file
47
spec/models/user_spec.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe User do
|
||||||
|
|
||||||
|
let(:new_password) { 'N3W54V3PW!' }
|
||||||
|
|
||||||
|
context 'password' do
|
||||||
|
|
||||||
|
it 'resets login_failed on password change' do
|
||||||
|
user = create(:user_login_failed)
|
||||||
|
expect {
|
||||||
|
user.password = new_password
|
||||||
|
user.save
|
||||||
|
}.to change { user.login_failed }.to(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#by_reset_token' do
|
||||||
|
|
||||||
|
it 'returns a User instance for existing tokens' do
|
||||||
|
token = create(:token_password_reset)
|
||||||
|
expect(described_class.by_reset_token(token.name)).to be_instance_of(described_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns nil for not existing tokens' do
|
||||||
|
expect(described_class.by_reset_token('not-existing')).to be nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#password_reset_via_token' do
|
||||||
|
|
||||||
|
it 'changes the password of the token user and destroys the token' do
|
||||||
|
token = create(:token_password_reset)
|
||||||
|
user = User.find(token.user_id)
|
||||||
|
|
||||||
|
expect {
|
||||||
|
described_class.password_reset_via_token(token.name, new_password)
|
||||||
|
user.reload
|
||||||
|
}.to change {
|
||||||
|
user.password
|
||||||
|
}.and change {
|
||||||
|
Token.count
|
||||||
|
}.by(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue