Jul 30 Bypassing declarative authorization in Cucumber steps

tags: cucumber declarative authorization | comments

You have set up that groovy declarative authorization plugin in your app, all the way from models, to controllers and views, to keep authorization tidy and out of the way, and everything runs smoothly. Now when you try to create objects in your features Given steps you face the dreadful not authorized exception:

No matching rules found for create for #<Authorization::GuestUser:0xb58904a8 @role_symbols=[:guest]> 
(roles [:guest], privileges [:create, :manage], context :jobs). (Authorization::NotAuthorized)
  ./features/step_definitions/leaves_steps.rb:3
  ./features/step_definitions/leaves_steps.rb:3:in `/^there exists 5 leaves not of mine$/'
    features/leaves.feature:5:in `Given there exists 5 leaves not of mine'

Guest user is the default, non session user in declarative authorization. The solution is to bypass declarative authorization in Cucumber and build the objects needed to set a status to run your features. Let’s see an example:

A typical authorization setup

This is the typical setup, a tree can only manage its leaves:

# config/authorization_rules.rb
authorization do
  role :tree do
    has_permission_on :leaves, :to => :manage do
      if_attribute :tree => is { user }
    end
  end
end

privileges do
# the distributed ones with declarative authorization
end

the models:

# the tree model
class Tree < ActiveRecord::Base
  has_many :leaves

  # the tree is declaring itself with role tree
  def role_symbols
    [:tree]
  end
end

# your leaf model
class Leaf < ActiveRecord::Base
  # now this requires the leaf belongs to tree so the tree can change it
  using_access_control

  belongs_to :tree
end

You have to set the controller the typical way, but I’ll leave that to you. Anyway you have to make the session available to the models somewhere like this:

# in some before_filter or so, a tree is user :-)
Authorization.current_user = current_tree

Your feature

With that setup, you want to run the feature:

# features/leaves.feature
Feature: Leaves authorizations

Scenario: A tree can only manage its own leaves
Given there exists 5 leaves not of mine
When I visit the edit url of a leaf not of mine
Then I should see "You are not allowed to access this action."

and the step goes like this, the way you always did:

# features/steps_definitions/leaves.rb
Given /^there exists 5 leaves not of mine$/
   5.times { Leaf.make }
end

Here is where the exception comes from, since you have no session, and you’ll never have one :-)

The solution, bypass authorization

Luckily declarative authorization provides a way of bypassing its lock. The trick is to load the Authorization::Maintenance module that lives in declarative_authorization/lib/declarative_authorization/maintenance.rb into the Cucumber World like this:

# features/support/env.rb
require File.expand_path(File.dirname(__FILE__) + 
"/../../vendor/plugins/declarative_authorization/lib/declarative_authorization/maintenance.rb")
World(Authorization::Maintenance)

and then in your step, run on non-authorized mode:

# features/steps_definitions/leaves.rb
Given /^there exists 5 leaves not of mine$/
   # now World contains the module, and here we run the block unprotected
   without_access_control do
     5.times { Leaf.make }
    end
end

You will always bear with authorization

In other place (like the console) you should do it this way:

>> require File.expand_path("/vendor/plugins/declarative_authorization/lib/declarative_authorization/maintenance.rb")
>> include Authorization::Maintenance
>> without_access_control do ...

TODO maybe you could make an initialization script to be run on start up of script/console and load it with an option.

blog comments powered by Disqus