Class: Trust::Permissions
- Inherits:
-
Object
- Object
- Trust::Permissions
- Includes:
- InheritableAttribute
- Defined in:
- lib/trust/permissions.rb
Overview
Trust Permissions
Permissions should be specified in a separate file in you app/model directory. The file could look like this:
module Permissions
class Default < Trust::Permissions
...
end
...
end
The above is the minimum required definitions that must exist in you file. Default
will be used if no classes match the permissions requested, so the Default
class definition is mandatory.
If you want to separate the permissions into separate files that is ok. Then you shoud place these files in the /app/model/permissions directory.
Defining permisions
The basic rules is to define classes in the Permissions module that matches your models. Here are some examples:
-
Project
should have a matching classPermissions::Project
-
Account
should have a matching classPermissions::Account
-
Account:Credit
may have a matching classPermissions::Account::Credit
, but if its inheriting fromAccount
and no special handling is necessary, it is not necessary to create the permissions class.
Using inheritance
Inheritance is also fully supported, but should generally follow your own inheritance model
module Permissions
class Account < Default
role :admin, :accountant do
...
end
end
class Account::Credit < Account
...
end
end
Action aliases
You can define aliases for actions. You do this by setting the action_aliases
attribute on Trust::Permissions class Example:
Trust::Permissions.action_aliases = {
read: [:index, :show],
create: [:create, :new]
}
Keep in mind that all permissions are expanded upon declaration, so when using the can?
method you must refer to the actual action and not the alias. The alias will never give a positive permission.
Accessors
Accessors that can be used when testing permissions:
-
user
- the user currently logged in -
action
- the action request from the controller such as :edit, or the action tested from helper or from the object itself when usingActiveRecord::can?
is being used. -
subject
- the object that is being tested for permissions. This may be a an existing object, a new object (such as for:create
and:new
action), or nil if no object has been instantiated. -
parent
- the parent object if in a nested route, specified bybelongs_to
in the controller. -
klass
- the class of involed in the request. It can be a base class or the real class, depending on your controller design.
Defining your own accessors or instance methods
You can easily define your own accessors in the classes. These can be helpful when declaring permissions.
Example:
class Account < Trust::Permissions
role :admin, :accountant do
can :update, :unless => :closed?
end
def closed?
subject.closed?
end
end
In the above example closed is testing on the subject to see if it is closed. The permission is referring to this method when evaluated. Keep in mind that you must refer to the subject
, as you do not access the inctance of the object directly.
Defined Under Namespace
Classes: SubjectInaccessible
Constant Summary collapse
- @@can_expressions =
read: [:index, :show], create: [:create, :new], update: [:update, :edit], manage: [:index, :show, :create, :new, :update, :edit, :destroy]
0
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
Returns the value of attribute action.
-
#klass ⇒ Object
readonly
Returns the value of attribute klass.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#subject ⇒ Object
Returns the value of attribute subject.
-
#user ⇒ Object
readonly
Returns the value of attribute user.
Class Method Summary collapse
- ._role(existing_permissions, *roles, &block) ⇒ Object
-
.can(*args) ⇒ Object
Defines permissions.
-
.cannot(*args) ⇒ Object
Revokes permissions.
-
.member_role(*roles, &block) ⇒ Object
(also: member_roles)
Assign permissions to one or more roles on a member role.
-
.permit(*attrs) ⇒ Object
Assign default permissions for whitelisting paremeter attributes.
-
.require(entity) ⇒ Object
Assign default requirement for whitelisting paremeters.
-
.role(*roles, &block) ⇒ Object
(also: roles)
Assign permissions to one or more roles.
Instance Method Summary collapse
-
#authorized? ⇒ Boolean
Returns params_handler if the user is authorized to perform the action.
-
#initialize(user, action, klass, subject, parent) ⇒ Permissions
constructor
Initializes the permission object.
-
#members_role ⇒ Object
Implement this in your permissions class if using membership roles.
- #preload ⇒ Object
-
#preload? ⇒ Boolean
returns true if permissions are currently being preloaded In new_actions, the framework must load require and permit in order to set permitted variables before the authorization can be evaluated.
-
#subject_or_parent ⇒ Object
Returns subject if subject is an instance, otherwise parent.
Methods included from InheritableAttribute
Constructor Details
#initialize(user, action, klass, subject, parent) ⇒ Permissions
Initializes the permission object
calling the authorized?
method on the instance later will test for the authorization.
Parameters:
+user+ - user object, must respond to role_symbols
+action+ - action, such as :create, :show, etc. Should not be an alias
+klass+ - the class of the subject.
+subject+ - the subject tested for authorization
+parent+ - the parent object, normally declared through belongs_to
See Authorization for more details
148 149 150 |
# File 'lib/trust/permissions.rb', line 148 def initialize(user, action, klass, subject, parent) @user, @action, @klass, @subject, @parent = user, action, klass, subject, parent end |
Instance Attribute Details
#action ⇒ Object (readonly)
Returns the value of attribute action.
115 116 117 |
# File 'lib/trust/permissions.rb', line 115 def action @action end |
#klass ⇒ Object (readonly)
Returns the value of attribute klass.
115 116 117 |
# File 'lib/trust/permissions.rb', line 115 def klass @klass end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
115 116 117 |
# File 'lib/trust/permissions.rb', line 115 def parent @parent end |
#subject ⇒ Object
Returns the value of attribute subject.
116 117 118 |
# File 'lib/trust/permissions.rb', line 116 def subject @subject end |
#user ⇒ Object (readonly)
Returns the value of attribute user.
115 116 117 |
# File 'lib/trust/permissions.rb', line 115 def user @user end |
Class Method Details
._role(existing_permissions, *roles, &block) ⇒ Object
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/trust/permissions.rb', line 361 def _role(, *roles, &block) if block_given? if @@can_expressions > 0 @@can_expressions = 0 raise RoleAssigmnentMissing end @perms = {:can => [], :cannot => []} @in_role_block = true yield @in_role_block = false perms = @perms else if @@can_expressions > 1 @@can_expressions = 0 raise RoleAssigmnentMissing end perms = roles. unless perms.size >= 1 && (perms[:can] || perms[:cannot]) raise ArgumentError, "Must have a block or a can or a cannot expression: #{perms.inspect}" end @@can_expressions = 0 end roles.flatten.each do |role| [role] ||= [] if perms[:cannot] && perms[:cannot].size > 0 perms[:cannot].each do |p| [role].delete_if { |perm| perm[0] == p } end end if perms[:can] && perms[:can].size > 0 [role] += perms[:can] end end end |
.can(*args) ⇒ Object
Defines permissions
Arguments
action - can be an alias or an actions of some kind
options - control the behavior of the permission
Options
+:if/:unless+ - :symbol or proc that will be called to evaluate an expression
+enforce+ - set to true to enforce the permission, delete any previous grants given from parent classes. Most meaningful in
combination with +:if+ and +:unless+ options
Example
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :update, :unless => :closed?
end
end
end
The above permits admin and accountant to read accounts, but can update only if the account is not closed. In the example above a method is used to test data on the actual record when testing for permissions.
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
# File 'lib/trust/permissions.rb', line 422 def can(*args) = args. enforce = .delete(:enforce) p = (args).collect { |action| [action, ] } if @in_role_block @perms[:can] += p if enforce @perms[:cannot] = (args).collect { |action| action } end else @@can_expressions += 1 perms = {:can => p } if enforce perms[:cannot] = (args).collect { |action| action } end return perms end end |
.cannot(*args) ⇒ Object
Revokes permissions.
Revokes any previous permissions given in parent classes. This cannot be used with conditions. See also :enforce
option for can
can
has presedence over cannot
. In practice this means that in a block; cannot
statements are processed before can
, and any previously permissions granted are deleted. Another way to say this is; if you have cannot :destroy and can :destroy, then all inheritied destroys will first be deleted, and then the can destroy will be granted.
Arguments
action - actions to be revoked permissions for. Cannot be aliases
Example
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :read
can :update, :destroy, :unless => :closed?
end
end
class Account::Credit < Account
role :accountant do
cannot :destroy # revoke permission to destroy
end
end
end
474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/trust/permissions.rb', line 474 def cannot(*args) = args. raise ArgumentError, "No options (#{.inspect}) are allowed for cannot. It is just meaning less" if .size > 0 p = (args).collect { |action| action } if @in_role_block @perms[:cannot] += p else @@can_expressions += 1 return {:cannot => p } end end |
.member_role(*roles, &block) ⇒ Object Also known as: member_roles
Assign permissions to one or more roles on a member role.
You may call member_role or member_roles, they are the same function like
+member_role :scrum_master+ or +member_roles :scrum_master, :product_owner+
When using this feature, your permission class must respond to members_rols, and return only one role
See role for definition See members_role for how to implement this method
356 357 358 |
# File 'lib/trust/permissions.rb', line 356 def member_role(*roles, &block) self. = _role(self., *roles, &block) end |
.permit(*attrs) ⇒ Object
Assign default permissions for whitelisting paremeter attributes
See ActionController::Parameters.permit for how this works in Rails
311 312 313 |
# File 'lib/trust/permissions.rb', line 311 def permit(*attrs) self.entity_attributes = attrs.dup end |
.require(entity) ⇒ Object
Assign default requirement for whitelisting paremeters
See ActionController::Parameters.require for how this works in Rails
303 304 305 |
# File 'lib/trust/permissions.rb', line 303 def require(entity) self.entity_required = entity end |
.role(*roles, &block) ⇒ Object Also known as: roles
Assign permissions to one or more roles.
You may call role or roles, they are the same function like role :admin or roles :admin, :accountant
There are two ways to call role, with or without block. If you want to set multiple permissions with different conditons then you should use a block.
module Permissions
class Account < Trust::Permissions
role :admin, can(:manage, :audit)
end
end
The above assigns the manage and audit permissions to admin.
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :read
can :update
end
end
end
The above permits admin and accountant to read accounts.
341 342 343 |
# File 'lib/trust/permissions.rb', line 341 def role(*roles, &block) self. = _role(self., *roles, &block) end |
Instance Method Details
#authorized? ⇒ Boolean
Returns params_handler if the user is authorized to perform the action
The handler contains information used by the resource on retrieing parametes later
155 156 157 158 159 160 161 |
# File 'lib/trust/permissions.rb', line 155 def trace 'authorized?', 0, "@user: #{@user.inspect}, @action: #{@action.inspect}, @klass: #{@klass.inspect}, @subject: #{@subject.inspect}, @parent: #{@parent.inspect}" if params_handler = (user && ( || )) params_handler = params_handler_default(params_handler) end params_handler end |
#members_role ⇒ Object
Implement this in your permissions class if using membership roles
One example is that you have teams or projects that have members with role and you want to Authorize against that role instead of any of the roles associated with the user directly
Example:
class Sprint < Trust::Permissions
member_role :scrum_master, can(:update)
def members_role()
@members_role ||= subject.memberships.where(user_id: user.id).first.role_symbol
end
182 183 184 |
# File 'lib/trust/permissions.rb', line 182 def members_role() {} end |
#preload ⇒ Object
163 164 165 166 167 168 |
# File 'lib/trust/permissions.rb', line 163 def preload @preload = true params_handler = || {} @preload = false params_handler end |
#preload? ⇒ Boolean
returns true if permissions are currently being preloaded In new_actions, the framework must load require and permit in order to set permitted variables before the authorization can be evaluated. At that time, the subject is not accessible by permissions. It is not mandatory to use this, but you may test on this in yor permissions file if necessary.
Example:
module Permissions
class Account < Trust::Permissions
role :admin, :accountant do
can :create, :new, require: :account, permit: [:number, :amount, :comment], if: :preload?
can :create, :new, require: :account, permit: [:number, :amount, :comment], if: :valid_amount?, unless: :preload?
end
end
end
212 213 214 |
# File 'lib/trust/permissions.rb', line 212 def preload? @preload end |
#subject_or_parent ⇒ Object
Returns subject if subject is an instance, otherwise parent
188 189 190 |
# File 'lib/trust/permissions.rb', line 188 def subject_or_parent (@subject.nil? || subject.is_a?(Class)) ? parent : subject end |