diff --git a/app/controllers/links_controller.rb b/app/controllers/links_controller.rb index e7160ca8cdd..adb8d025853 100644 --- a/app/controllers/links_controller.rb +++ b/app/controllers/links_controller.rb @@ -1,5 +1,6 @@ class LinksController < ApplicationController skip_before_action :require_login, :authorize, :session_expiry, :update_activity_time, :set_taxonomy, :set_gettext_locale_db, :only => :show + before_action :validate_root_url def show url = external_url(type: params[:type], options: params) @@ -29,6 +30,16 @@ def external_url(type:, options: {}) private + def validate_root_url + unless params[:root_url].nil? + root_uri = URI.parse(params[:root_url]) + unless SETTINGS[:trusted_redirect_domains].include?(root_uri.host) || SETTINGS[:trusted_redirect_domains].any? { |d| root_uri.host.end_with?(".#{d}") } + logger.warn "Denied access to forbidden root_url: #{params[:root_url]}" + not_found + end + end + end + def foreman_org_path(sub_path) "https://theforeman.org/#{sub_path}" end diff --git a/config/settings.rb b/config/settings.rb index b2ef0be9ad5..a6f9632fb18 100644 --- a/config/settings.rb +++ b/config/settings.rb @@ -28,6 +28,8 @@ SETTINGS[:hosts] ||= [] +SETTINGS[:trusted_redirect_domains] ||= ['theforeman.org', 'redhat.com', 'orcharhino.com'].freeze + # Load plugin config, if any Dir["#{__dir__}/settings.plugins.d/*.yaml"].each do |f| SETTINGS.merge! YAML.load(ERB.new(File.read(f)).result) diff --git a/test/controllers/links_controller_test.rb b/test/controllers/links_controller_test.rb index 8d5fbb2b83d..33826b4ce3e 100644 --- a/test/controllers/links_controller_test.rb +++ b/test/controllers/links_controller_test.rb @@ -26,6 +26,37 @@ class LinksControllerTest < ActionController::TestCase assert_redirected_to /my_plugin/ end + test '#documentation_url receives an allowed root_url domain' do + ['theforeman.org', 'redhat.com', 'orcharhino.com'].each do |domain| + get :show, params: { + type: 'manual', + root_url: "http://#{domain}", + } + + assert_redirected_to /#{domain}/ + end + end + + test '#documentation_url receives an allowed root_url subdomain' do + ['theforeman.org', 'redhat.com', 'orcharhino.com'].each do |domain| + get :show, params: { + type: 'manual', + root_url: "http://some-sub.#{domain}", + } + + assert_redirected_to /some-sub.#{domain}/ + end + end + + test '#documentation_url receives a forbidden root_url option' do + get :show, params: { + type: 'manual', + root_url: 'http://www.example.invalid', + } + + assert_response :not_found + end + test '#plugin_documentation_url returns foreman docs url for a plugin with a version and a given section' do get :show, params: { type: 'plugin_manual',