I want to add "is_admin?" filter to ActiveAdmin initializer. In which file should I define the "is_admin?" method?
# == Controller Filters
#
# You can add before, after and around filters to all of your
# Active Admin resources from here.
#
config.before_filter :is_admin?
In your app/controllers/application_controller.rb
Related
I would like to secure the rails_admin pages using the sorcery gem. According to this SO answer, the way to do this is as follows:
# config/initializers/rails_admin.rb
RailsAdmin.config do |config|
config.authenticate_with do
# Use sorcery's before filter to auth users
require_login
end
end
# app/controllers/application_controller.rb
class ApplicationController
# Overwrite the method sorcery calls when it
# detects a non-authenticated request.
def not_authenticated
# Make sure that we reference the route from the main app.
redirect_to main_app.login_path
end
end
This overrides sorcery's default method for handling no login. The overriding does work in my app, but when I visit the rails_admin pages, I get the following error:
undefined local variable or method `root_path' for #<RailsAdmin::MainController.
so the overriding is not working in the rails_admin code. I am mounting rails_admin at the bottom of my routes file with
# config/routes.rb
...
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
How do I fix this?
It is because the rails_admin controller is not inheriting from my application controller. There is a rails_admin configuration setting that sets this inheritance, i.e.
#config/initializers/rails_admin.rb
RailsAdmin.config do |config|
...
config.parent_controller = 'ApplicationController'
end
Using devise gem to authenticate all users of an application.
I'm trying to implement Active Storage.
Let's say that all users must be authenticated as soon as they reach the app:
class ApplicationController < ActionController::Base
before_action :authenticate_user!
...
end
How to secure the Active Storage generated routes?
URL of an uploaded file can be accessed without having to authenticate first. The unauthenticated user can get the file url generated by Active Storage.
This is not a full answer but a starting point:
The gist: You would need to override the redirect controller.
The docs for activestorage/app/controllers/active_storage/blobs_controller.rb say:
If you need to enforce access protection beyond the
security-through-obscurity factor of the signed blob references,
you'll need to implement your own authenticated redirection
controller.
Also if you plan to use previews the docs for activestorage/app/models/active_storage/blob/representable.rb say
Active Storage provides one [controller action for previews], but you may want to create your own (for
example, if you need authentication).
Also you might find some relevant information in this rails github issue
Update:
Here is a minimal example that "should" work for preventing unauthorised access to the redirects when using the devise gem.
How the url, that the user will be redirected to if logged, is then secured is still another story I guess. By default they expire after 5 minutes but this could be set to a shorter period like 10 seconds (if you replace line 6 in example below with expires_in 10.seconds)
Create a file app/controllers/active_storage/blobs_controller.rb with the following code:
class ActiveStorage::BlobsController < ActiveStorage::BaseController
before_action :authenticate_user!
include ActiveStorage::SetBlob
def show
expires_in ActiveStorage::Blob.service.url_expires_in
redirect_to #blob.service_url(disposition: params[:disposition])
end
end
Please note that the only thing that changed from the original code is that the second line is added
before_action :authenticate_user!
Update 2:
Here is a concern that you can include in ActiveStorage::RepresentationsController and ActiveStorage::BlobsController to enable devise authentication for ActiveStorage
See gist is at https://gist.github.com/dommmel/4e41b204b97238e9aaf35939ae8e1666 also included here:
# Rails controller concern to enable Devise authentication for ActiveStorage.
# Put it in +app/controllers/concerns/blob_authenticatable.rb+ and include it when overriding
# +ActiveStorage::BlobsController+ and +ActiveStorage::RepresentationsController+.
#
# Optional configuration:
#
# Set the model that includes devise's database_authenticatable.
# Defaults to Devise.default_scope which defaults to the first
# devise role declared in your routes (usually :user)
#
# blob_authenticatable resource: :admin
#
# To specify how to determine if the current_user is allowed to access the
# blob, override the can_access_blob? method
#
# Minimal example:
#
# class ActiveStorage::BlobsController < ActiveStorage::BaseController
# include ActiveStorage::SetBlob
# include AdminOrUserAuthenticatable
#
# def show
# expires_in ActiveStorage::Blob.service.url_expires_in
# redirect_to #blob.service_url(disposition: params[:disposition])
# end
# end
#
# Complete example:
#
# class ActiveStorage::RepresentationsController < ActiveStorage::BaseController
# include ActiveStorage::SetBlob
# include AdminOrUserAuthenticatable
#
# blob_authenticatable resource: :admin
#
# def show
# expires_in ActiveStorage::Blob.service.url_expires_in
# redirect_to #blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition])
# end
#
# private
#
# def can_access_blob?(current_user)
# #blob.attachments.map(&:record).all? { |record| record.user == current_user }
# end
# end
module BlobAuthenticatable
extend ActiveSupport::Concern
included do
around_action :wrap_in_authentication
end
module ClassMethods
def auth_resource
#auth_resource || Devise.default_scope
end
private
def blob_authenticatable(resource:)
#auth_resource = resource
end
end
private
def wrap_in_authentication
is_signed_in_and_authorized = send("#{self.class.auth_resource}_signed_in?") \
& can_access_blob?(send("current_#{self.class.auth_resource}"))
if is_signed_in_and_authorized
yield
else
head :unauthorized
end
end
def can_access_blob?(_user)
true
end
end
If you want to implement authentication for all endpoints provided by active storage, you can override the ActiveStorage::BaseController based on the original implementation:
# app/controllers/active_storage/base_controller.rb
# frozen_string_literal: true
# The base class for all Active Storage controllers.
class ActiveStorage::BaseController < ActionController::Base
before_action :authenticate_user!
include ActiveStorage::SetCurrent
protect_from_forgery with: :exception
end
I'm using ActiveAdmin with Devise and have 2 models, User and AdminUser. Both models are apart of Devise when generated:
20140210105605_devise_create_users.rb
20140731015129_devise_create_admin_users.rb
The users table has 4 new columns which are :name, :latitude, :longitude, :address
Just in case in the initializers/devise.rb I added the following lines:
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
config.scoped_views = true
# Configure the default scope given to Warden. By default it's the first
# devise role declared in your routes (usually :user).
config.default_scope = :user
I'm having trouble getting pass a method meant for my users only:
ApplicationController
before_filter :set_user_location
private
def set_user_location
if user_signed_in?
#user_location = current_user.address
#user_latitude = current_user.latitude
#user_longitude = current_user.longitude
end
end
This is throwing me this error:
undefined method `address' for nil:NilClass
But this method shouldn't even take place unless a User is signed in, not an AdminUser. How would I fixed this?
Try this: before_filter :set_user_location, :if => proc { current_user }
In this case the filter will be applied only if the curren_user has been set.
I have CanCan and Rolify set up with ActiveAdmin, and now it's time to force authorization on my controllers.
Do I have to authorize_resource on every controller (We have a couple dozen models and controllers now), or is there a way to apply it to all of my ActiveAdmin controllers?
I tried calling it in a before_filter from ActiveAdmin.setup, but that didn't work.
I made an initializer: config/initializers/active_admin-cancan.rb
module ActiveAdmin
class ResourceController
# If you don't skip loading on #index you will get the exception:
#
# "Collection is not a paginated scope. Set collection.page(params[:page]).per(10) before calling :paginated_collection."
load_resource :except => :index
authorize_resource
def scoped_collection
end_of_association_chain.accessible_by(current_ability)
end
end
end
Borrowed from another user's code, but now I can't find the source any more.
I'm trying to install the Rails Admin Gem using Sorcery for authentication instead of Devise.
Rails admin does provide a hook that you can use to attach your own authentication method. Here is the example they provide in their docs (using warden):
config.authenticate_with do
warden.authenticate! :scope => :admin
end
config.current_user_method { current_admin }
I'm guessing that inside the block I need to reference the before_filter that Sorcery uses to authenticate users, which would be require_login.
However, when I try that and I try to visit /admin when logged out, I get a routing error:
No route matches {:action=>"new", :controller=>"sessions"}
This probably happens because I am being redirected within the engine rather than in the main app.
How can I set this up correctly?
# config/initializers/rails_admin.rb
RailsAdmin.config do |config|
config.authenticate_with do
# Use sorcery's before filter to auth users
require_login
end
end
# app/controllers/application_controller.rb
class ApplicationController
# Overwrite the method sorcery calls when it
# detects a non-authenticated request.
def not_authenticated
# Make sure that we reference the route from the main app.
redirect_to main_app.login_path
end
end
#config/initializers/rails_admin.rb
RailsAdmin.config do |config|
...
config.parent_controller = 'ApplicationController'
end
If you use Sorcery with Cancancan gem, you should also add config.current_user_method(&:current_user) in your config/initializers/rails_admin.rb file, or you'll get the error: You are not authorized.