deviseactiveadminwarden

ActiveAdmin and Warden route constraint


We recently updated to ActiveAdmin 1.1.0, on a site which maintains two distinct user models - Users and AdminUsers. ActiveAdmin authenticates AdminUsers, and the rest of the site authenticates Users. Both paths use Devise, like this:

  devise_for :users, controllers: {sessions: :practitioner_sessions, passwords: :practitioner_passwords}

  admin_devise_config = ActiveAdmin::Devise.config
  admin_devise_config[:controllers][:sessions] = :sessions

  devise_for :admin_users, admin_devise_config

Now, I have a Rails engine (Resque::Server) mounted which I want to restrict to admins, using a routing constraint like this in config/routes.rb:

module RouteConstraint
  class Admin
    def self.matches?(request)
      request.env['warden'].user && request.env['warden'].user.admin?
    end
  end
end

  mount ResqueWeb::Engine, :at => "/resque", :constraints => RouteConstraint::Admin

This used to work. However, now when an AdminUser is logged in to ActiveAdmin, request.env['warden'].user returns nil and request.env['warden'].authenticated? returns false.

Where do I go to check if a user is authenticated with ActiveAdmin in this configuration?


Solution

  • The "scopes" section of the Warden wiki gave me the clues I needed to rewrite two route constraints. Instead of querying the user method of the Warden object, I passed the relevant Devise scopes as arguments to the authenticated?() method. Remember that the Devise scopes can be found in routes.rb, e.g.:

    devise_for :admin_users, admin_devise_config
    
    devise_scope :admin_user do
      # some stuff
    end
    

    So then constraints can be written like this:

    module RouteConstraint
      class SuperAdmin
        def self.matches?(request)
          warden = request.env['warden']
          warden.authenticated?(:admin_user)
        end
      end
    end
    
    module RouteConstraint
      class LoggedIn
        def self.matches?(request)
          warden = request.env['warden']
          warden.authenticated?(:user) || warden.authenticated?(:admin_user)
        end
      end
    end
    

    Then I was able to use the constraints in the same way as before:

      mount Resque::Server, :at => "/resque", :constraints => RouteConstraint::SuperAdmin
      mount JobState::Engine, :at => "/job_state", :constraints => RouteConstraint::LoggedIn