diff --git a/app/models/active_session.rb b/app/models/active_session.rb index 2eb9c9bca7f24730c3de04caf629006261b51368..4ee04a3d62d2dc571332f14fd9e7963de3245e61 100644 --- a/app/models/active_session.rb +++ b/app/models/active_session.rb @@ -25,11 +25,17 @@ class ActiveSession SESSION_BATCH_SIZE = 200 ALLOWED_NUMBER_OF_ACTIVE_SESSIONS = 100 - attr_accessor :ip_address, :browser, :os, + ATTR_ACCESSOR_LIST = [ + :ip_address, :browser, :os, :device_name, :device_type, :is_impersonated, :session_id, :session_private_id + ].freeze + ATTR_READER_LIST = [ + :created_at, :updated_at + ].freeze - attr_reader :created_at, :updated_at + attr_accessor(*ATTR_ACCESSOR_LIST) + attr_reader(*ATTR_READER_LIST) def created_at=(time) @created_at = time.is_a?(String) ? Time.zone.parse(time) : time @@ -240,6 +246,8 @@ def dump if raw_session.start_with?('v2:') session_data = Gitlab::Json.parse(raw_session[3..]).symbolize_keys + # load only known attributes + session_data.slice!(*ATTR_ACCESSOR_LIST.union(ATTR_READER_LIST)) new(**session_data) else # Deprecated legacy format. To be removed in 15.0 diff --git a/lib/gitlab/auth/current_user_mode.rb b/lib/gitlab/auth/current_user_mode.rb index 9bd4711c4bbf16bf3c5993d76e90d07160b01c42..4dd808182ec7ed77b2d35dd0b99980f257cc5754 100644 --- a/lib/gitlab/auth/current_user_mode.rb +++ b/lib/gitlab/auth/current_user_mode.rb @@ -8,6 +8,7 @@ module Auth # an administrator must have explicitly enabled admin-mode # e.g. on web access require re-authentication class CurrentUserMode + include Gitlab::Utils::StrongMemoize NotRequestedError = Class.new(StandardError) # RequestStore entries @@ -85,8 +86,9 @@ def current_admin end end - def initialize(user) + def initialize(user, session = Gitlab::Session.current) @user = user + @session = session end def admin_mode? @@ -138,6 +140,11 @@ def request_admin_mode! current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = Time.now end + def current_session_data + Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY, @session) + end + strong_memoize_attr :current_session_data + private attr_reader :user @@ -152,10 +159,6 @@ def admin_mode_requested_rs_key @admin_mode_requested_rs_key ||= { res: :current_user_mode, user: user.id, method: :admin_mode_requested? } end - def current_session_data - @current_session ||= Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY) - end - def session_with_admin_mode? return true if bypass_session? diff --git a/spec/features/user_settings/active_sessions_spec.rb b/spec/features/user_settings/active_sessions_spec.rb index bc0693d79e1f820b6d59cbca930af602bd56b35b..bb3ad718173ca3fed4a3d62ff8a306fb26013f02 100644 --- a/spec/features/user_settings/active_sessions_spec.rb +++ b/spec/features/user_settings/active_sessions_spec.rb @@ -110,4 +110,20 @@ expect(page).to have_content('You need to sign in or sign up before continuing.') end end + + it 'load_raw_session does load known attributes only' do + new_session = ActiveSession.send(:load_raw_session, + 'v2:{"ip_address": "127.0.0.1", "browser": "Firefox", "os": "Debian",' \ + '"device_type": "desktop", "session_id": "8f62cc7383c",' \ + '"new_attribute": "unknown attribute"}' + ) + + expect(new_session).to have_attributes( + ip_address: "127.0.0.1", + browser: "Firefox", + os: "Debian", + device_type: "desktop", + session_id: "8f62cc7383c" + ) + end end diff --git a/spec/lib/gitlab/auth/current_user_mode_spec.rb b/spec/lib/gitlab/auth/current_user_mode_spec.rb index 650af6af22961c691f58105147086e2f774cf533..014c812d9eea4a1e26299fe6e270ce6d468b03ef 100644 --- a/spec/lib/gitlab/auth/current_user_mode_spec.rb +++ b/spec/lib/gitlab/auth/current_user_mode_spec.rb @@ -7,6 +7,55 @@ 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'