Module: Walruz::Utils

Included in:
Policy
Defined in:
lib/walruz/utils.rb

Overview

This module provides pretty handy methods to do compositions of basic policies to create more complex ones.

Using a policies file to manage complex policies

It’s always a good idea to keep the policy composition in one place, you may place a file in your project where you manage all the authorization policies, and then you use them on your models.

Say for example you have a lib/policies.rb in your project where you manage the composition of policies, and a lib/policies folder where you create your custom policies.

The lib/policies.rb file could be something like this:

module Policies
  include Walruz::Utils 

  # Requiring basic Walruz::Policy classes
  BASE = File.join(File.dirname(__FILE__), "policies") unless defined?(BASE)
  require File.join(BASE, "actor_is_admin")
  require File.join(BASE, "user_is_owner")
  require File.join(BASE, "user_is_friend")

  #####
  # User Policies
  #
  UserCreatePolicy  = ActorIsAdmin
  UserReadPolicy    = any(UserIsOwner, UserIsFriend, ActorIsAdmin)
  UserUpdatePolicy  = any(UserIsOwner, ActorIsAdmin)
  UserDestroyPolicy = ActorIsAdmin

end

Using a policies file on your project, keeps all your authorization logic just in one place that way, when you change the authorizations you just have to go to one place only.

Defined Under Namespace

Modules: PolicyCompositionHelper

Class Method Summary collapse

Class Method Details

.all(*policies) ⇒ Walruz::Policy

Generates a new policy that merges together different policies by an AND association. This will execute every policy on the list, if all of them return true then the policy will succeed. This process will merge the parameters of each policy, so you may be able to use the parameters of previous policies, and at the end it will return all the parameters from every policy.

Parameters:

  • A (Array<Walruz::Policy>)

    set of policies that will be merged by an AND association.

Returns:

  • (Walruz::Policy)

    A new policy class that will check true for each policy.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/walruz/utils.rb', line 108

def all(*policies)
  clazz = Class.new(Walruz::Policy) do # :nodoc:
    extend PolicyCompositionHelper
    
    def authorized?(actor, subject) # :nodoc:
      acum = [true, self.params || {}]
      self.class.policies.each do |policy|
        break unless acum[0]
        result = policy.new.set_params(acum[1]).safe_authorized?(actor, subject)
        acum[0] &&= result[0]
        acum[1].merge!(result[1])
      end
      acum[0] ? acum : acum[0]
    end
    
    def self.policy_keyword # :nodoc:
      (self.policies.map { |p| p.policy_keyword.to_s[0..-2] }.join('_and_') + "?").to_sym
    end
    
  end
  clazz.policies = policies
  clazz
end

.any(*policies) ⇒ Walruz::Policy

Generates a new policy that merges together different policies by an OR association. As soon as one of the policies succeed, the parameters of that policy will be returned.

Examples:

UserReadPolicy = any(UserIsOwner, UserIsAdmin)

Parameters:

  • A (Array<Walruz::Policy>)

    set of policies that will be merged by an OR association.

Returns:

  • (Walruz::Policy)

    A new policy class that will execute each policy until one of them succeeds.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/walruz/utils.rb', line 81

def any(*policies)
  clazz = Class.new(Walruz::Policy) do # :nodoc:
    extend PolicyCompositionHelper
    
    def authorized?(actor, subject) # :nodoc:
      result = nil
      self.class.policies.detect do |policy|
        result = policy.new.set_params(params).safe_authorized?(actor, subject)
        result[0]
      end
      result[0] ? result : result[0]
    end
  
  end
  clazz.policies = policies
  clazz
end

.negate(policy) ⇒ Object

Generates a new policy that negates the result of the given policy.

Parameters:

  • The (Walruz::Policy)

    policy which result is going to be negated.

  • A (Walruz::Policy)

    new policy that will negate the result of the given policy.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/walruz/utils.rb', line 137

def negate(policy)
  clazz = Class.new(Walruz::Policy) do # :nodoc:
    extend PolicyCompositionHelper
    
    # :nodoc:
    def authorized?(actor, subject)
      result = self.class.policy.new.set_params(params).safe_authorized?(actor, subject)
      result[0] = !result[0]
      result
    end
    
    
    def self.policy_keyword # :nodoc:
      keyword = self.policy.policy_keyword.to_s[0..-2]
      :"not(#{keyword})?"
    end
    
  end
  clazz.policy = policy
  clazz
end