Authenticate two different devise classes in same controller in Rails - ruby-on-rails

I have this view called Intranet where only authenticated "devise clients" can access.
class IntranetController < ApplicationController
before_action :authenticate_client!
def index
end
end
On the other side, I also have other "devise admin", this devise admin requires to access the same view. How can I handle this situation?

Try this:
class IntranetController < ApplicationController
before_action :authenticate_all!
def index
end
def authenticate_all!
if admin_signed_in?
true
else
authenticate_client!
end
end
end

Related

Rails 5, pundit authorization

Pundit works well, if action has resources like:
class Admin::PagesController << ApplicationController
def index
#pages = Page.all
end
end
How to authorise method without any resources in action?
class Admin::DashboardController << ApplicationController
def index
end
end
I hav file policies/admin/dashboard_policy.rb
class Admin::DashboardPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
end
This file was generated by command:
rails g pundit:policy Admin/Dashboard
File views/admin/index.html.slim has only static text. Nothing more.
How to authorise action without any resources?
Regards
Sssebaaa
To authorize without a scope or model instance call authorize with a symbol or array of symbols (when namespaced):
class Admin::DashboardController << ApplicationController
def index
authorize [:admin, :dashboard]
end
end
This will call the #index? method on the policy class:
class Admin::DashboardPolicy < ApplicationPolicy
def index?
user.admin?
end
end
You can also remove the scope completely from your policy.
If you don't have any callbacks checking that the policy is scoped, as pundit doc suggests, like
class ApplictationController < ActionController::Base
include Pundit
after_action :verify_policy_scoped, only: :index
end
You don't have anything to do.
However if you do have a callback, you can just skip it in your controller action like this:
class Admin::DashboardController << ApplicationController
skip_after_action :verify_policy_scoped, only: [:index]
def index
end
end

Rails/Devise: Restore session without going through full auth process?

I'm using Devise + ominauth2 to allow users to sign in via different services. If they sign in they get a slightly better experience but if not life still goes on. However I don't see a way with Devise to have a page that allows both authenticated and unauthenticated access.
For example:
class SomeController < ApplicationController
before_action :authenticate_user!
def some_action
end
end
In the above controller, some_action is only accessible if the user authenticates. But what I actually want is something more like:
class SomeController < ApplicationController
def some_action
loadSessionFromCookieIfExists
end
end
Then, I can use user_signed_in? in my views. But this doesn't work because authenticate_user! will redirect them elsewhere. Unless there is an authenticate_if_possible method?
So what I have now, which is really gross is:
class SomeController < ApplicationController
before_action :authenticate_user!
skip_before_action :authenticate_user!, :only=>[:no_auth]
def action
do_stuff
return
end
def no_auth
do_stuff
return
end
private
def do_stuff
render :template => "action"
end
end
I should add, that omniauth2 doesn't support rememberable out of the gate so it's possible this is all supposed to work just fine and the problem is with omniauth2.

Check if current request is protected in Rails with CanCan

I'm using the CanCan gem in my Rails app and want to check if the current request is a protected resource in my application.
So for example I have the following:
class AdminController < ApplicationController
load_and_authorize_resource
end
How can I check if the request is protected by CanCan?
I can access the controller and action via params. I can't use the standard can? and cannot? helpers as they will check if the current_user has permission rather than if the action itself has a protection on it.
So for example:
class ApplicationController < ActionController::Base
before_action :check_protected
def check_protected
if can? params[:action].to_sym, Object.const_get(params[:controller].classify)
# resource is protected
else
# resource is not protected
end
end
end
^^ This won't work because it will always say false when no current_user or if the user doesn't have permission. I need to check if the resource itself is protected with CanCan.
If I had these examples:
class PostsController < AdminController
def index
end
end
class HomeController < ApplicationController
def index
end
end
The index for PostsController should be identifiable as protected, and the index for HomeController as unprotected.
CanCan uses CanCan::ControllerResource#skip? method to determine whether it should authorize resource or not. So I guess you may rely on it as follows:
def check_protected
if CanCan::ControllerResource.new(self).skip?(:authorize)
# resource is not protected
else
# resource is protected
end
end
I've tried it in my sandbox and it worked for me

Pundit Headless Policy

I'm using pundit for access control in the admin section of my app. I have a dashboards controller that looks like this:
class Admin::DashboardsController < AdminController
def index
#total_revenue = Order.total_revenue
authorize :dashboards, :index?
end
...
end
and a policy that looks like this:
class DashboardPolicy < Struct.new(:user, :dashboard)
def index?
true
end
end
When I try to access /admin/dashboards/ I get a Pundit::NotDefinedError, unable to find policy SymbolPolicy for dashboards
I've also tried namespacing the policy and got the same error.
jizak's answer did not work for me, I found following solution for headless name-spaced policies, the trick being with the [:admin, :policy] first argument.
class Admin::HomeController < AdminController
def dashboard
authorize [:admin, :home], :dashboard?
end
end
And then for the policy:
Admin::HomePolicy < AdminPolicy
def dashboard?
return false unless user && user.admin?
true
end
end
I have such headless policy:
app/policies/admin/statistic_policy.rb
class Admin::StatisticPolicy < Struct.new(:user, :statistic)
def show?
user.admin?
end
end
app/controllers/admin/statistics_controller.rb
class Admin::StatisticsController < Admin::ApplicationController
def show
per_today Time.zone.now
authorize :statistics, :show?
end
...
end
and it works for me.
Try to update gem, because these changes are new (https://github.com/elabs/pundit/issues/77).
Delete your Gemfile.lock from the project and do 'bundle install'.
I recently had the same issue. The problem that I faced was that the controller was without a model.
Remember that Pundit is a model based authorization, not so much of controller based.
Before creating an Admin class (in the models), I was getting the same error as you were. Also, take note of the authorization statement on my dashboard action in the controller.
controllers/admin_controller.rb
class AdminController < ApplicationController
after_action :verify_authorized
def dashboard
authorize Admin, :dashboard?
end
end
models/admin.rb
class Admin
def self.policy_class
AdminPolicy
end
end
policies/admin_policy
class AdminPolicy < Struct.new(:user, :admin)
def dashboard?
user.admin?
end
end
I managed to use Pundit on namespaced controller actions regardless of the model by using this:
In my /private/scrapers_controller.rb I have
module Private
class ScrapersController < Private::PrivateApplicationController
# Pundit authorizations
before_action { authorize [:private, :scrapers] }
def index
end
...
And then in policies/private/scrapers_policy.rb
class Private::ScrapersPolicy < ApplicationPolicy
def index?
return true if user.has_role?(:super_admin)
return false
end
end
This will disallow visiting scrapers#index or any other action within the controller to any user who's not an :super_admin
To disallow only index explicitly you can use:
before_action { authorize [:private, :scrapers], :index? }
Check yout pundit version. You may need to run 'bundle update pundit', because headless policies were merged to master quite recently and before that you had need to install pundit from github: 'elabs/pundit' to use them.
Described issue
Merged headless policies
if you just want to render landing page for controller dashboard#index for example, where no need to authorize users you can just skip authorization like
dashboard_controller.rb
class DashboardController < ApplicationController
def index
skip_policy_scope
end
end
And therefore you don't have to create DashboardPolicy at all.

how to make devise admin see everything?

I normally have everything scoped with current_user
eg:
#integrations = current_user.integrations.all
For trouble shooting, I want the admin to see everything for all users. I currently have a boolean on the user model that is admin: true
To get around the admin seeing everything, I keep doing this:
def index
if current_user.admin?
#integrations = Integration.all.includes(:user)
#reports = Report.all
else
#integrations = current_user.integrations
#reports = current_user.reports
end
end
I feel like there is an easier way... suggestions?
Thanks!
You could maybe abstract the admin check to a protected/private method in your User controller:
def is_admin
current_user.admin?
end
And then at the top of the controller, place a before action to catch whatever methods you want:
class UsersController < ApplicationController
before_action :is_admin, only: [:index, :show]
# rest of your code
end
OR
class UsersController < ApplicationController
before_action :is_admin, except: [:destroy]
# rest of your code
end
You could make a protected method in the application_controller.rb file. As stated above it will check to see if the current_user is and admin. Then you can use conditional statements to set privileges.
assuming that admin is a boolean value
def is_admin?
current_user.admin == true
end
In a view you can then say
if current_user.is_admin?
........
end

Resources