Receive CanCan::AccessDenied error on first attempt to access resource after logging in with Devise #956

Closed
barriault opened this Issue Nov 11, 2013 · 4 comments

Comments

Projects
None yet
2 participants

I'm using the following in an app:

Ruby 2.0.0
Rails 4.0.1
CanCan 1.6.10
Devise 3.2.0

After signing in with Devise, the first time I attempt to access any CanCan protected resources, I get a CanCan::AccessDenied error. If I reload the page, it works fine. In my tests I'm seeing the same behavior. The first test that attempts to access a CanCan protected resource always fails.

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  check_authorization unless: :devise_controller?
  before_filter :authenticate_user!, unless: :devise_controller?

  # rescue_from CanCan::AccessDenied do |exception|
  #   redirect_to root_url, :alert => exception.message
  # end
end

Here is one of my tests:

require 'spec_helper'

describe UsersController do

  before (:each) do
    @request.env["devise.mapping"] = Devise.mappings[:admin_user]
    sign_in FactoryGirl.create(:admin_user)

    @user = FactoryGirl.create(:user)
  end

  def valid_session
    {"warden.user.user.key" => session["warden.user.user.key"]}
  end

  describe "#show" do
    context 'when logged in as admin and given a user' do

      it "displays the show page" do
        get :show, { :id => @user.id }, valid_session
        response.should be_success
      end

      it "finds the right user" do
        get :show, { :id => @user.id }, valid_session
        assigns(:user).should == @user
      end

    end
  end

end

Here the output with --backtrace turned on"

UsersController
  #show
    when logged in as admin and given a user
      displays the show page (FAILED - 1)
      finds the right user

Failures:

  1) UsersController#show when logged in as admin and given a user displays the show page
     Failure/Error: get :show, { :id => @user.id }, valid_session
     CanCan::AccessDenied:
       You are not authorized to access this page.
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/cancan-1.6.10/lib/cancan/ability.rb:208:in `authorize!'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/cancan-1.6.10/lib/cancan/controller_additions.rb:338:in `authorize!'
     # ./app/controllers/users_controller.rb:16:in `show'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/abstract_controller/base.rb:189:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/rendering.rb:10:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/abstract_controller/callbacks.rb:18:in `block in process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activesupport-4.0.1/lib/active_support/callbacks.rb:423:in `_run__1383360963607712464__process_action__callbacks'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activesupport-4.0.1/lib/active_support/callbacks.rb:80:in `run_callbacks'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/abstract_controller/callbacks.rb:17:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/rescue.rb:29:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activesupport-4.0.1/lib/active_support/notifications.rb:159:in `block in instrument'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activesupport-4.0.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activesupport-4.0.1/lib/active_support/notifications.rb:159:in `instrument'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/activerecord-4.0.1/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/abstract_controller/base.rb:136:in `process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/abstract_controller/rendering.rb:44:in `process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/test_case.rb:569:in `process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/test_case.rb:64:in `process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/devise-3.2.0/lib/devise/test_helpers.rb:19:in `block in process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/devise-3.2.0/lib/devise/test_helpers.rb:72:in `catch'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/devise-3.2.0/lib/devise/test_helpers.rb:72:in `_catch_warden'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/devise-3.2.0/lib/devise/test_helpers.rb:19:in `process'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/actionpack-4.0.1/lib/action_controller/test_case.rb:469:in `get'
     # ./spec/controllers/users_controller_spec.rb:20:in `block (4 levels) in <top (required)>'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:114:in `instance_eval'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:114:in `block in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_exec'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_eval_with_args'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:247:in `instance_eval_with_args'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:106:in `block (2 levels) in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:179:in `call'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:179:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_exec'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_eval_with_args'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:247:in `instance_eval_with_args'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:106:in `block (2 levels) in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:108:in `call'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:108:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/hooks.rb:446:in `run_hook'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:340:in `run_around_each_hooks'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:256:in `with_around_each_hooks'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example.rb:111:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:390:in `block in run_examples'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:386:in `map'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:386:in `run_examples'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:371:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `block in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `map'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `block in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `map'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/example_group.rb:372:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `map'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:28:in `block in run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/reporter.rb:58:in `report'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/command_line.rb:25:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/runner.rb:80:in `run'
     # /Users/jeffb/.rvm/gems/ruby-2.0.0-p195@backoffice/gems/rspec-core-2.14.7/lib/rspec/core/runner.rb:17:in `block in autorun'

So I added better_errors gem, commented out the rescue_from CanCan method in my applications controller, and added a point of failure to my UsersController like this:

  # GET /users/1
  # GET /users/1.json
  def show
    @user.unknown_method
  end

After logging in, the first time I go to /users/1, I get a CanCan::AccessDenied exception and some of my instance variables are:

@_authorized =
true
@current_user = 
#<User id: 1, email: "jeff@barriault.net", encrypted_password: "$2a$10$X5A4y.cc9tD3kEfTdVkvge3ipN74JRhcQjafhLtj5oeg...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 24, current_sign_in_at: "2013-11-11 17:08:46", last_sign_in_at: "2013-11-11 16:40:07", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2013-11-06 16:50:11", updated_at: "2013-11-11 17:08:46">
@current_ability     =
#<Ability:0x007fc805150b88 @rules=[], @aliased_actions={:read=>[:index, :show], :create=>[:new], :update=>[:edit]}>

When I reload the page it fails where expected at @user.unknown_method, but the current_ability instance variable is now:

@current_ability =
#<Ability:0x007fc805fb2e10 @rules=[#<CanCan::Rule:0x007fc8071b2390 @match_all=false, @base_behavior=true, @actions=[:manage], @subjects=[:all], @conditions={}, @block=nil, @expanded_actions=[:manage]>, #<CanCan::Rule:0x007fc8071b1df0 @match_all=false, @base_behavior=true, @actions=[:read], @subjects=[:all], @conditions={}, @block=nil, @expanded_actions=[:read, :index, :show]>], @aliased_actions={:read=>[:index, :show], :create=>[:new], :update=>[:edit]}>

So it looks like on first visit the current_ability for the user isn't defined. No idea if this is something I did wrong or a bug in CanCan. Any ideas?

I feel like such a dufus. Looks like the problem was in my Ability class:

class Ability
  include CanCan::Ability

  def initialize(user)
    def initialize(user)
      user ||= User.new # guest user

      if user.role? :admin
        can :manage, :all
      end
      can :read, :all
    end  
  end
end

How's that for stupid?

barriault closed this Nov 13, 2013

Worked for me. Thanks mate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment