diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 02fc4912f94d91937e2c137fcb341655e899c09d..75328dcd891a42bbfb3f5185ca5a9a277d637707 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -19,15 +19,31 @@ "_gitlab_session" end -sessions_config = Gitlab::Redis::SharedState.params -sessions_config[:namespace] = Gitlab::Redis::SharedState::SESSION_NAMESPACE +if Gitlab::Utils.to_boolean(ENV['GITLAB_REDIS_STORE_WITH_SESSION_STORE'], default: true) + store = Gitlab::Redis::SharedState.store( + namespace: Gitlab::Redis::SharedState::SESSION_NAMESPACE + ) -Gitlab::Application.config.session_store( - :redis_store, # Using the cookie_store would enable session replay attacks. - servers: sessions_config, - key: cookie_key, - secure: Gitlab.config.gitlab.https, - httponly: true, - expires_in: Settings.gitlab['session_expire_delay'] * 60, - path: Rails.application.config.relative_url_root.presence || '/' -) + Gitlab::Application.config.session_store( + :redis_store, # Using the cookie_store would enable session replay attacks. + redis_store: store, + key: cookie_key, + secure: Gitlab.config.gitlab.https, + httponly: true, + expires_in: Settings.gitlab['session_expire_delay'] * 60, + path: Rails.application.config.relative_url_root.presence || '/' + ) +else + sessions_config = Gitlab::Redis::SharedState.params + sessions_config[:namespace] = Gitlab::Redis::SharedState::SESSION_NAMESPACE + + Gitlab::Application.config.session_store( + :redis_store, # Using the cookie_store would enable session replay attacks. + servers: sessions_config, + key: cookie_key, + secure: Gitlab.config.gitlab.https, + httponly: true, + expires_in: Settings.gitlab['session_expire_delay'] * 60, + path: Rails.application.config.relative_url_root.presence || '/' + ) +end diff --git a/lib/gitlab/redis/wrapper.rb b/lib/gitlab/redis/wrapper.rb index 7b8040381468c6c8adb443949f1c12e6ea78d1bc..985c8dc619cad9f5f0e8cbe4b66caed8f68a5a4c 100644 --- a/lib/gitlab/redis/wrapper.rb +++ b/lib/gitlab/redis/wrapper.rb @@ -17,7 +17,7 @@ module Gitlab module Redis class Wrapper class << self - delegate :params, :url, to: :new + delegate :params, :url, :store, to: :new def with pool.with { |redis| yield redis } @@ -126,6 +126,10 @@ def sentinels? sentinels && !sentinels.empty? end + def store(extras = {}) + ::Redis::Store::Factory.create(redis_store_options.merge(extras)) + end + private def redis_store_options diff --git a/spec/initializers/session_store_spec.rb b/spec/initializers/session_store_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3da52ccc9813a42ecd349679e63993864b7e15eb --- /dev/null +++ b/spec/initializers/session_store_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Session initializer for GitLab' do + subject { Gitlab::Application.config } + + let(:load_session_store) do + load Rails.root.join('config/initializers/session_store.rb') + end + + describe 'config#session_store' do + context 'when the GITLAB_REDIS_STORE_WITH_SESSION_STORE env is not set' do + before do + stub_env('GITLAB_REDIS_STORE_WITH_SESSION_STORE', nil) + end + + it 'initialized as a redis_store with a proper Redis::Store instance' do + expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(redis_store: kind_of(::Redis::Store))) + + load_session_store + end + end + + context 'when the GITLAB_REDIS_STORE_WITH_SESSION_STORE env is disabled' do + before do + stub_env('GITLAB_REDIS_STORE_WITH_SESSION_STORE', false) + end + + it 'initialized as a redis_store with a proper servers configuration' do + expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(servers: kind_of(Hash))) + + load_session_store + end + end + end +end diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb index dd916aea3e8805775c9d89f0e69476d06142fce3..72b3a72f9d40d9763dd5ba3b376e80e252c290d2 100644 --- a/spec/support/redis/redis_shared_examples.rb +++ b/spec/support/redis/redis_shared_examples.rb @@ -87,6 +87,43 @@ end end + describe '.store' do + let(:rails_env) { 'development' } + + subject { described_class.new(rails_env).store } + + shared_examples 'redis store' do + it 'instantiates Redis::Store' do + is_expected.to be_a(::Redis::Store) + expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database}") + end + + context 'with the namespace' do + let(:namespace) { 'namespace_name' } + + subject { described_class.new(rails_env).store(namespace: namespace) } + + it "uses specified namespace" do + expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database} with namespace #{namespace}") + end + end + end + + context 'with old format' do + it_behaves_like 'redis store' do + let(:config_file_name) { config_old_format_host } + let(:host) { "localhost:#{redis_port}" } + end + end + + context 'with new format' do + it_behaves_like 'redis store' do + let(:config_file_name) { config_new_format_host } + let(:host) { "development-host:#{redis_port}" } + end + end + end + describe '.params' do subject { described_class.new(rails_env).params }