From 3fcf5a9d08a8903ec7f84de86c217c0fbf311602 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Mon, 22 Dec 2025 21:05:55 +0100 Subject: [PATCH] Require authorization for direct uploads Respond with 403 to JSON requests that are unauthorized, instead of redirecting. --- app/controllers/concerns/authorization.rb | 7 ++++- config/initializers/active_storage.rb | 1 + .../direct_uploads_controller_test.rb | 26 ++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/controllers/concerns/authorization.rb b/app/controllers/concerns/authorization.rb index 1afb878ef..f30d518cc 100644 --- a/app/controllers/concerns/authorization.rb +++ b/app/controllers/concerns/authorization.rb @@ -26,7 +26,12 @@ module Authorization end def ensure_can_access_account - redirect_to session_menu_path(script_name: nil) if Current.user.blank? || !Current.user.active? + if Current.user.blank? || !Current.user.active? + respond_to do |format| + format.html { redirect_to session_menu_path(script_name: nil) } + format.json { head :forbidden } + end + end end def redirect_existing_user diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index 5c83b18f5..3edd75cc8 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -40,6 +40,7 @@ module ActiveStorageDirectUploadsControllerExtensions included do include Authentication + include Authorization skip_forgery_protection if: :authenticate_by_bearer_token end end diff --git a/test/controllers/active_storage/direct_uploads_controller_test.rb b/test/controllers/active_storage/direct_uploads_controller_test.rb index cdb218be2..f52d34321 100644 --- a/test/controllers/active_storage/direct_uploads_controller_test.rb +++ b/test/controllers/active_storage/direct_uploads_controller_test.rb @@ -54,19 +54,33 @@ class ActiveStorage::DirectUploadsControllerTest < ActionDispatch::IntegrationTe test "create unauthenticated" do post rails_direct_uploads_path, - params: @blob_params.merge(authenticity_token: csrf_token), + params: @blob_params, as: :json assert_response :redirect end + test "create in another account is forbidden" do + sign_in_as :david + + post rails_direct_uploads_path(script_name: "/#{ActiveRecord::FixtureSet.identify("initech")}"), + params: @blob_params, + as: :json + + assert_response :forbidden + end + + test "create with valid access token in another account is forbidden" do + post rails_direct_uploads_path(script_name: "/#{ActiveRecord::FixtureSet.identify("initech")}"), + params: @blob_params, + headers: bearer_token_header(identity_access_tokens(:davids_api_token).token), + as: :json + + assert_response :forbidden + end + private def bearer_token_header(token) { "Authorization" => "Bearer #{token}" } end - - def csrf_token - get new_session_url - response.body[/name="csrf-token" content="([^"]+)"/, 1] - end end