Merge pull request #6113 from consuldemocracy/saml_on_demand

Only access SAML single sign-on URL when necessary
This commit is contained in:
Javi Martín
2025-10-22 15:17:04 +02:00
committed by GitHub
3 changed files with 30 additions and 26 deletions

View File

@@ -42,21 +42,28 @@ module OmniauthTenantSetup
end end
def saml_auth(env, sp_entity_id, idp_metadata_url, idp_sso_service_url) def saml_auth(env, sp_entity_id, idp_metadata_url, idp_sso_service_url)
unless Tenant.default? env["omniauth.strategy"].options.merge!(
strategy = env["omniauth.strategy"] saml_settings(sp_entity_id, idp_metadata_url, idp_sso_service_url)
)
strategy.options[:sp_entity_id] = sp_entity_id if sp_entity_id.present?
strategy.options[:idp_metadata_url] = idp_metadata_url if idp_metadata_url.present?
strategy.options[:idp_sso_service_url] = idp_sso_service_url if idp_sso_service_url.present?
if strategy.options[:issuer].present? && sp_entity_id.present?
strategy.options[:issuer] = sp_entity_id
end end
if strategy.options[:idp_metadata].present? && idp_metadata_url.present? def saml_settings(sp_entity_id, idp_metadata_url, idp_sso_service_url)
strategy.options[:idp_metadata] = idp_metadata_url remote_saml_settings(idp_metadata_url).tap do |settings|
settings[:sp_entity_id] = sp_entity_id if sp_entity_id.present?
settings[:idp_sso_service_url] = idp_sso_service_url if idp_sso_service_url.present?
settings[:allowed_clock_drift] = 1.minute
end end
end end
def remote_saml_settings(idp_metadata_url)
return {} if idp_metadata_url.blank?
@remote_saml_settings ||= {}
@remote_saml_settings[idp_metadata_url] ||= parsed_saml_metadata(idp_metadata_url)
end
def parsed_saml_metadata(idp_metadata_url)
OneLogin::RubySaml::IdpMetadataParser.new.parse_remote_to_hash(idp_metadata_url)
end end
def oidc_auth(env, client_id, client_secret, issuer) def oidc_auth(env, client_id, client_secret, issuer)

View File

@@ -286,16 +286,7 @@ Devise.setup do |config|
Rails.application.secrets.wordpress_oauth2_secret, Rails.application.secrets.wordpress_oauth2_secret,
client_options: { site: Rails.application.secrets.wordpress_oauth2_site }, client_options: { site: Rails.application.secrets.wordpress_oauth2_site },
setup: ->(env) { OmniauthTenantSetup.wordpress_oauth2(env) } setup: ->(env) { OmniauthTenantSetup.wordpress_oauth2(env) }
saml_settings = {} config.omniauth :saml, setup: ->(env) { OmniauthTenantSetup.saml(env) }
if Rails.application.secrets.saml_idp_metadata_url.present?
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
saml_settings = idp_metadata_parser.parse_remote_to_hash(Rails.application.secrets.saml_idp_metadata_url)
saml_settings[:idp_sso_service_url] = Rails.application.secrets.saml_idp_sso_service_url
saml_settings[:sp_entity_id] = Rails.application.secrets.saml_sp_entity_id
saml_settings[:allowed_clock_drift] = 1.minute
end
config.omniauth :saml, saml_settings.merge(setup: ->(env) { OmniauthTenantSetup.saml(env) })
config.omniauth :openid_connect, config.omniauth :openid_connect,
name: :oidc, name: :oidc,
scope: [:openid, :email, :profile], scope: [:openid, :email, :profile],

View File

@@ -2,6 +2,12 @@ require "rails_helper"
describe OmniauthTenantSetup do describe OmniauthTenantSetup do
describe "#saml" do describe "#saml" do
before do
allow(OmniauthTenantSetup).to receive(:parsed_saml_metadata) do |idp_metadata_url|
{ idp_entity_id: idp_metadata_url.gsub("metadata", "entityid") }
end
end
it "uses different secrets for different tenants" do it "uses different secrets for different tenants" do
create(:tenant, schema: "mars") create(:tenant, schema: "mars")
create(:tenant, schema: "venus") create(:tenant, schema: "venus")
@@ -34,8 +40,8 @@ describe OmniauthTenantSetup do
mars_strategy_options = mars_env["omniauth.strategy"].options mars_strategy_options = mars_env["omniauth.strategy"].options
expect(mars_strategy_options[:sp_entity_id]).to eq "https://mars.consul.dev/saml/metadata" expect(mars_strategy_options[:sp_entity_id]).to eq "https://mars.consul.dev/saml/metadata"
expect(mars_strategy_options[:idp_metadata_url]).to eq "https://mars-idp.example.com/metadata"
expect(mars_strategy_options[:idp_sso_service_url]).to eq "https://mars-idp.example.com/sso" expect(mars_strategy_options[:idp_sso_service_url]).to eq "https://mars-idp.example.com/sso"
expect(mars_strategy_options[:idp_entity_id]).to eq "https://mars-idp.example.com/entityid"
end end
Tenant.switch("venus") do Tenant.switch("venus") do
@@ -48,8 +54,8 @@ describe OmniauthTenantSetup do
venus_strategy_options = venus_env["omniauth.strategy"].options venus_strategy_options = venus_env["omniauth.strategy"].options
expect(venus_strategy_options[:sp_entity_id]).to eq "https://venus.consul.dev/saml/metadata" expect(venus_strategy_options[:sp_entity_id]).to eq "https://venus.consul.dev/saml/metadata"
expect(venus_strategy_options[:idp_metadata_url]).to eq "https://venus-idp.example.com/metadata"
expect(venus_strategy_options[:idp_sso_service_url]).to eq "https://venus-idp.example.com/sso" expect(venus_strategy_options[:idp_sso_service_url]).to eq "https://venus-idp.example.com/sso"
expect(venus_strategy_options[:idp_entity_id]).to eq "https://venus-idp.example.com/entityid"
end end
end end
@@ -79,8 +85,8 @@ describe OmniauthTenantSetup do
earth_strategy_options = earth_env["omniauth.strategy"].options earth_strategy_options = earth_env["omniauth.strategy"].options
expect(earth_strategy_options[:sp_entity_id]).to eq "https://default.consul.dev/saml/metadata" expect(earth_strategy_options[:sp_entity_id]).to eq "https://default.consul.dev/saml/metadata"
expect(earth_strategy_options[:idp_metadata_url]).to eq "https://default-idp.example.com/metadata"
expect(earth_strategy_options[:idp_sso_service_url]).to eq "https://default-idp.example.com/sso" expect(earth_strategy_options[:idp_sso_service_url]).to eq "https://default-idp.example.com/sso"
expect(earth_strategy_options[:idp_entity_id]).to eq "https://default-idp.example.com/entityid"
end end
end end
end end