300 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| require 'spec_helper'
 | |
| 
 | |
| RSpec.describe Gitlab::Auth::CurrentUserMode, :request_store, feature_category: :system_access do
 | |
|   let(:user) { build_stubbed(:user) }
 | |
| 
 | |
|   subject { described_class.new(user) }
 | |
| 
 | |
|   describe '#initialize' do
 | |
|     context 'with user' do
 | |
|       around do |example|
 | |
|         Gitlab::Session.with_session(nil) do
 | |
|           example.run
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       it 'has no session' do
 | |
|         subject
 | |
|         expect(Gitlab::Session.current).to be_nil
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with user and session' do
 | |
|       include_context 'custom session'
 | |
|       let(:session) { { 'key' => "value" } }
 | |
| 
 | |
|       it 'has a session' do
 | |
|         described_class.new(user, session)
 | |
|         expect(Gitlab::Session.current).to eq(session)
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   describe '#current_session_data' do
 | |
|     include_context 'custom session'
 | |
|     let(:session) { { 'key' => "value" } }
 | |
| 
 | |
|     it 'without session' do
 | |
|       expect(Gitlab::Session.current).to eq(session)
 | |
| 
 | |
|       expect(Gitlab::NamespacedSessionStore).to receive(:new).with(described_class::SESSION_STORE_KEY, session)
 | |
| 
 | |
|       subject.current_session_data
 | |
|       expect(Gitlab::Session.current).to eq(session)
 | |
|     end
 | |
| 
 | |
|     it 'with session' do
 | |
|       expect(Gitlab::Session.current).to eq(session)
 | |
|       subject = described_class.new(user, session)
 | |
| 
 | |
|       expect(Gitlab::NamespacedSessionStore).to receive(:new).with(described_class::SESSION_STORE_KEY, session)
 | |
| 
 | |
|       subject.current_session_data
 | |
|       expect(Gitlab::Session.current).to eq(session)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   context 'when session is available' do
 | |
|     include_context 'custom session'
 | |
| 
 | |
|     before do
 | |
|       allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session])
 | |
|     end
 | |
| 
 | |
|     shared_examples 'admin mode cannot be enabled' do
 | |
|       it 'is false by default' do
 | |
|         expect(subject.admin_mode?).to be(false)
 | |
|       end
 | |
| 
 | |
|       it 'cannot be enabled with a valid password' do
 | |
|         subject.enable_admin_mode!(password: user.password)
 | |
| 
 | |
|         expect(subject.admin_mode?).to be(false)
 | |
|       end
 | |
| 
 | |
|       it 'cannot be enabled with an invalid password' do
 | |
|         subject.enable_admin_mode!(password: nil)
 | |
| 
 | |
|         expect(subject.admin_mode?).to be(false)
 | |
|       end
 | |
| 
 | |
|       it 'cannot be enabled with empty params' do
 | |
|         subject.enable_admin_mode!
 | |
| 
 | |
|         expect(subject.admin_mode?).to be(false)
 | |
|       end
 | |
| 
 | |
|       it 'disable has no effect' do
 | |
|         subject.enable_admin_mode!
 | |
|         subject.disable_admin_mode!
 | |
| 
 | |
|         expect(subject.admin_mode?).to be(false)
 | |
|       end
 | |
| 
 | |
|       context 'skipping password validation' do
 | |
|         it 'cannot be enabled with a valid password' do
 | |
|           subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
 | |
| 
 | |
|           expect(subject.admin_mode?).to be(false)
 | |
|         end
 | |
| 
 | |
|         it 'cannot be enabled with an invalid password' do
 | |
|           subject.enable_admin_mode!(skip_password_validation: true)
 | |
| 
 | |
|           expect(subject.admin_mode?).to be(false)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     describe '#admin_mode?' do
 | |
|       context 'when the user is a regular user' do
 | |
|         it_behaves_like 'admin mode cannot be enabled'
 | |
| 
 | |
|         context 'bypassing session' do
 | |
|           it_behaves_like 'admin mode cannot be enabled' do
 | |
|             around do |example|
 | |
|               described_class.bypass_session!(user.id) { example.run }
 | |
|             end
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'when the user is an admin' do
 | |
|         let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|         it_behaves_like 'admin_mode? check if admin_mode can be enabled'
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     describe '#enable_admin_mode!' do
 | |
|       context 'when the user is an admin' do
 | |
|         let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|         it_behaves_like 'enabling admin_mode when it can be enabled'
 | |
|       end
 | |
| 
 | |
|       context 'when user is not an admin' do
 | |
|         let(:user) { build_stubbed(:user) }
 | |
| 
 | |
|         it 'returns false' do
 | |
|           subject.request_admin_mode!
 | |
| 
 | |
|           expect(subject.enable_admin_mode!(password: user.password)).to eq(false)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     describe '#disable_admin_mode!' do
 | |
|       let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|       it_behaves_like 'disabling admin_mode'
 | |
|     end
 | |
| 
 | |
|     describe '.with_current_request_admin_mode' do
 | |
|       context 'with a regular user' do
 | |
|         it 'user is not available inside nor outside the yielded block' do
 | |
|           described_class.with_current_admin(user) do
 | |
|             expect(described_class.current_admin).to be_nil
 | |
|           end
 | |
| 
 | |
|           expect(described_class.bypass_session_admin_id).to be_nil
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'with an admin user' do
 | |
|         let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|         context 'admin mode is disabled' do
 | |
|           it 'user is not available inside nor outside the yielded block' do
 | |
|             described_class.with_current_admin(user) do
 | |
|               expect(described_class.current_admin).to be_nil
 | |
|             end
 | |
| 
 | |
|             expect(described_class.bypass_session_admin_id).to be_nil
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         context 'admin mode is enabled' do
 | |
|           before do
 | |
|             subject.request_admin_mode!
 | |
|             subject.enable_admin_mode!(password: user.password)
 | |
|           end
 | |
| 
 | |
|           it 'user is available only inside the yielded block' do
 | |
|             described_class.with_current_admin(user) do
 | |
|               expect(described_class.current_admin).to be(user)
 | |
|             end
 | |
| 
 | |
|             expect(described_class.current_admin).to be_nil
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   context 'when no session available' do
 | |
|     around do |example|
 | |
|       Gitlab::Session.with_session(nil) do
 | |
|         example.run
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     describe '.bypass_session!' do
 | |
|       context 'when providing a block' do
 | |
|         context 'with a regular user' do
 | |
|           it 'admin mode is false' do
 | |
|             described_class.bypass_session!(user.id) do
 | |
|               expect(Gitlab::Session.current).to be_nil
 | |
|               expect(subject.admin_mode?).to be(false)
 | |
|               expect(described_class.bypass_session_admin_id).to be(user.id)
 | |
|             end
 | |
| 
 | |
|             expect(described_class.bypass_session_admin_id).to be_nil
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         context 'with an admin user' do
 | |
|           let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|           it 'admin mode is true' do
 | |
|             described_class.bypass_session!(user.id) do
 | |
|               expect(Gitlab::Session.current).to be_nil
 | |
|               expect(subject.admin_mode?).to be(true)
 | |
|               expect(described_class.bypass_session_admin_id).to be(user.id)
 | |
|             end
 | |
| 
 | |
|             expect(described_class.bypass_session_admin_id).to be_nil
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'when not providing a block' do
 | |
|         context 'with a regular user' do
 | |
|           it 'admin mode is false' do
 | |
|             described_class.bypass_session!(user.id)
 | |
| 
 | |
|             expect(Gitlab::Session.current).to be_nil
 | |
|             expect(subject.admin_mode?).to be(false)
 | |
|             expect(described_class.bypass_session_admin_id).to be(user.id)
 | |
| 
 | |
|             described_class.reset_bypass_session!
 | |
| 
 | |
|             expect(described_class.bypass_session_admin_id).to be_nil
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         context 'with an admin user' do
 | |
|           let(:user) { build_stubbed(:user, :admin) }
 | |
| 
 | |
|           it 'admin mode is true' do
 | |
|             described_class.bypass_session!(user.id)
 | |
| 
 | |
|             expect(Gitlab::Session.current).to be_nil
 | |
|             expect(subject.admin_mode?).to be(true)
 | |
|             expect(described_class.bypass_session_admin_id).to be(user.id)
 | |
| 
 | |
|             described_class.reset_bypass_session!
 | |
| 
 | |
|             expect(described_class.bypass_session_admin_id).to be_nil
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     describe '.optionally_run_in_admin_mode' do
 | |
|       let(:admin) { build_stubbed(:admin) }
 | |
| 
 | |
|       context 'when invoked from a sidekiq context', :with_sidekiq_context do
 | |
|         before do
 | |
|           stub_application_setting(admin_mode: true)
 | |
|         end
 | |
| 
 | |
|         it 'yields without changing the admin mode for non-admin users' do
 | |
|           expect { |b| described_class.optionally_run_in_admin_mode(user, &b) }.to yield_control
 | |
|           expect(described_class.bypass_session_admin_id).to be_nil
 | |
|         end
 | |
| 
 | |
|         it 'runs in admin mode for admin users' do
 | |
|           described_class.optionally_run_in_admin_mode(admin) do
 | |
|             expect(described_class.bypass_session_admin_id).to eq(admin.id)
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         it 'resets the admin mode after yielding for admin users' do
 | |
|           described_class.optionally_run_in_admin_mode(admin) { -> {} }
 | |
|           expect(described_class.bypass_session_admin_id).to be_nil
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'when invoked from a non-sidekiq context' do
 | |
|         it 'raises an exception' do
 | |
|           expect { described_class.optionally_run_in_admin_mode(admin) }
 | |
|             .to raise_error(Gitlab::Auth::CurrentUserMode::NonSidekiqEnvironmentError)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |