diff options
Diffstat (limited to 'spec/lib/gitlab/auth')
-rw-r--r-- | spec/lib/gitlab/auth/auth_finders_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/crowd/authentication_spec.rb | 48 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/ldap/user_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/o_auth/user_spec.rb | 17 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/otp/session_enforcer_spec.rb | 41 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb | 24 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/otp/strategies/forti_token_cloud_spec.rb | 87 | ||||
-rw-r--r-- | spec/lib/gitlab/auth/request_authenticator_spec.rb | 56 |
8 files changed, 278 insertions, 29 deletions
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb index 3c19ef0bd1b..f927d5912bb 100644 --- a/spec/lib/gitlab/auth/auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/auth_finders_spec.rb @@ -147,6 +147,13 @@ RSpec.describe Gitlab::Auth::AuthFinders do expect(find_user_from_feed_token(:rss)).to eq user end + it 'returns nil if valid feed_token and disabled' do + allow(Gitlab::CurrentSettings).to receive(:disable_feed_token).and_return(true) + set_param(:feed_token, user.feed_token) + + expect(find_user_from_feed_token(:rss)).to be_nil + end + it 'returns nil if feed_token is blank' do expect(find_user_from_feed_token(:rss)).to be_nil end @@ -377,6 +384,16 @@ RSpec.describe Gitlab::Auth::AuthFinders do expect { find_personal_access_token }.to raise_error(Gitlab::Auth::UnauthorizedError) end + + context 'when using a non-prefixed access token' do + let(:personal_access_token) { create(:personal_access_token, :no_prefix, user: user) } + + it 'returns user' do + set_header('HTTP_AUTHORIZATION', "Bearer #{personal_access_token.token}") + + expect(find_user_from_access_token).to eq user + end + end end end diff --git a/spec/lib/gitlab/auth/crowd/authentication_spec.rb b/spec/lib/gitlab/auth/crowd/authentication_spec.rb new file mode 100644 index 00000000000..71eb8036fdd --- /dev/null +++ b/spec/lib/gitlab/auth/crowd/authentication_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Auth::Crowd::Authentication do + let(:provider) { 'crowd' } + let(:login) { generate(:username) } + let(:password) { 'password' } + let(:crowd_auth) { described_class.new(provider) } + let(:user_info) { { user: login } } + + describe 'login' do + before do + allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).with(provider).and_return(true) + allow(crowd_auth).to receive(:user_info_from_authentication).and_return(user_info) + end + + it "finds the user if authentication is successful" do + create(:omniauth_user, extern_uid: login, username: login, provider: provider) + + expect(crowd_auth.login(login, password)).to be_truthy + end + + it "is false if the user does not exist" do + expect(crowd_auth.login(login, password)).to be_falsey + end + + it "is false if the authentication fails" do + allow(crowd_auth).to receive(:user_info_from_authentication).and_return(nil) + + expect(crowd_auth.login(login, password)).to be_falsey + end + + it "fails when crowd is disabled" do + allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).with('crowd').and_return(false) + + expect(crowd_auth.login(login, password)).to be_falsey + end + + it "fails if no login is supplied" do + expect(crowd_auth.login('', password)).to be_falsey + end + + it "fails if no password is supplied" do + expect(crowd_auth.login(login, '')).to be_falsey + end + end +end diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb index ccaed94b5c8..e910ac09448 100644 --- a/spec/lib/gitlab/auth/ldap/user_spec.rb +++ b/spec/lib/gitlab/auth/ldap/user_spec.rb @@ -49,23 +49,6 @@ RSpec.describe Gitlab::Auth::Ldap::User do end end - describe '.find_by_uid_and_provider' do - let(:dn) { 'CN=John Åström, CN=Users, DC=Example, DC=com' } - - it 'retrieves the correct user' do - special_info = { - name: 'John Åström', - email: 'john@example.com', - nickname: 'jastrom' - } - special_hash = OmniAuth::AuthHash.new(uid: dn, provider: 'ldapmain', info: special_info) - special_chars_user = described_class.new(special_hash) - user = special_chars_user.save - - expect(described_class.find_by_uid_and_provider(dn, 'ldapmain')).to eq user - end - end - describe 'find or create' do it "finds the user if already existing" do create(:omniauth_user, extern_uid: 'uid=john smith,ou=people,dc=example,dc=com', provider: 'ldapmain') diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb index 243d0a4cb45..6c6cee9c273 100644 --- a/spec/lib/gitlab/auth/o_auth/user_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb @@ -25,6 +25,23 @@ RSpec.describe Gitlab::Auth::OAuth::User do let(:ldap_user) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') } + describe '.find_by_uid_and_provider' do + let(:dn) { 'CN=John Åström, CN=Users, DC=Example, DC=com' } + + it 'retrieves the correct user' do + special_info = { + name: 'John Åström', + email: 'john@example.com', + nickname: 'jastrom' + } + special_hash = OmniAuth::AuthHash.new(uid: dn, provider: 'ldapmain', info: special_info) + special_chars_user = described_class.new(special_hash) + user = special_chars_user.save + + expect(described_class.find_by_uid_and_provider(dn, 'ldapmain')).to eq user + end + end + describe '#persisted?' do let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') } diff --git a/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb b/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb new file mode 100644 index 00000000000..928aade4008 --- /dev/null +++ b/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Auth::Otp::SessionEnforcer, :clean_gitlab_redis_shared_state do + let_it_be(:key) { create(:key)} + + describe '#update_session' do + it 'registers a session in Redis' do + redis = double(:redis) + expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis) + + expect(redis).to( + receive(:setex) + .with("#{described_class::OTP_SESSIONS_NAMESPACE}:#{key.id}", + described_class::DEFAULT_EXPIRATION, + true) + .once) + + described_class.new(key).update_session + end + end + + describe '#access_restricted?' do + subject { described_class.new(key).access_restricted? } + + context 'with existing session' do + before do + Gitlab::Redis::SharedState.with do |redis| + redis.set("#{described_class::OTP_SESSIONS_NAMESPACE}:#{key.id}", true ) + end + end + + it { is_expected.to be_falsey } + end + + context 'without an existing session' do + it { is_expected.to be_truthy } + end + end +end diff --git a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb index 18fd6d08057..88a245b6b10 100644 --- a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb +++ b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb @@ -12,30 +12,32 @@ RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator do let(:api_token) { 's3cr3t' } let(:forti_authenticator_auth_url) { "https://#{host}:#{port}/api/v1/auth/" } + let(:response_status) { 200 } subject(:validate) { described_class.new(user).validate(otp_code) } before do - stub_feature_flags(forti_authenticator: true) + stub_feature_flags(forti_authenticator: user) stub_forti_authenticator_config( + enabled: true, host: host, port: port, username: api_username, - token: api_token + access_token: api_token ) request_body = { username: user.username, token_code: otp_code } stub_request(:post, forti_authenticator_auth_url) - .with(body: JSON(request_body), headers: { 'Content-Type' => 'application/json' }) - .to_return(status: response_status, body: '', headers: {}) + .with(body: JSON(request_body), + headers: { 'Content-Type': 'application/json' }, + basic_auth: [api_username, api_token]) + .to_return(status: response_status, body: '') end context 'successful validation' do - let(:response_status) { 200 } - it 'returns success' do expect(validate[:status]).to eq(:success) end @@ -49,6 +51,16 @@ RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator do end end + context 'unexpected error' do + it 'returns error' do + error_message = 'boom!' + stub_request(:post, forti_authenticator_auth_url).to_raise(StandardError.new(error_message)) + + expect(validate[:status]).to eq(:error) + expect(validate[:message]).to eq(error_message) + end + end + def stub_forti_authenticator_config(forti_authenticator_settings) allow(::Gitlab.config.forti_authenticator).to(receive_messages(forti_authenticator_settings)) end diff --git a/spec/lib/gitlab/auth/otp/strategies/forti_token_cloud_spec.rb b/spec/lib/gitlab/auth/otp/strategies/forti_token_cloud_spec.rb new file mode 100644 index 00000000000..1580fc82279 --- /dev/null +++ b/spec/lib/gitlab/auth/otp/strategies/forti_token_cloud_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Auth::Otp::Strategies::FortiTokenCloud do + let_it_be(:user) { create(:user) } + let(:otp_code) { 42 } + + let(:url) { 'https://ftc.example.com:9696/api/v1' } + let(:client_id) { 'client_id' } + let(:client_secret) { 's3cr3t' } + let(:access_token_create_url) { url + '/login' } + let(:otp_verification_url) { url + '/auth' } + let(:access_token) { 'an_access_token' } + let(:access_token_create_response_body) { '' } + + subject(:validate) { described_class.new(user).validate(otp_code) } + + before do + stub_feature_flags(forti_token_cloud: user) + + stub_const("#{described_class}::BASE_API_URL", url) + + stub_forti_token_cloud_config( + enabled: true, + client_id: client_id, + client_secret: client_secret + ) + + access_token_request_body = { client_id: client_id, + client_secret: client_secret } + + stub_request(:post, access_token_create_url) + .with(body: JSON(access_token_request_body), headers: { 'Content-Type' => 'application/json' }) + .to_return( + status: access_token_create_response_status, + body: Gitlab::Json.generate(access_token_create_response_body), + headers: {} + ) + end + + context 'access token is created successfully' do + let(:access_token_create_response_body) { { access_token: access_token, expires_in: 3600 } } + let(:access_token_create_response_status) { 201 } + + before do + otp_verification_request_body = { username: user.username, + token: otp_code } + + stub_request(:post, otp_verification_url) + .with(body: JSON(otp_verification_request_body), + headers: { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{access_token}" + }) + .to_return(status: otp_verification_response_status, body: '', headers: {}) + end + + context 'otp verification is successful' do + let(:otp_verification_response_status) { 200 } + + it 'returns success' do + expect(validate[:status]).to eq(:success) + end + end + + context 'otp verification is not successful' do + let(:otp_verification_response_status) { 401 } + + it 'returns error' do + expect(validate[:status]).to eq(:error) + end + end + end + + context 'access token creation fails' do + let(:access_token_create_response_status) { 400 } + + it 'returns error' do + expect(validate[:status]).to eq(:error) + end + end + + def stub_forti_token_cloud_config(forti_token_cloud_settings) + allow(::Gitlab.config.forti_token_cloud).to(receive_messages(forti_token_cloud_settings)) + end +end diff --git a/spec/lib/gitlab/auth/request_authenticator_spec.rb b/spec/lib/gitlab/auth/request_authenticator_spec.rb index b89ceb37076..ef6b1d72712 100644 --- a/spec/lib/gitlab/auth/request_authenticator_spec.rb +++ b/spec/lib/gitlab/auth/request_authenticator_spec.rb @@ -50,13 +50,13 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do allow_any_instance_of(described_class).to receive(:find_user_from_web_access_token).and_return(access_token_user) allow_any_instance_of(described_class).to receive(:find_user_from_feed_token).and_return(feed_token_user) - expect(subject.find_sessionless_user([:api])).to eq access_token_user + expect(subject.find_sessionless_user(:api)).to eq access_token_user end it 'returns feed_token user if no access_token user found' do allow_any_instance_of(described_class).to receive(:find_user_from_feed_token).and_return(feed_token_user) - expect(subject.find_sessionless_user([:api])).to eq feed_token_user + expect(subject.find_sessionless_user(:api)).to eq feed_token_user end it 'returns static_object_token user if no feed_token user found' do @@ -64,7 +64,7 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do .to receive(:find_user_from_static_object_token) .and_return(static_object_token_user) - expect(subject.find_sessionless_user([:api])).to eq static_object_token_user + expect(subject.find_sessionless_user(:api)).to eq static_object_token_user end it 'returns job_token user if no static_object_token user found' do @@ -72,17 +72,61 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do .to receive(:find_user_from_job_token) .and_return(job_token_user) - expect(subject.find_sessionless_user([:api])).to eq job_token_user + expect(subject.find_sessionless_user(:api)).to eq job_token_user end it 'returns nil if no user found' do - expect(subject.find_sessionless_user([:api])).to be_blank + expect(subject.find_sessionless_user(:api)).to be_blank end it 'rescue Gitlab::Auth::AuthenticationError exceptions' do allow_any_instance_of(described_class).to receive(:find_user_from_web_access_token).and_raise(Gitlab::Auth::UnauthorizedError) - expect(subject.find_sessionless_user([:api])).to be_blank + expect(subject.find_sessionless_user(:api)).to be_blank + end + end + + describe '#find_personal_access_token_from_http_basic_auth' do + let_it_be(:personal_access_token) { create(:personal_access_token) } + let_it_be(:user) { personal_access_token.user } + + before do + allow(subject).to receive(:has_basic_credentials?).and_return(true) + allow(subject).to receive(:user_name_and_password).and_return([user.username, personal_access_token.token]) + end + + context 'with API requests' do + before do + env['SCRIPT_NAME'] = '/api/endpoint' + end + + it 'tries to find the user' do + expect(subject.user([:api])).to eq user + end + + it 'returns nil if the token is revoked' do + personal_access_token.revoke! + + expect(subject.user([:api])).to be_blank + end + + it 'returns nil if the token does not have API scope' do + personal_access_token.update!(scopes: ['read_registry']) + + expect(subject.user([:api])).to be_blank + end + end + + context 'without API requests' do + before do + env['SCRIPT_NAME'] = '/web/endpoint' + end + + it 'does not search for job users' do + expect(PersonalAccessToken).not_to receive(:find_by_token) + + expect(subject.user([:api])).to be_nil + end end end |