From ae77ad0d9555d44ba1ff8d4d8a66f2d726257608 Mon Sep 17 00:00:00 2001 From: Eric Richardson Date: Wed, 22 Jun 2016 16:30:21 -0400 Subject: [PATCH] Allow outside middleware to mark a request as authorized and bypass ACL check Add `authorized!(env)` and `authorized?(env)` to `Rails::Auth`. Outside middleware can use `authorized!` to mark a request as being exempt from the ACL check. Allows other authorization systems to play nicely on a per-request basis. --- lib/rails/auth/acl/middleware.rb | 2 +- lib/rails/auth/override.rb | 29 ++++++++++++++++++++++++++ lib/rails/auth/rack.rb | 2 ++ spec/rails/auth/acl/middleware_spec.rb | 20 ++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 lib/rails/auth/override.rb diff --git a/lib/rails/auth/acl/middleware.rb b/lib/rails/auth/acl/middleware.rb index 88a7906..cef6e88 100644 --- a/lib/rails/auth/acl/middleware.rb +++ b/lib/rails/auth/acl/middleware.rb @@ -22,7 +22,7 @@ def initialize(app, acl: nil) end def call(env) - raise NotAuthorizedError, "unauthorized request" unless @acl.match(env) + raise NotAuthorizedError, "unauthorized request" unless Rails::Auth.authorized?(env) || @acl.match(env) @app.call(env) end end diff --git a/lib/rails/auth/override.rb b/lib/rails/auth/override.rb new file mode 100644 index 0000000..ab397d1 --- /dev/null +++ b/lib/rails/auth/override.rb @@ -0,0 +1,29 @@ +module Rails + # Modular resource-based authentication and authorization for Rails/Rack + module Auth + # Rack environment key for marking external authorization + AUTHORIZED_ENV_KEY = "rails-auth.authorized".freeze + + # Functionality allowing external middleware to override our ACL check process + module Override + # Mark a request as externally authorized. Causes ACL checks to be skipped. + # + # @param [Hash] :env Rack environment + # + def authorized!(env) + env[AUTHORIZED_ENV_KEY] = true + end + + # Check whether a request has been externally authorized? Used to bypass + # ACL check. + # + # @param [Hash] :env Rack environment + # + def authorized?(env) + env.fetch(AUTHORIZED_ENV_KEY, false) + end + end + + extend Override + end +end diff --git a/lib/rails/auth/rack.rb b/lib/rails/auth/rack.rb index 1edb82a..8f8c7cd 100644 --- a/lib/rails/auth/rack.rb +++ b/lib/rails/auth/rack.rb @@ -8,6 +8,8 @@ require "rails/auth/exceptions" +require "rails/auth/override" + require "rails/auth/acl" require "rails/auth/acl/middleware" require "rails/auth/acl/resource" diff --git a/spec/rails/auth/acl/middleware_spec.rb b/spec/rails/auth/acl/middleware_spec.rb index 0fe6e2b..e0aac7a 100644 --- a/spec/rails/auth/acl/middleware_spec.rb +++ b/spec/rails/auth/acl/middleware_spec.rb @@ -21,4 +21,24 @@ expect { expect(middleware.call(request)) }.to raise_error(Rails::Auth::NotAuthorizedError) end end + + context "externally authorized requests" do + let(:authorized) { false } + let(:external_middleware) do + Class.new do + def initialize(app) + @app = app + end + + def call(env) + Rails::Auth.authorized!(env) + @app.call(env) + end + end + end + + it "allows externally authorized requests" do + expect(external_middleware.new(middleware).call(request)[0]).to eq 200 + end + end end