diff options
author | GitLab Release Tools Bot <robert+release-tools@gitlab.com> | 2019-08-26 07:42:37 +0000 |
---|---|---|
committer | GitLab Release Tools Bot <robert+release-tools@gitlab.com> | 2019-08-26 07:42:37 +0000 |
commit | 298c1357ebb07519eb968d318c375bd81ca69d2f (patch) | |
tree | 3a89645be6320296eeb45aaa71a7cc27272c09b8 | |
parent | f3853daceca5061e41d0351d0dff2938ba374bfa (diff) | |
parent | 0c21854764464bd110b505d689b3fa112936944f (diff) | |
download | gitlab-ce-298c1357ebb07519eb968d318c375bd81ca69d2f.tar.gz |
Merge branch 'security-sarcila-fix-weak-session-management-12-1' into '12-1-stable'
Clear reset_password_tokens when login (email or username) change
See merge request gitlab/gitlabhq!3347
-rw-r--r-- | app/models/user.rb | 7 | ||||
-rw-r--r-- | changelogs/unreleased/security-sarcila-fix-weak-session-management.yml | 6 | ||||
-rw-r--r-- | spec/features/profiles/user_edit_profile_spec.rb | 17 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 41 |
4 files changed, 71 insertions, 0 deletions
diff --git a/app/models/user.rb b/app/models/user.rb index 0fd3daa3383..58509976135 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -630,6 +630,13 @@ class User < ApplicationRecord end end + # will_save_change_to_attribute? is used by Devise to check if it is necessary + # to clear any existing reset_password_tokens before updating an authentication_key + # and login in our case is a virtual attribute to allow login by username or email. + def will_save_change_to_login? + will_save_change_to_username? || will_save_change_to_email? + end + def unique_email if !emails.exists?(email: email) && Email.exists?(email: email) errors.add(:email, _('has already been taken')) diff --git a/changelogs/unreleased/security-sarcila-fix-weak-session-management.yml b/changelogs/unreleased/security-sarcila-fix-weak-session-management.yml new file mode 100644 index 00000000000..a37a3099519 --- /dev/null +++ b/changelogs/unreleased/security-sarcila-fix-weak-session-management.yml @@ -0,0 +1,6 @@ +--- +title: Fix weak session management by clearing password reset tokens after login (username/email) + are updated +merge_request: +author: +type: security diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb index a53da94ef7d..9ab5026dbc4 100644 --- a/spec/features/profiles/user_edit_profile_spec.rb +++ b/spec/features/profiles/user_edit_profile_spec.rb @@ -47,6 +47,23 @@ describe 'User edit profile' do end end + describe 'when I change my email' do + before do + user.send_reset_password_instructions + end + + it 'clears the reset password token' do + expect(user.reset_password_token?).to be true + + fill_in 'user_email', with: 'new-email@example.com' + submit_settings + + user.reload + expect(user.confirmation_token).not_to be_nil + expect(user.reset_password_token?).to be false + end + end + context 'user avatar' do before do attach_file(:user_avatar, Rails.root.join('spec', 'fixtures', 'banana_sample.gif')) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5cfa64fd764..f4e1fea739b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -3037,6 +3037,47 @@ describe User do end end + describe '#will_save_change_to_login?' do + let(:user) { create(:user, username: 'old-username', email: 'old-email@example.org') } + let(:new_username) { 'new-name' } + let(:new_email) { 'new-email@example.org' } + + subject { user.will_save_change_to_login? } + + context 'when the username is changed' do + before do + user.username = new_username + end + + it { is_expected.to be true } + end + + context 'when the email is changed' do + before do + user.email = new_email + end + + it { is_expected.to be true } + end + + context 'when both email and username are changed' do + before do + user.username = new_username + user.email = new_email + end + + it { is_expected.to be true } + end + + context 'when email and username aren\'t changed' do + before do + user.name = 'new_name' + end + + it { is_expected.to be_falsy } + end + end + describe '#sync_attribute?' do let(:user) { described_class.new } |