Module: Authorization::AuthorizationInModel

Defined in:
lib/declarative_authorization/in_model.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/declarative_authorization/in_model.rb', line 34

def self.included(base) # :nodoc:
  #base.extend(ClassMethods)
  base.module_eval do
    scopes[:with_permissions_to] = lambda do |parent_scope, *args|
      options = args.last.is_a?(Hash) ? args.pop : {}
      privilege = (args[0] || :read).to_sym
      privileges = [privilege]
      context =
          if options[:context]
            options[:context]
          elsif parent_scope.respond_to?(:proxy_reflection)
            parent_scope.proxy_reflection.klass.name.tableize.to_sym
          elsif parent_scope.respond_to?(:decl_auth_context)
            parent_scope.decl_auth_context
          else
            parent_scope.name.tableize.to_sym
          end
      
      user = options[:user] || Authorization.current_user

      engine = options[:engine] || Authorization::Engine.instance
      engine.permit!(privileges, :user => user, :skip_attribute_test => true,
                     :context => context)

      obligation_scope_for( privileges, :user => user,
          :context => context, :engine => engine, :model => parent_scope)
    end
    
    # Builds and returns a scope with joins and conditions satisfying all obligations.
    def self.obligation_scope_for( privileges, options = {} )
      options = {
        :user => Authorization.current_user,
        :context => nil,
        :model => self,
        :engine => nil,
      }.merge(options)
      engine = options[:engine] || Authorization::Engine.instance

      scope = ObligationScope.new( options[:model], {} )
      engine.obligations( privileges, :user => options[:user], :context => options[:context] ).each do |obligation|
        scope.parse!( obligation )
      end
      scope
    end

    # Named scope for limiting query results according to the authorization
    # of the current user.  If no privilege is given, :+read+ is assumed.
    # 
    #   User.with_permissions_to
    #   User.with_permissions_to(:update)
    #   User.with_permissions_to(:update, :context => :users)
    #   
    # As in the case of other named scopes, this one may be chained:
    #   User.with_permission_to.find(:all, :conditions...)
    # 
    # Options
    # [:+context+]
    #   Context for the privilege to be evaluated in; defaults to the
    #   model's table name.
    # [:+user+]
    #   User to be used for gathering obligations; defaults to the
    #   current user.
    #
    def self.with_permissions_to (*args)
      scopes[:with_permissions_to].call(self, *args)
    end
    
    # Activates model security for the current model.  Then, CRUD operations
    # are checked against the authorization of the current user.  The
    # privileges are :+create+, :+read+, :+update+ and :+delete+ in the
    # context of the model.  By default, :+read+ is not checked because of
    # performance impacts, especially with large result sets.
    # 
    #   class User < ActiveRecord::Base
    #     using_access_control
    #   end
    #   
    # If an operation is not permitted, a Authorization::AuthorizationError
    # is raised.
    #
    # To activate model security on all models, call using_access_control
    # on ActiveRecord::Base
    #   ActiveRecord::Base.using_access_control
    # 
    # Available options
    # [:+context+] Specify context different from the models table name.
    # [:+include_read+] Also check for :+read+ privilege after find.
    #
    def self.using_access_control (options = {})
      options = {
        :context => nil,
        :include_read => false
      }.merge(options)

      class_eval do
        [:create, :update, [:destroy, :delete]].each do |action, privilege|
          send(:"before_#{action}") do |object|
            Authorization::Engine.instance.permit!(privilege || action,
              :object => object, :context => options[:context])
          end
        end

        # after_find is only called if after_find is implemented
        after_find do |object|
          Authorization::Engine.instance.permit!(:read, :object => object,
            :context => options[:context])
        end
        
        if options[:include_read]
          def after_find; end
        end

        def self.using_access_control?
          true
        end
      end
    end

    # Returns true if the model is using model security.
    def self.using_access_control?
      false
    end
  end
end

Instance Method Details

#permitted_to!(privilege, options = {}) ⇒ Object

Works similar to the permitted_to? method, but doesn’t accept a block and throws the authorization exceptions, just like Engine#permit!



24
25
26
27
28
29
30
31
32
# File 'lib/declarative_authorization/in_model.rb', line 24

def permitted_to! (privilege, options = {} )
  options = {
    :user =>  Authorization.current_user,
    :object => self
  }.merge(options)
  Authorization::Engine.instance.permit!(privilege,
      {:user => options[:user],
       :object => options[:object]})
end

#permitted_to?(privilege, options = {}, &block) ⇒ Boolean

If the user meets the given privilege, permitted_to? returns true and yields to the optional block.

Returns:

  • (Boolean)


11
12
13
14
15
16
17
18
19
20
# File 'lib/declarative_authorization/in_model.rb', line 11

def permitted_to? (privilege, options = {}, &block)
  options = {
    :user =>  Authorization.current_user,
    :object => self
  }.merge(options)
  Authorization::Engine.instance.permit?(privilege,
      {:user => options[:user],
       :object => options[:object]},
      &block)
end