diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-16 03:13:19 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-16 03:13:19 +0000 |
commit | 0e6ff93eba3ed1ba4c7be0ec78a76dde71a47285 (patch) | |
tree | 5644055ecab86d9f68a1ac701ca8ac8e9219ce77 /spec | |
parent | d746accf38bc9304f29c2bc4a70dfdc6565170f7 (diff) | |
download | gitlab-ce-0e6ff93eba3ed1ba4c7be0ec78a76dde71a47285.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/registrations_controller_spec.rb | 27 | ||||
-rw-r--r-- | spec/finders/groups_finder_spec.rb | 102 | ||||
-rw-r--r-- | spec/initializers/settings_spec.rb | 36 | ||||
-rw-r--r-- | spec/lib/security/weak_passwords_spec.rb | 112 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 52 |
5 files changed, 329 insertions, 0 deletions
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index fcf7331423c..2af04918882 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -493,6 +493,33 @@ RSpec.describe RegistrationsController do end end end + + context 'when the password is weak' do + render_views + let_it_be(:new_user_params) { { new_user: base_user_params.merge({ password: "password" }) } } + + subject { post(:create, params: new_user_params) } + + context 'when block_weak_passwords is enabled (default)' do + it 'renders the form with errors' do + expect { subject }.not_to change(User, :count) + + expect(controller.current_user).to be_nil + expect(response).to render_template(:new) + expect(response.body).to include(_('Password must not contain commonly used combinations of words and letters')) + end + end + + context 'when block_weak_passwords is disabled' do + before do + stub_feature_flags(block_weak_passwords: false) + end + + it 'permits weak passwords' do + expect { subject }.to change(User, :count).by(1) + end + end + end end describe '#destroy' do diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb index a4cbee6a124..123df418f8d 100644 --- a/spec/finders/groups_finder_spec.rb +++ b/spec/finders/groups_finder_spec.rb @@ -261,6 +261,108 @@ RSpec.describe GroupsFinder do end end end + + context 'with include_ancestors' do + let_it_be(:user) { create(:user) } + + let_it_be(:parent_group) { create(:group, :public) } + let_it_be(:public_subgroup) { create(:group, :public, parent: parent_group) } + let_it_be(:public_subgroup2) { create(:group, :public, parent: parent_group) } + let_it_be(:private_subgroup1) { create(:group, :private, parent: parent_group) } + let_it_be(:internal_sub_subgroup) { create(:group, :internal, parent: public_subgroup) } + let_it_be(:public_sub_subgroup) { create(:group, :public, parent: public_subgroup) } + let_it_be(:private_subgroup2) { create(:group, :private, parent: parent_group) } + let_it_be(:private_sub_subgroup) { create(:group, :private, parent: private_subgroup2) } + let_it_be(:private_sub_sub_subgroup) { create(:group, :private, parent: private_sub_subgroup) } + + context 'if include_ancestors is true' do + let(:params) { { include_ancestors: true } } + + it 'returns ancestors of user groups' do + private_sub_subgroup.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + parent_group, + public_subgroup, + public_subgroup2, + internal_sub_subgroup, + public_sub_subgroup, + private_subgroup2, + private_sub_subgroup, + private_sub_sub_subgroup + ) + end + + it 'returns subgroup if user is member of project of subgroup' do + project = create(:project, :private, namespace: private_sub_subgroup) + project.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + parent_group, + public_subgroup, + public_subgroup2, + internal_sub_subgroup, + public_sub_subgroup, + private_subgroup2, + private_sub_subgroup + ) + end + + it 'returns only groups related to user groups if all_available is false' do + params[:all_available] = false + private_sub_subgroup.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + parent_group, + private_subgroup2, + private_sub_subgroup, + private_sub_sub_subgroup + ) + end + end + + context 'if include_ancestors is false' do + let(:params) { { include_ancestors: false } } + + it 'does not return private ancestors of user groups' do + private_sub_subgroup.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + parent_group, + public_subgroup, + public_subgroup2, + internal_sub_subgroup, + public_sub_subgroup, + private_sub_subgroup, + private_sub_sub_subgroup + ) + end + + it "returns project's parent group if user is member of project" do + project = create(:project, :private, namespace: private_sub_subgroup) + project.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + parent_group, + public_subgroup, + public_subgroup2, + internal_sub_subgroup, + public_sub_subgroup, + private_sub_subgroup + ) + end + + it 'returns only user groups and their descendants if all_available is false' do + params[:all_available] = false + private_sub_subgroup.add_developer(user) + + expect(described_class.new(user, params).execute).to contain_exactly( + private_sub_subgroup, + private_sub_sub_subgroup + ) + end + end + end end describe '#execute' do diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index 71ea12a41aa..c3200d2fab1 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -58,4 +58,40 @@ RSpec.describe Settings do end end end + + describe "#weak_passwords_digest_set" do + subject { described_class.gitlab.weak_passwords_digest_set } + + it 'is a Set' do + expect(subject).to be_kind_of(Set) + end + + it 'contains 4500 password digests' do + expect(subject.length).to eq(4500) + end + + it 'includes 8 char weak password digest' do + expect(subject).to include(digest("password")) + end + + it 'includes 16 char weak password digest' do + expect(subject).to include(digest("progressivehouse")) + end + + it 'includes long char weak password digest' do + expect(subject).to include(digest("01234567890123456789")) + end + + it 'does not include 7 char weak password digest' do + expect(subject).not_to include(digest("1234567")) + end + + it 'does not include plaintext' do + expect(subject).not_to include("password") + end + + def digest(plaintext) + Digest::SHA256.base64digest(plaintext) + end + end end diff --git a/spec/lib/security/weak_passwords_spec.rb b/spec/lib/security/weak_passwords_spec.rb new file mode 100644 index 00000000000..9d12c352abf --- /dev/null +++ b/spec/lib/security/weak_passwords_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Security::WeakPasswords do + describe "#weak_for_user?" do + using RSpec::Parameterized::TableSyntax + + let(:user) do + build_stubbed(:user, username: "56d4ab689a_win", + name: "Weakést McWeaky-Pass Jr", + email: "predictāble.ZZZ+seventeen@examplecorp.com", + public_email: "fortunate@acme.com" + ) + end + + where(:password, :too_weak) do + # A random password is not too weak + "d2262d56" | false + + # The case-insensitive weak password list + "password" | true + "pAssWord" | true + "princeofdarkness" | true + + # Forbidden substrings + "A1B2gitlabC3" | true + "gitlab123" | true + "theonedevopsplatform" | true + "A1gitlib" | false + + # Predicatable name substrings + "Aweakést" | true + "!@mCwEaKy" | true + "A1B2pass" | true + "A1B2C3jr" | false # jr is too short + + # Predictable username substrings + "56d4ab689a" | true + "56d4ab689a_win" | true + "56d4ab68" | false # it's part of the username, but not a full part + "A1B2Cwin" | false # win is too short + + # Predictable user.email substrings + "predictāble.ZZZ+seventeen@examplecorp.com" | true + "predictable.ZZZ+seventeen@examplecorp.com" | true + "predictāble.ZZZ+seventeen" | true + "examplecorp.com" | true + "!@exAmplecorp" | true + "predictāble123" | true + "seventeen" | true + "predictable" | false # the accent is different + "A1B2CZzZ" | false # ZZZ is too short + # Other emails are not considered + "fortunate@acme.com" | false + "A1B2acme" | false + "fortunate" | false + + # A short password is not automatically too weak + # We rely on User's password length validation, not WeakPasswords. + "1" | false + "1234567" | false + # But a short password with forbidden words or user attributes + # is still weak + "gitlab" | true + "pass" | true + end + + with_them do + it { expect(subject.weak_for_user?(password, user)).to eq(too_weak) } + end + + context 'with a user who has short email parts' do + before do + user.email = 'sid@1.io' + end + + where(:password, :too_weak) do + "11111111" | true # This is on the weak password list + "1.ioABCD" | true # 1.io is long enough to match + "sid@1.io" | true # matches the email in full + "sid@1.ioAB" | true + # sid, 1, and io on their own are too short + "sid1ioAB" | false + "sidsidsi" | false + "ioioioio" | false + end + + with_them do + it { expect(subject.weak_for_user?(password, user)).to eq(too_weak) } + end + end + + context 'with a user who is missing attributes' do + before do + user.name = nil + user.email = nil + user.username = nil + end + + where(:password, :too_weak) do + "d2262d56" | false + "password" | true + "gitlab123" | true + end + + with_them do + it { expect(subject.weak_for_user?(password, user)).to eq(too_weak) } + end + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3487bf7b70e..04f2c7f9176 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -334,6 +334,58 @@ RSpec.describe User do end end end + + context 'check_password_weakness' do + let(:weak_password) { "qwertyuiop" } + + context 'when feature flag is disabled' do + before do + stub_feature_flags(block_weak_passwords: false) + end + + it 'does not add an error when password is weak' do + expect(Security::WeakPasswords).not_to receive(:weak_for_user?) + + user.password = weak_password + expect(user).to be_valid + end + end + + context 'when feature flag is enabled' do + before do + stub_feature_flags(block_weak_passwords: true) + end + + it 'checks for password weakness when password changes' do + expect(Security::WeakPasswords).to receive(:weak_for_user?) + .with(weak_password, user).and_call_original + user.password = weak_password + expect(user).not_to be_valid + end + + it 'adds an error when password is weak' do + user.password = weak_password + expect(user).not_to be_valid + expect(user.errors).to be_of_kind(:password, 'must not contain commonly used combinations of words and letters') + end + + it 'is valid when password is not weak' do + user.password = ::User.random_password + expect(user).to be_valid + end + + it 'is valid when weak password was already set' do + user = build(:user, password: weak_password) + user.save!(validate: false) + + expect(Security::WeakPasswords).not_to receive(:weak_for_user?) + + # Change an unrelated value + user.name = "Example McExampleFace" + expect(user).to be_valid + end + end + end end describe 'name' do |