diff --git a/lib/auth/default_current_user_provider.rb b/lib/auth/default_current_user_provider.rb index f20b056b2ca..30a8ff8152f 100644 --- a/lib/auth/default_current_user_provider.rb +++ b/lib/auth/default_current_user_provider.rb @@ -359,6 +359,10 @@ class Auth::DefaultCurrentUserProvider private + def parameter_api_patterns + PARAMETER_API_PATTERNS + DiscoursePluginRegistry.api_parameter_routes + end + # By default we only allow headers for sending API credentials # However, in some scenarios it is essential to send them via url parameters # so we need to add some exceptions @@ -369,7 +373,7 @@ class Auth::DefaultCurrentUserProvider path_params = @env['action_dispatch.request.path_parameters'] request_route = "#{path_params[:controller]}##{path_params[:action]}" if path_params - PARAMETER_API_PATTERNS.any? do |p| + parameter_api_patterns.any? do |p| (p[:method] == "*" || Array(p[:method]).include?(request_method)) && (p[:format] == "*" || Array(p[:format]).include?(request_format)) && (p[:route] == "*" || Array(p[:route]).include?(request_route)) diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb index 335d102fd70..93e2c117f30 100644 --- a/lib/discourse_plugin_registry.rb +++ b/lib/discourse_plugin_registry.rb @@ -79,6 +79,7 @@ class DiscoursePluginRegistry define_filtered_register :topic_thumbnail_sizes + define_filtered_register :api_parameter_routes define_filtered_register :api_key_scope_mappings def self.register_auth_provider(auth_provider) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 0ca72b1e6e3..e0dec5ff24e 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -782,6 +782,21 @@ class Plugin::Instance DiscoursePluginRegistry.register_api_key_scope_mapping({ resource => action }, self) end + # Register a route which can be authenticated using an api key or user api key + # in a query parameter rather than a header. For example: + # + # add_api_parameter_route( + # method: :get, + # route: "users#bookmarks", + # format: :ics + # ) + # + # See Auth::DefaultCurrentUserProvider::PARAMETER_API_PATTERNS for more examples + # and Auth::DefaultCurrentUserProvider#api_parameter_allowed? for implementation + def add_api_parameter_route(method:, route:, format:) + DiscoursePluginRegistry.register_api_parameter_route({ method: method, route: route, format: format }, self) + end + protected def self.js_path diff --git a/spec/integration/api_keys_spec.rb b/spec/integration/api_keys_spec.rb index 451768718fc..d74378c7e45 100644 --- a/spec/integration/api_keys_spec.rb +++ b/spec/integration/api_keys_spec.rb @@ -48,6 +48,19 @@ describe 'api keys' do expect(response.status).to eq(302) end + context "with a plugin registered filter" do + before do + plugin = Plugin::Instance.new + plugin.add_api_parameter_route method: :get, route: "session#current", format: "*" + end + + it 'allows parameter access to the registered route' do + get '/session/current.json', params: { + api_key: api_key.key + } + expect(response.status).to eq(200) + end + end end describe 'user api keys' do