From 48ec3e074687714d3421a3881e02078315b38d43 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 12 Mar 2016 15:30:37 -0800 Subject: [PATCH] Rails::Auth::ErrorPage::DebugMiddleware This middleware provides detailed debugging information about a request intended to simplify development, or for use debugging authorization problems in a staging environment. It displays what request was made, all of the credentials currently in the Rack environment, and all of the candidate ACL entries which match the current request. --- README.md | 42 +++++- images/debug_error_page.png | Bin 0 -> 23763 bytes lib/rails/auth/error_page/debug_middleware.rb | 58 ++++++++ lib/rails/auth/error_page/debug_page.html.erb | 128 ++++++++++++++++++ lib/rails/auth/rack.rb | 1 + .../auth/error_page/debug_middleware_spec.rb | 37 +++++ 6 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 images/debug_error_page.png create mode 100644 lib/rails/auth/error_page/debug_middleware.rb create mode 100644 lib/rails/auth/error_page/debug_page.html.erb create mode 100644 spec/rails/auth/error_page/debug_middleware_spec.rb diff --git a/README.md b/README.md index 4ffd881..4f2a29c 100644 --- a/README.md +++ b/README.md @@ -406,10 +406,46 @@ exception is raised up the middleware chain. However, it's likely you would prefer to show an error page than have an unhandled exception. You can write your own middleware that catches `Rails::Auth::NotAuthorizedError` -if you'd like. However, a default one is provided which renders a 403 response -with a static page body if you find that helpful. +if you'd like. However, this library includes two middleware for rescuing this +exception for you and displaying an error page. -To use it, add `Rails::Auth::ErrorPage::Middleware` to your app: +#### Rails::Auth::ErrorPage::DebugMiddleware + +This middleware displays a detailed error page intended to help debug authorization errors: + +![Debug Error Page](https://raw.github.com/square/rails-auth/master/images/debug_error_page.png) + +Please be aware this middleware leaks information about your ACL to a potential attacker. +Make sure you're ok with that information being public before using it. If you would like +to avoid leaking that information, see `Rails::Auth::ErrorPage::Middleware` below. + +```ruby +app = MyRackApp.new + +acl = Rails::Auth::ACL.from_yaml( + File.read("/path/to/my/acl.yaml") + matchers: { allow_x509_subject: Rails::Auth::X509::Matcher } +) + +acl_auth = Rails::Auth::ACL::Middleware.new(app, acl: acl) + +x509_auth = Rails::Auth::X509::Middleware.new( + acl_auth, + ca_file: "/path/to/my/cabundle.pem" + cert_filters: { 'X-SSL-Client-Cert' => :pem }, + require_cert: true +) + +error_page = Rails::Auth::ErrorPage::Middleware.new(x509_auth, acl: acl) + +run error_page +``` + +#### Rails::Auth::ErrorPage::Middleware + +This middleware catches `Rails::Auth::NotAuthorizedError` and renders a given static HTML file, +e.g. the 403.html file which ships with Rails. It will not give detailed errors to your users, +but it also won't leak information to an attacker. ```ruby app = MyRackApp.new diff --git a/images/debug_error_page.png b/images/debug_error_page.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf9ea123751afaa2d3c178344893a3b29df56f3 GIT binary patch literal 23763 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°iJ__VHkW^P_2I9}*GpVuPA)DN^JJEiVMsb;01 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 bk3;sXxh|UPmher-e`cy+EyXGY%i#Y4j$0Rw literal 0 HcmV?d00001 diff --git a/lib/rails/auth/error_page/debug_middleware.rb b/lib/rails/auth/error_page/debug_middleware.rb new file mode 100644 index 0000000..69ff806 --- /dev/null +++ b/lib/rails/auth/error_page/debug_middleware.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "erb" +require "cgi" + +module Rails + module Auth + module ErrorPage + # Render a descriptive access denied page with debugging information about why the given + # request was not authorized. Useful for debugging, but leaks information about your ACL + # to a potential attacker. Make sure you're ok with that information being public. + class DebugMiddleware + # Configure CSP to disable JavaScript, but allow inline CSS + # This is just in case someone pulls off reflective XSS, but hopefully all values are + # properly escaped on the page so that won't happen. + RESPONSE_HEADERS = { + "Content-Security-Policy" => + "default-src 'self'; " \ + "script-src 'none'; " \ + "style-src 'unsafe-inline'" + }.freeze + + def initialize(app, acl: nil) + raise ArgumentError, "ACL must be a Rails::Auth::ACL" unless acl.is_a?(Rails::Auth::ACL) + + @app = app + @acl = acl + @erb = ERB.new(File.read(File.expand_path("../debug_page.html.erb", __FILE__))).freeze + end + + def call(env) + @app.call(env) + rescue Rails::Auth::NotAuthorizedError + [403, RESPONSE_HEADERS.dup, [error_page(env)]] + end + + def error_page(env) + credentials = Rails::Auth.credentials(env) + resources = @acl.matching_resources(env) + + @erb.result(binding) + end + + def h(text) + CGI.escapeHTML(text || "") + end + + def format_attributes(value) + value.respond_to?(:attributes) ? value.attributes.inspect : value.inspect + end + + def format_path(path) + path.source.sub(/\A\\A/, "").sub(/\\z\z/, "") + end + end + end + end +end diff --git a/lib/rails/auth/error_page/debug_page.html.erb b/lib/rails/auth/error_page/debug_page.html.erb new file mode 100644 index 0000000..9609713 --- /dev/null +++ b/lib/rails/auth/error_page/debug_page.html.erb @@ -0,0 +1,128 @@ + + + + + Rails::Auth: Access Denied + + + + + + +
+
+

Error: Access to the requested resource is not allowed with your current credentials.

+

Below is information about the request you made and the credentials you sent:

+
+ +
+

Request:

+ + + + + + + + + + + + + + +
Method<%= h(env["REQUEST_METHOD"]) %>
Path<%= h(env["REQUEST_PATH"]) %>
Host<%= h(env["HTTP_HOST"]) %>
+
+ +
+

Credentials:

+ + <% if credentials.empty? %> +

No credentials provided! This is a likely cause of this error.

+

Please retry the request with proper credentials.

+ <% else %> + + <% credentials.each do |name, credential| %> + + + + + <% end %> +
<%= h(name) %><%= h(format_attributes(credential)) %>
+ <% end %> +
+ +
+

Authorized ACL Entries:

+ <% if resources.empty? %> +

Error: No matching resources! This is a likely cause of this error.

+

Please check your ACL and make sure there's an entry for this route.

+ <% else %> +

The following entries in your ACL are authorized to view this paritcular route:

+ + + <% resources.each do |resource| %> + + + + + <% end %> +
<%= h((resource.http_methods || "ALL").join(" ")) %> <%= h(format_path(resource.path)) %> +
    + <% resource.predicates.each do |name, predicate| %> +
  • <%= h(name) %>: <%= h(format_attributes(predicate)) %>
  • + <% end %> +
+
+ <% end %> +
+
+ + diff --git a/lib/rails/auth/rack.rb b/lib/rails/auth/rack.rb index 64249e9..918da23 100644 --- a/lib/rails/auth/rack.rb +++ b/lib/rails/auth/rack.rb @@ -14,6 +14,7 @@ require "rails/auth/acl/resource" require "rails/auth/error_page/middleware" +require "rails/auth/error_page/debug_middleware" require "rails/auth/x509/certificate" require "rails/auth/x509/filter/pem" diff --git a/spec/rails/auth/error_page/debug_middleware_spec.rb b/spec/rails/auth/error_page/debug_middleware_spec.rb new file mode 100644 index 0000000..b373d69 --- /dev/null +++ b/spec/rails/auth/error_page/debug_middleware_spec.rb @@ -0,0 +1,37 @@ +RSpec.describe Rails::Auth::ErrorPage::DebugMiddleware do + let(:request) { Rack::MockRequest.env_for("https://www.example.com") } + + let(:example_config) { fixture_path("example_acl.yml").read } + + let(:example_acl) do + Rails::Auth::ACL.from_yaml( + example_config, + matchers: { + allow_x509_subject: Rails::Auth::X509::Matcher, + allow_claims: ClaimsMatcher + } + ) + end + + subject(:middleware) { described_class.new(app, acl: example_acl) } + + context "access granted" do + let(:code) { 200 } + let(:app) { ->(env) { [code, env, "Hello, world!"] } } + + it "renders the expected response" do + response = middleware.call(request) + expect(response.first).to eq code + end + end + + context "access denied" do + let(:app) { ->(_env) { raise(Rails::Auth::NotAuthorizedError, "not authorized!") } } + + it "renders the error page" do + code, _env, body = middleware.call(request) + expect(code).to eq 403 + expect(body.join).to include("Access Denied") + end + end +end