vinistock / sail

Sail is a lightweight Rails engine that brings an admin panel for managing configuration settings on a live Rails app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issues with sessions when using `redis_store` and custom session key names

lavilet opened this issue · comments

Describe the bug
Hey guys 👋 . Recently we've migrated from using ActiveRecord Session Store (https://github.com/rails/activerecord-session_store) to redis_store (https://github.com/redis-store/redis-actionpack). After this change our Sail Dashboard stopped working:

Zrzut ekranu 2022-04-28 o 10 00 48

When debugging from within Sails:

[1] pry(#<Sail::SettingsController>)> session.options
=> #<ActionDispatch::Request::Session::Options:0x00007fa5b36098b0
 @by=
  #<ActionDispatch::Session::RedisStore:0x00007fa593577a48
   @app=#<ActionDispatch::Routing::RouteSet:0x00007fa571addf18>,
   @conn=
    #<Redis::Rack::Connection:0x00007fa5935771b0
     @options=
      {:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :redis_server=>nil},
     @pool=nil,
     @pooled=false,
     @store=#<Redis client v4.6.0 for redis://0.0.0.0:6379/0>>,
   @cookie_only=true,
   @default_options=
    {:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :redis_server=>nil},
   @key="_session_id",
   @mutex=#<Thread::Mutex:0x00007fa5935771d8>,
   @same_site=nil>,
 @delegate=
  {:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :redis_server=>nil}>

What I've noticed - the session key ("_session_id") looks like kind of a default key - in our configuration we are using different key name, so when we would try to fetch sesssion.id we'll get nil, because parent app stores session under different key.

When I've updated this line

config.middleware.use Rails.application.config.session_store || ActionDispatch::Session::CookieStore
to

if Rails.application.config.session_store.nil?
 config.middleware.use ActionDispatch::Session::CookieStore
end

Everything works as expected - dashboard loads, and when debugging and checking whats inside session object:

=> #<ActionDispatch::Request::Session::Options:0x00007fb952e3a720
 @by=
  #<ActionDispatch::Session::RedisStore:0x00007fb9e2a5fa98
   @app=
    #<ActionDispatch::ContentSecurityPolicy::Middleware:0x00007fb9e2a5fcc8
     @app=
      #<Rack::Head:0x00007fb9e2a5fed0
       @app=
        #<Rack::ConditionalGet:0x00007fb9e2a5ff48
         @app=
          #<Rack::ETag:0x00007fb9e2a54008
           @app=
            #<Rack::TempfileReaper:0x00007fb9e2a54058
             @app=
              #<Warden::Manager:0x00007fb9e2a54170
               @app=
                #<ApolloUploadServer::Middleware:0x00007fb9e2a541c0
                 @app=
                  #<Warden::JWTAuth::Middleware:0x00007fb9e2a54210
                   @app=#<Bullet::Rack:0x00007fb9e2a54260 @app=#<ActionDispatch::Routing::RouteSet:0x00007fb984297210>>>>,
               @config=
                {:default_scope=>:account,
                 :scope_defaults=>{},
                 :default_strategies=>
                  {:account=>[:jwt, :database_authenticatable],
                   ...},
                 :intercept_401=>false,
                 :failure_app=>#<Devise::Delegator:0x00007fb98468e3f0>}>>,
           @cache_control="max-age=0, private, must-revalidate",
           @no_cache_control="no-cache">>>>,
   @conn=
    #<Redis::Rack::Connection:0x00007fb9e2a5f368
     @options=
      {:path=>"/",
       :domain=>nil,
       :expire_after=>1 minute,
       :secure=>false,
       :httponly=>true,
       :defer=>false,
       :renew=>false,
       :redis_server=>["redis://0.0.0.0:6379/0/session"],
       :servers=>["redis://0.0.0.0:6379/0/session"],
       :threadsafe=>true},
     @pool=nil,
     @pooled=false,
     @store=#<Redis client v4.6.0 for redis://0.0.0.0:6379/0>>,
   @cookie_only=true,
   @default_options=
    {:path=>"/",
     :domain=>nil,
     :expire_after=>1 minute,
     :secure=>false,
     :httponly=>true,
     :defer=>false,
     :renew=>false,
     :redis_server=>["redis://0.0.0.0:6379/0/session"],
     :servers=>["redis://0.0.0.0:6379/0/session"],
     :threadsafe=>true},
   @key="_hub_session",
   @mutex=#<Thread::Mutex:0x00007fb9e2a5f390>,
   @same_site=nil>,
 @delegate=
  {:path=>"/",
   :domain=>nil,
   :expire_after=>1 minute,
   :secure=>false,
   :httponly=>true,
   :defer=>false,
   :renew=>false,
   :redis_server=>["redis://0.0.0.0:6379/0/session"],
   :servers=>["redis://0.0.0.0:6379/0/session"],
   :threadsafe=>true,
   :id=>"7f9d96ee441b7b418f5f2573263fa03c"}>
[7] pry(#<Sail::SettingsController>)>

So here I can see way more details and options, also the key matches the one we've configured ("_hub_session"). Looks like when we are adding a middleware in after_initialize block it somehow overrides some of the configs from the base/parent app 🤔 .

Environment
Gemfile

source 'https://rubygems.org'

ruby '2.7.6'
gem 'rails', '~> 6.0.0'
gem 'redis-actionpack'
gem 'sail'
...

To Reproduce
Steps to reproduce the behavior:
Install 'redis-actionpack' gem,
create app/initializers/session_store.rb

opts = {
    key: '_hub_session',
    servers: ['redis_url'],
    expire_after: 1.hour,
    threadsafe: true,
    secure: !(Rails.env.development? || Rails.env.test?)
  }
  Rails.application.config.session_store :redis_store, opts

routes:

...
authenticate :user, ->(u) { u.admin? } do
    mount Sail::Engine => '/sail'
...

Login and visit localhost:3000/sail

Expected behavior
User should see a Sail Dashboard

Actual behavior
User sees an error page.