Extract class from CSP configuration/initialization (#26905)
This commit is contained in:
		
							parent
							
								
									2e6bf60f15
								
							
						
					
					
						commit
						eae5c7334a
					
				
							
								
								
									
										59
									
								
								app/lib/content_security_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/lib/content_security_policy.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | class ContentSecurityPolicy | ||||||
|  |   def base_host | ||||||
|  |     Rails.configuration.x.web_domain | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def assets_host | ||||||
|  |     url_from_configured_asset_host || url_from_base_host | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def media_host | ||||||
|  |     cdn_host_value || assets_host | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def url_from_configured_asset_host | ||||||
|  |     Rails.configuration.action_controller.asset_host | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def cdn_host_value | ||||||
|  |     s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def url_from_base_host | ||||||
|  |     host_to_url(base_host) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def host_to_url(host_string) | ||||||
|  |     uri_from_configuration_and_string(host_string) if host_string.present? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def s3_alias_host | ||||||
|  |     host_to_url ENV.fetch('S3_ALIAS_HOST', nil) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def s3_cloudfront_host | ||||||
|  |     host_to_url ENV.fetch('S3_CLOUDFRONT_HOST', nil) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def azure_alias_host | ||||||
|  |     host_to_url ENV.fetch('AZURE_ALIAS_HOST', nil) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def s3_hostname_host | ||||||
|  |     host_to_url ENV.fetch('S3_HOSTNAME', nil) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def uri_from_configuration_and_string(host_string) | ||||||
|  |     Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri| | ||||||
|  |       uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/') | ||||||
|  |     end.to_s | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def host_protocol | ||||||
|  |     Rails.configuration.x.use_https ? 'https' : 'http' | ||||||
|  |   end | ||||||
|  | end | ||||||
| @ -6,24 +6,11 @@ | |||||||
| # See the Securing Rails Applications Guide for more information: | # See the Securing Rails Applications Guide for more information: | ||||||
| # https://guides.rubyonrails.org/security.html#content-security-policy-header | # https://guides.rubyonrails.org/security.html#content-security-policy-header | ||||||
| 
 | 
 | ||||||
| def host_to_url(str) | require_relative '../../app/lib/content_security_policy' | ||||||
|   return if str.blank? |  | ||||||
| 
 | 
 | ||||||
|   uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}") | policy = ContentSecurityPolicy.new | ||||||
|   uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/') | assets_host = policy.assets_host | ||||||
|   uri.to_s | media_host = policy.media_host | ||||||
| end |  | ||||||
| 
 |  | ||||||
| base_host = Rails.configuration.x.web_domain |  | ||||||
| 
 |  | ||||||
| assets_host   = Rails.configuration.action_controller.asset_host |  | ||||||
| assets_host ||= host_to_url(base_host) |  | ||||||
| 
 |  | ||||||
| media_host   = host_to_url(ENV['S3_ALIAS_HOST']) |  | ||||||
| media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST']) |  | ||||||
| media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST']) |  | ||||||
| media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true' |  | ||||||
| media_host ||= assets_host |  | ||||||
| 
 | 
 | ||||||
| def sso_host | def sso_host | ||||||
|   return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' |   return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' | ||||||
|  | |||||||
							
								
								
									
										129
									
								
								spec/lib/content_security_policy_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								spec/lib/content_security_policy_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | |||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | describe ContentSecurityPolicy do | ||||||
|  |   subject { described_class.new } | ||||||
|  | 
 | ||||||
|  |   around do |example| | ||||||
|  |     original_asset_host = Rails.configuration.action_controller.asset_host | ||||||
|  |     original_web_domain = Rails.configuration.x.web_domain | ||||||
|  |     original_use_https = Rails.configuration.x.use_https | ||||||
|  |     example.run | ||||||
|  |     Rails.configuration.action_controller.asset_host = original_asset_host | ||||||
|  |     Rails.configuration.x.web_domain = original_web_domain | ||||||
|  |     Rails.configuration.x.use_https = original_use_https | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#base_host' do | ||||||
|  |     before { Rails.configuration.x.web_domain = 'host.example' } | ||||||
|  | 
 | ||||||
|  |     it 'returns the configured value for the web domain' do | ||||||
|  |       expect(subject.base_host).to eq 'host.example' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#assets_host' do | ||||||
|  |     context 'when asset_host is not configured' do | ||||||
|  |       before { Rails.configuration.action_controller.asset_host = nil } | ||||||
|  | 
 | ||||||
|  |       context 'with a configured web domain' do | ||||||
|  |         before { Rails.configuration.x.web_domain = 'host.example' } | ||||||
|  | 
 | ||||||
|  |         context 'when use_https is enabled' do | ||||||
|  |           before { Rails.configuration.x.use_https = true } | ||||||
|  | 
 | ||||||
|  |           it 'returns value from base host with https protocol' do | ||||||
|  |             expect(subject.assets_host).to eq 'https://host.example' | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         context 'when use_https is disabled' do | ||||||
|  |           before { Rails.configuration.x.use_https = false } | ||||||
|  | 
 | ||||||
|  |           it 'returns value from base host with http protocol' do | ||||||
|  |             expect(subject.assets_host).to eq 'http://host.example' | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when asset_host is configured' do | ||||||
|  |       before do | ||||||
|  |         Rails.configuration.action_controller.asset_host = 'https://assets.host.example' | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns full value from configured host' do | ||||||
|  |         expect(subject.assets_host).to eq 'https://assets.host.example' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#media_host' do | ||||||
|  |     context 'when there is no configured CDN' do | ||||||
|  |       it 'defaults to using the assets_host value' do | ||||||
|  |         expect(subject.media_host).to eq(subject.assets_host) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when an S3 alias host is configured' do | ||||||
|  |       around do |example| | ||||||
|  |         ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example' do | ||||||
|  |           example.run | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses the s3 alias host value' do | ||||||
|  |         expect(subject.media_host).to eq 'https://asset-host.s3-alias.example' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when an S3 alias host with a trailing path is configured' do | ||||||
|  |       around do |example| | ||||||
|  |         ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example/pathname' do | ||||||
|  |           example.run | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses the s3 alias host value and preserves the path' do | ||||||
|  |         expect(subject.media_host).to eq 'https://asset-host.s3-alias.example/pathname/' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when an S3 cloudfront host is configured' do | ||||||
|  |       around do |example| | ||||||
|  |         ClimateControl.modify S3_CLOUDFRONT_HOST: 'asset-host.s3-cloudfront.example' do | ||||||
|  |           example.run | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses the s3 cloudfront host value' do | ||||||
|  |         expect(subject.media_host).to eq 'https://asset-host.s3-cloudfront.example' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when an azure alias host is configured' do | ||||||
|  |       around do |example| | ||||||
|  |         ClimateControl.modify AZURE_ALIAS_HOST: 'asset-host.azure-alias.example' do | ||||||
|  |           example.run | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses the azure alias host value' do | ||||||
|  |         expect(subject.media_host).to eq 'https://asset-host.azure-alias.example' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when s3_enabled is configured' do | ||||||
|  |       around do |example| | ||||||
|  |         ClimateControl.modify S3_ENABLED: 'true', S3_HOSTNAME: 'asset-host.s3.example' do | ||||||
|  |           example.run | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'uses the s3 hostname host value' do | ||||||
|  |         expect(subject.media_host).to eq 'https://asset-host.s3.example' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user