From a496aeabcb28b7cc7d8a9e69bf47543c2be038c2 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 12 Sep 2024 15:24:19 +0200 Subject: [PATCH] Change form-action Content-Security-Policy directive to be more restrictive (#26897) --- .../concerns/web_app_controller_concern.rb | 10 +++++++++ app/lib/content_security_policy.rb | 16 ++++++++++++++ .../initializers/content_security_policy.rb | 22 ++----------------- spec/requests/content_security_policy_spec.rb | 2 +- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/app/controllers/concerns/web_app_controller_concern.rb b/app/controllers/concerns/web_app_controller_concern.rb index b8c909877..e1f599dcb 100644 --- a/app/controllers/concerns/web_app_controller_concern.rb +++ b/app/controllers/concerns/web_app_controller_concern.rb @@ -8,6 +8,16 @@ module WebAppControllerConcern before_action :redirect_unauthenticated_to_permalinks! before_action :set_app_body_class + + content_security_policy do |p| + policy = ContentSecurityPolicy.new + + if policy.sso_host.present? + p.form_action policy.sso_host + else + p.form_action :none + end + end end def skip_csrf_meta_tags? diff --git a/app/lib/content_security_policy.rb b/app/lib/content_security_policy.rb index 210f37cea..0b60b0d98 100644 --- a/app/lib/content_security_policy.rb +++ b/app/lib/content_security_policy.rb @@ -13,6 +13,22 @@ class ContentSecurityPolicy [assets_host, cdn_host_value, paperclip_root_url].compact end + def sso_host + return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1 + + provider = Devise.omniauth_configs[Devise.omniauth_providers[0]] + @sso_host ||= begin + case provider.provider + when :cas + provider.cas_url + when :saml + provider.options[:idp_sso_target_url] + when :openid_connect + provider.options.dig(:client_options, :authorization_endpoint) || OpenIDConnect::Discovery::Provider::Config.discover!(provider.options[:issuer]).authorization_endpoint + end + end + end + private def url_from_configured_asset_host diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 7f34d93ee..9f4a41e3a 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -12,24 +12,6 @@ policy = ContentSecurityPolicy.new assets_host = policy.assets_host media_hosts = policy.media_hosts -def sso_host - return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' - return unless ENV['OMNIAUTH_ONLY'] == 'true' - return unless Devise.omniauth_providers.length == 1 - - provider = Devise.omniauth_configs[Devise.omniauth_providers[0]] - @sso_host ||= begin - case provider.provider - when :cas - provider.cas_url - when :saml - provider.options[:idp_sso_target_url] - when :openid_connect - provider.options.dig(:client_options, :authorization_endpoint) || OpenIDConnect::Discovery::Provider::Config.discover!(provider.options[:issuer]).authorization_endpoint - end - end -end - Rails.application.config.content_security_policy do |p| p.base_uri :none p.default_src :none @@ -40,8 +22,8 @@ Rails.application.config.content_security_policy do |p| p.media_src :self, :data, *media_hosts p.manifest_src :self, assets_host - if sso_host.present? - p.form_action :self, sso_host + if policy.sso_host.present? + p.form_action :self, policy.sso_host else p.form_action :self end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 7520ecb0d..2bbbdd841 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Content-Security-Policy' do connect-src 'self' data: blob: https://cb6e6126.ngrok.io #{Rails.configuration.x.streaming_api_base_url} default-src 'none' font-src 'self' https://cb6e6126.ngrok.io - form-action 'self' + form-action 'none' frame-ancestors 'none' frame-src 'self' https: img-src 'self' data: blob: https://cb6e6126.ngrok.io