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:



33
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
# File 'lib/declarative_authorization/in_model.rb', line 33

def self.included(base) # :nodoc:
  base.module_eval do
    # 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

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

      obligation_scope.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)
      options      = args.last.is_a?(Hash) ? args.pop : {}
      privilege    = (args[0] || :read).to_sym
      privileges   = [privilege]
      parent_scope = where(nil)
      context      =
        if options[:context]
          options[:context]
        elsif parent_scope.klass.respond_to?(:decl_auth_context)
          parent_scope.klass.decl_auth_context
        else
          parent_scope.klass.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.klass)
    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
        
        if options[:include_read]
          # 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
        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!



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

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] }) do
    yield if block_given?
  end
end

#permitted_to?(privilege, options = {}) ⇒ 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
# File 'lib/declarative_authorization/in_model.rb', line 11

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]}) do
    yield if block_given?
  end
end