nathanl / authority

*CURRENTLY UNMAINTAINED*. Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.
MIT License
1.21k stars 67 forks source link

controller action that involves data from multiple resources #103

Closed garyfoster closed 7 years ago

garyfoster commented 9 years ago

Is there a solution or better workaround to the following use case: A controller action involves data from 2 resources, for example, Customer and Order. If the action is in the Customer controller, the authorize_actions_for Customer handles that resource. In the case when the user does not have access to the Order resource, I would like the controller action to kick out to the access denied. I can explicitly check in the controller action like current_user.can_read?(Order) and if false, redirect to the 403 page, is that the best way?

nathanl commented 9 years ago

Gary - I'm not 100% sure I understand the use case, but if you need to handle this manually, I'd suggest doing fail SecurityViolation.new(user, action, resource) rather than redirecting manually. That will get rescued and handled like other security violations, according to your configuration. The default handler will log and render 403.

schugabe commented 9 years ago

I think I have the same question.

Assume you have a nested resource eg. a customer has many orders.

Within the index action of the order controller you fetch the customer and want to check if the current user is allowed to see the orders of this customer. If you do the check like this the index (or read) action of the UserAuthorizer is called.

def index
  @customer = Customer.find params[:customer_id]
  authorize_action_for @customer
  @orders = @customer.orders
end

How can you use a different action for this check e.g. the update action in the authorizer. I tried the command from the readme but it did not work correctly (I got a MissingResource error):

authorize_actions_for :set_customer, all_actions: :update, only: [:index]
private
def set_customer
  @customer = Customer.find params[:customer_id]
end

I would prefer the possibility to pass an additional argument to authorize_action_for that defines the action that is used from the authorizer.

jeriko commented 9 years ago

Perhaps I'm using the gem incorrectly, but I have a similar use case. To re-use similar lingo, if customer has many orders...

class OrdersController < ApplicationController
  authorize_actions_for :customer, all_actions: :read

  def create
    @order = Order.build(order_params)
    authorize_action_for(@order)
    @order.save!
  end

private
  def customer
    @customer = Customer.find(params[:customer_id])
  end
end

So I'm trying to first check if the user can read the customer, then check if they can create a customer's order. However, the authorize_action_for(@order) ends up checking for action read not create because of the customer declaration at the top.

Is this incorrect usage? Should I be checking everything in OrderAuthorizer? I can't see how to reduce duplication in that case.

nathanl commented 7 years ago

Authority is now unmaintained - see README.