wardencommunity / warden

General Rack Authentication Framework
MIT License
2.48k stars 204 forks source link

Set failure_app per scope #193

Open willianveiga opened 4 years ago

willianveiga commented 4 years ago

It's possible to configure failure apps per scope:

Current config:

use Warden::Manager do |manager|
  manager.failure_app = MyCustomFailureApp
end

Single scope config:

use Warden::Manager do |manager|
  manager.failure_app = { app: MyCustomFailureApp, scope: :user }
end

Multiple scopes config:

use Warden::Manager do |manager|
  manager.failure_app = [
    { app: MyCustomFailureApp, scope: :user },
    { app: AnotherCustomFailureApp, scope: :psychologist }
  ]
end

A RuntimeError is raised if no matching Failure App is found.

Fixes #40.

jsmestad commented 4 years ago

Thanks for contributing! At first glance this looks good, but I'll take a closer look soon.

l4cr0ss commented 3 years ago

I just ran into this issue, too, as I refactor a jumble of duplicated authentication subsystems inside of a large application.

In my case, a common Rack middleware is divvying up requests to autonomous applications, each of which will be responsible for registering its own warden scope and maintaining its own failure application.

To bounce the failures back to a common handler is possible, but means duplicating the registration logic, so it would be nice to see this fix merged!

itskingori commented 3 years ago

Very welcome feature. Ended up here looking for it. I was looking at the "Advanced Setup (with scopes)" and this is the current API for differentiated configuration per scope ...

use Warden::Manager do |config|
  config.failure_app = ->(env) do
    env['REQUEST_METHOD'] = 'GET'
    SessionsController.action(:new).call(env)
  end
  config.default_scope = :user

  config.scope_defaults :user,        :strategies => [:password]
  config.scope_defaults :account,     :store => false,  :strategies => [:account_by_subdomain]
  config.scope_defaults :membership,  :store => false,  :strategies => [:membership, :account_owner]

  config.scope_defaults(
    :api,
    :strategies => [:api_token],
    :store      => false,
    :action     => "unauthenticated_api"
  )
end

I was wondering if it might be better to follow that approach. That is, something like this on scope_defaults ...

use Warden::Manager do |config|
  config.default_scope = :user

  config.scope_defaults(
    :api,
    :strategies    => [:session],
    :store         => false,
    :failure_app   => ->(env) { SessionsControllerExampleForAPI.action(:new).call(env) }
  )

  config.scope_defaults(
    :web,
    :strategies    => [:token],
    :store         => true,
    :failure_app   => ->(env) { SessionsControllerExampleForWeb.action(:new).call(env) }
  )
end

Thoughts?

masterT commented 8 months ago

@itskingori I like this a lot!