ActiveAdmin: How to setup HTTP basic authentication?
Asked Answered
P

3

8

I want to set basic authentication for ActiveAdmin, which internal devise solution doesn't apply to my case. For that I would like to be able to add middleware to the ActiveAdmin Engine before this is bundled into my app. What I managed to do was:

ActiveAdmin::Engine.configure do |config|
  config.middleware.use Rack::Auth::Basic do |username, password|
    username == 'admin' && password == 'root'
  end  
end

But apparently this doesn't make it work, since my active admin routes are still unprotected. How can I effectively do this? And no, I don't want to protect my whole site with basic authentication.

Phonogram answered 8/3, 2013 at 14:6 Comment(0)
K
21

Here's a few ideas:

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

  # ...
  http_basic_authenticate_with :name => "frodo", :password => "thering", :if => :admin_controller?

  def admin_controller?
    self.class < ActiveAdmin::BaseController
  end

Or, the monkeypatching version

# config/initializers/active_admin.rb

# somewhere outside the setup block

class ActiveAdmin::BaseController
  http_basic_authenticate_with :name => "frodo", :password => "thering"
end

If you only want to protect specific resources, you can use the controller block:

# app/admin/users.rb

ActiveAdmin.register Users do
  controller do
    http_basic_authenticate_with :name => "frodo", :password => "thering"
  end

  # ...
end

I was hoping that I would be able to extend the controller in this way in config/initializers/active_admin.rb in the setup block, but this didn't work for me:

# app/admin/users.rb

ActiveAdmin.setup do |config|
  config.controller do
    http_basic_authenticate_with :name => "frodo", :password => "thering"
  end

  # ...
end

You might try it though, as it could be an ActiveAdmin version thing (I could have sworn that I saw that documented somewhere...)

Good luck, I hope this helps.

UPDATE: A couple more options:

I hadn't realized before that :before_filter in activeadmin config takes a block.

# config/initializers/active_admin.rb

ActiveAdmin.setup do |config|
  # ...
  config.before_filter do
    authenticate_or_request_with_http_basic("Whatever") do |name, password|
      name == "frodo" && password == "thering"
    end
  end
end

And... just one more idea. It sounds like you are not keen on adding anything to application_controller, but this version is not conditional like the first above:

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base

  def authenticate_admin
    authenticate_or_request_with_http_basic("Whatever") do |name, password|
      name == "frodo" && password == "thering"
    end
  end
end



# config/initializers/active_admin.rb

ActiveAdmin.setup do |config|
  # ...
  config.authentication_method = :authenticate_admin
end
Koto answered 11/3, 2013 at 18:57 Comment(9)
hey, thanks for listing out all the available options! The first one is one I was aware of, but didn't want to implement at all costs (conditional filtering sucks, it is also evaluated by all the open actions). Second one is a nice candidate. 3rd one is not exactly my use case. 4th one is what I'd be expecting (albeit not with that syntax) to be implemented anytime the active admin team realizes not all rails applications have/need an authentication system. I think I'll go with your second suggestion and report to you back as soon as I have an evaluation. Thx again!Phonogram
@ChuckE: It looks like the second option will work just fine for you. I just added a couple more based on authentication_method and before_filter. The last one might be good if there's anywhere else you might want to authenticate for admin users... After looking at all of them again, I realized that I think I like the first of my edits (using config.before_filter) the best. Good luck!Koto
I'm also of your opinion, a solution that remains in the default active admin initializer seems like a winner!Phonogram
Subjected to timing attack. Please see codahale.com/a-lesson-in-timing-attacksAftmost
@Aftmost Thanks for the warning, I will certainly keep that in mind. I'd like to say that my answer is not about how to secure ActiveAdmin, but how to configure ActiveAdmin with http basic. It sounds like a pull-request to rails might be a good idea (github.com/rails/rails/blob/master/actionpack/lib/…)Koto
You found it. So you should take the fame to fix it. Its IMHO a serious security issue that even deserves a CVE.Aftmost
UPDATE: It looks like http_basic_authenticate_with now uses ActiveSupport::SecurityUtils.variable_size_secure_compare.Koto
config.before_filter is config.before_action now in Rails 5Ventriloquism
great catch @AmielMartin, Though filter is deprecated from rails 5 to onwards.Diadiabase
M
-1

If you just want to protect the admin area of ActiveAdmin, then you should try this:

# app/admin/dashboard.rb
controller do
  http_basic_authenticate_with :name => "mega-admin", :password => "supersecret"
end

that works like a charm ;-)

have fun

Meaghan answered 4/2, 2014 at 20:44 Comment(1)
Subjected to timing attack. Please see codahale.com/a-lesson-in-timing-attacksAftmost
M
-1

just another solution for you would be:

  # app/controllers/application_controller.rb
  protected
  def authenticate
    authenticate_or_request_with_http_basic do |username, password|
      username == "admin" && password == "superpassword"
    end
  end

# config/initializers/active_admin.rb
config.before_filter :authenticate

the big plus for this solution ist, that you can call

before_filter :authenticate

in every area you want to protet.

Meaghan answered 4/2, 2014 at 21:5 Comment(1)
Never, EVER validate credentials via String#== this is subjected to a timing attack. codahale.com/a-lesson-in-timing-attacksAftmost

© 2022 - 2024 — McMap. All rights reserved.