Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,44 @@ The following matchers are available:

* `allow_request`: allows a request with the given Rack environment, and optional principals

### Error Page Middleware

When an authorization error occurs, the `Rails::Auth::NotAuthorizedError`
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.

To use it, add `Rails::Auth::ErrorPage::Middleware` to your app:

```
```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,
page_body: File.read("path/to/403.html")
)

run error_page
```

## Contributing

Any contributors to the master *rails-auth* repository must sign the
Expand Down
21 changes: 21 additions & 0 deletions lib/rails/auth/error_page/middleware.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Rails
module Auth
module ErrorPage
# Render an error page in the event Rails::Auth::NotAuthorizedError is raised
class Middleware
def initialize(app, page_body: nil)
fail TypeError, "page_body must be a String" unless page_body.is_a?(String)

@app = app
@page_body = page_body.freeze
end

def call(env)
@app.call(env)
rescue Rails::Auth::NotAuthorizedError
[403, {}, [@page_body]]
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/rails/auth/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
require "rails/auth/acl/middleware"
require "rails/auth/acl/resource"

require "rails/auth/error_page/middleware"

require "rails/auth/x509/filter/pem"
require "rails/auth/x509/filter/java" if defined?(JRUBY_VERSION)
require "rails/auth/x509/matcher"
Expand Down
26 changes: 26 additions & 0 deletions spec/rails/auth/error_page/middleware_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
RSpec.describe Rails::Auth::ErrorPage::Middleware do
let(:request) { Rack::MockRequest.env_for("https://www.example.com") }
let(:error_page) { "<h1> Unauthorized!!! </h1>" }

subject(:middleware) { described_class.new(app, page_body: error_page) }

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) { fail(Rails::Auth::NotAuthorizedError, "not authorized!") } }

it "renders the error page" do
code, _env, body = middleware.call(request)
expect(code).to eq 403
expect(body).to eq [error_page]
end
end
end