From 365fa1950f7b975ae6224e2879e4e0ccb367ee75 Mon Sep 17 00:00:00 2001 From: Joe Rafaniello Date: Mon, 24 Feb 2025 11:10:48 -0500 Subject: [PATCH] Set secret_key_base early enough for rails processes We don't use secret_key_base like vanilla rails. We implemented secrets through MiqPassword before any of this existed in rails. Our only things currently going through rails secrets perhaps is the provider vcr cassette information. Rails 7.1 asserts secret_key_base is now set and set during rails boot fairly early. So, now, we can't only set this for puma based workers, but all rails processes. We also, must move this logic to be done earlier during boot. It was found that after eager load allows us to leverage autoload and access the database, both are required in order to fetch the secrets from the database. Move over the logic for rails console so it can use a dummy secret key base. Move the tests to a vmdb/initializer test. Co-Authored-By: Jason Frey --- .../mixins/miq_web_server_worker_mixin.rb | 17 -------- config/application.rb | 5 +++ lib/vmdb/initializer.rb | 13 ++++-- spec/lib/vmdb/initializer_spec.rb | 41 +++++++++++++++++++ .../miq_web_server_worker_mixin_spec.rb | 37 ----------------- 5 files changed, 56 insertions(+), 57 deletions(-) create mode 100644 spec/lib/vmdb/initializer_spec.rb diff --git a/app/models/mixins/miq_web_server_worker_mixin.rb b/app/models/mixins/miq_web_server_worker_mixin.rb index 9a3459be310..8bc88696c7c 100644 --- a/app/models/mixins/miq_web_server_worker_mixin.rb +++ b/app/models/mixins/miq_web_server_worker_mixin.rb @@ -18,25 +18,8 @@ def binding_address BINDING_ADDRESS end - def preload_for_console - configure_secret_token(SecureRandom.hex(64)) - end - def preload_for_worker_role raise "Expected database to be seeded via `rake db:seed`." unless EvmDatabase.seeded_primordially? - - configure_secret_token - end - - def configure_secret_token(token = MiqDatabase.first.session_secret_token) - return if Rails.application.config.secret_key_base - - Rails.application.config.secret_key_base = token - - # To set a secret token after the Rails.application is initialized, - # we need to reset the secrets since they are cached: - # https://github.com/rails/rails/blob/7-0-stable/railties/lib/rails/application.rb#L392-L404 - Rails.application.secrets = nil if Rails.version < "7.1" end def rails_server diff --git a/config/application.rb b/config/application.rb index 2a875913791..b5f24677ab1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -209,6 +209,11 @@ class Application < Rails::Application end end + # Run after code is eager loaded so we can autoload MiqDatabase and ApplicationRecord + initializer :init_secret_token, :after => :eager_load! do + Vmdb::Initializer.init_secret_token + end + config.after_initialize do Vmdb::Initializer.init ActiveRecord::Base.connection_pool.release_connection diff --git a/lib/vmdb/initializer.rb b/lib/vmdb/initializer.rb index 1eae159f817..505a42a965d 100644 --- a/lib/vmdb/initializer.rb +++ b/lib/vmdb/initializer.rb @@ -12,11 +12,18 @@ def self.init MiqServer.my_server.starting_server_record MiqServer.my_server.update(:status => "started") end + end + + def self.init_secret_token + return if Rails.application.config.secret_key_base - # Rails console needs session store configured - if defined?(Rails::Console) - MiqUiWorker.preload_for_console + token = if ActiveRecord::Base.connectable? && MiqDatabase.any? + MiqDatabase.first.session_secret_token + else + SecureRandom.hex(64) end + + Rails.application.config.secret_key_base = token end private_class_method def self.log_db_connectable diff --git a/spec/lib/vmdb/initializer_spec.rb b/spec/lib/vmdb/initializer_spec.rb new file mode 100644 index 00000000000..5d992d9feff --- /dev/null +++ b/spec/lib/vmdb/initializer_spec.rb @@ -0,0 +1,41 @@ +RSpec.describe Vmdb::Initializer do + describe ".init_secret_token" do + before do + @token = Rails.application.secret_key_base + end + + after do + Rails.application.config.secret_key_base = @token + Rails.application.secrets = nil + end + + it "defaults to MiqDatabase session_secret_token" do + MiqDatabase.seed + Rails.application.config.secret_key_base = nil + Rails.application.secrets = nil + + described_class.init_secret_token + expect(Rails.application.secret_key_base).to eq(MiqDatabase.first.session_secret_token) + expect(Rails.application.config.secret_key_base).to eq(MiqDatabase.first.session_secret_token) + end + + it "uses random hex when MiqDatabase isn't seeded" do + Rails.application.config.secret_key_base = nil + Rails.application.secrets = nil + + described_class.init_secret_token + expect(Rails.application.secret_key_base).to match(/^\h{128}$/) + expect(Rails.application.config.secret_key_base).to match(/^\h{128}$/) + end + + it "does not reset secrets when token already configured" do + existing_value = SecureRandom.hex(64) + Rails.application.config.secret_key_base = existing_value + Rails.application.secrets = nil + + described_class.init_secret_token + expect(Rails.application.secret_key_base).to eq(existing_value) + expect(Rails.application.config.secret_key_base).to eq(existing_value) + end + end +end diff --git a/spec/models/mixins/miq_web_server_worker_mixin_spec.rb b/spec/models/mixins/miq_web_server_worker_mixin_spec.rb index e706c66ae6e..448c4f82633 100644 --- a/spec/models/mixins/miq_web_server_worker_mixin_spec.rb +++ b/spec/models/mixins/miq_web_server_worker_mixin_spec.rb @@ -14,43 +14,6 @@ end end - before do - @token = Rails.application.secret_key_base - MiqDatabase.seed - end - - after do - Rails.application.config.secret_key_base = @token - Rails.application.secrets = nil if Rails.version < "7.1" - end - - it ".configure_secret_token defaults to MiqDatabase session_secret_token" do - Rails.application.config.secret_key_base = nil - - test_class.configure_secret_token - expect(Rails.application.secret_key_base).to eq(MiqDatabase.first.session_secret_token) - expect(Rails.application.config.secret_key_base).to eq(MiqDatabase.first.session_secret_token) - end - - it ".configure_secret_token accepts an input token" do - Rails.application.config.secret_key_base = nil - - token = SecureRandom.hex(64) - test_class.configure_secret_token(token) - expect(Rails.application.secret_key_base).to eq(token) - expect(Rails.application.config.secret_key_base).to eq(token) - end - - it ".configure_secret_token does not reset secrets when token already configured" do - existing_value = SecureRandom.hex(64) - Rails.application.config.secret_key_base = existing_value - Rails.application.secrets = nil if Rails.version < "7.1" - - test_class.configure_secret_token - expect(Rails.application.secret_key_base).to eq(existing_value) - expect(Rails.application.config.secret_key_base).to eq(existing_value) - end - it "#rails_server_options" do w = FactoryBot.create(:miq_ui_worker, :uri => "http://127.0.0.1:3000") expect(w.rails_server_options).to include(