Skip to content

Caveat: Don't add roles to resource instances that have not yet been persisted. #476

@waterjump

Description

@waterjump

If you have an active record callback set up that will add roles to an instance of a resource that has not yet been persisted, Rolify will by default add the role on the class level, instead of just one instance, which could be disastrous. This one snuck up on me and I was scratching my head for a while so I thought I'd share. Here's a simple (non-comprehensive) example:

class User < ActiveRecord::Base
  rolify
end

class Organization < ActiveRecord::Base
  resourcify
  belongs_to :parent_organization, class_name: 'Organization'
  has_many :child_organizations, class_name: 'Organization', after_add: :cascade_roles_to_child
  after_create :add_dummy_child

  def add_dummy_child
    return unless is_parent? && child_organizations.empty
    child_organizations.build(name: 'Dummy')  # Will trigger the after_add hook
  end

  def cascade_roles_to_child(child_org)
    User.with_role(:admin, self).each do |user|
      # child_org is not yet persisted! 
      # The next line will give users admin role on all organizations.
      user.add_role(:admin, child_org)
    end
  end

I'm aware this is not a common use case, but it's high risk and Rolify does not offer protection against accidental misuse. The cause of this is in Rolify::Role#add_role line 15 because it doesn't check if the resource is persisted or not before passing the instance id as nil. The only difference between class level and instance level role creation is an optional parameter in the RolesAdapter. Very easy to miss.

To protect against this in your application, prefer to call #create on relationships instead of #build, or assign an id before persistence (have not checked if this second part is supported).

NOTE: I have not tried to recreate this functionality using the Mongoid adapter.

The more you know.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions