authorizer 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -1
- data/README.rdoc +19 -8
- data/lib/authorizer.rb +1 -1
- data/lib/authorizer/application_controller.rb +17 -18
- data/lib/authorizer/base.rb +74 -65
- data/lib/authorizer/exceptions.rb +5 -1
- metadata +4 -4
data/History.txt
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
+
=== 0.0.2 2011-08-22
|
2
|
+
|
3
|
+
* Major enhancements:
|
4
|
+
* Find function wasn't working properly, a user would get a list of objects from another user. Also reworked its internals so all arguments are passed on to the ActiveRecord::Base find function.
|
5
|
+
* Minor enhancements:
|
6
|
+
* Improved error messages.
|
7
|
+
* Fixed some other bugs and quirks.
|
8
|
+
|
1
9
|
=== 0.0.1 2011-07-01
|
2
10
|
|
3
11
|
* 1 major enhancement:
|
4
|
-
* Initial release
|
12
|
+
* Initial release.
|
data/README.rdoc
CHANGED
@@ -45,13 +45,15 @@ Handles authorization for you.
|
|
45
45
|
Authorize a user on an object
|
46
46
|
|
47
47
|
Authorizer::Base.authorize_user( :object => object )
|
48
|
-
|
49
48
|
=> true/false
|
50
49
|
|
51
50
|
If you want to know if the current user is authorized on an object, use:
|
52
51
|
|
53
|
-
Authorizer::Base.user_is_authorized?( :object => object)
|
52
|
+
Authorizer::Base.user_is_authorized?( :object => object )
|
54
53
|
=> true/false
|
54
|
+
|
55
|
+
Authorizer::Base.authorize!( :object => object, :message => "You are not authorized to access this resource." ) # message is optional
|
56
|
+
=> returns true or raises Authorizer::UserNotAuthorized
|
55
57
|
|
56
58
|
Remove authorization from an object
|
57
59
|
|
@@ -91,16 +93,13 @@ Authorizer uses ActiveRecord observers to make sure it doesn't make any mess, fo
|
|
91
93
|
|
92
94
|
- Ruby (this gem was tested with 1.8.7)
|
93
95
|
- Rails 2.3 (tested with 2.3.11 and 2.3.12)
|
94
|
-
- Authlogic
|
96
|
+
- An authentication mechanism such as Authlogic for authentication (tested with authlogic 2.1.6)
|
95
97
|
|
96
98
|
Optional:
|
97
99
|
- inherited_resources if you want to use the controller filters supplied with this gem. Otherwise, you'll have to check for authorization yourself.
|
98
100
|
|
99
101
|
== INSTALL:
|
100
102
|
|
101
|
-
Installation
|
102
|
-
===
|
103
|
-
|
104
103
|
1. sudo gem install authorizer
|
105
104
|
2. add "authorizer" to your Gemfile (I hope you've stopped using config.gem already even if you are on Rails 2.3?)
|
106
105
|
3. generate a migration for authorization objects:
|
@@ -125,14 +124,26 @@ Paste this code into the newly generated file:
|
|
125
124
|
end
|
126
125
|
|
127
126
|
4. run "rake db:migrate" to migrate your database
|
127
|
+
5. Add these lines to your app/controllers/application_controller.rb:
|
128
|
+
|
129
|
+
require 'authorizer/exceptions'
|
130
|
+
|
131
|
+
rescue_from Authorizer::UserNotAuthorized do |exception|
|
132
|
+
# Show a static 403 page upon authorization failure
|
133
|
+
render :file => "#{Rails.root}/public/403.html", :status => 403
|
134
|
+
end
|
135
|
+
|
136
|
+
6. Download the file public/403.html from {authorizer_project}[https://github.com/cmdjohnson/authorizer_project] and copy it to your own app.
|
128
137
|
|
129
138
|
That's it!
|
130
139
|
|
131
140
|
== DEVELOPERS:
|
132
141
|
|
133
|
-
Reviews, patches and bug tickets are welcome!
|
142
|
+
Reviews, patches and bug tickets are welcome! There's still some features that need to be implemented:
|
143
|
+
- (Multiple) roles for users on an object
|
144
|
+
- Rails 3 support!
|
134
145
|
|
135
|
-
{authorizer_project}[https://github.com/cmdjohnson/authorizer_project] is a sample project that shows the usage of the Authorizer gem. It also contains all tests for your testing pleasure.
|
146
|
+
{authorizer_project}[https://github.com/cmdjohnson/authorizer_project] is a sample project that shows the usage of the Authorizer gem. It also contains all unit and functional tests for your testing pleasure.
|
136
147
|
|
137
148
|
== LICENSE:
|
138
149
|
|
data/lib/authorizer.rb
CHANGED
@@ -17,49 +17,48 @@ class ApplicationController < ActionController::Base
|
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
|
21
|
-
#
|
22
|
-
|
20
|
+
# Own an object (you've just created)
|
21
|
+
# With no arguments given, this method will try to use inherited_resources to determine the object you've just created.
|
22
|
+
# The object can be overridden with :object => object
|
23
|
+
def own_created_object(options = {})
|
24
|
+
ret = false # default answer: don't allow
|
23
25
|
|
24
|
-
|
25
|
-
ret = true # always return true otherwise the filter chain would be blocked.
|
26
|
+
r = options[:object]
|
26
27
|
|
27
28
|
begin
|
28
|
-
r
|
29
|
+
r ||= resource
|
29
30
|
rescue
|
30
31
|
end
|
31
32
|
|
32
33
|
unless r.nil?
|
33
34
|
# only if this objet was successfully created will we do this.
|
34
35
|
unless r.new_record?
|
35
|
-
Authorizer::Base.authorize_user( :object => r )
|
36
|
+
ret = Authorizer::Base.authorize_user( :object => r )
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
40
|
ret
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
+
# Authorize on the current object.
|
44
|
+
# With no arguments given, this method will try to use inherited_resources to determine the object you're supposed to authorize on.
|
45
|
+
# The object can be overridden with :object => object
|
46
|
+
def authorize(options = {})
|
43
47
|
ret = false # return false by default, effectively using a whitelist method.
|
44
48
|
|
49
|
+
r = options[:object]
|
50
|
+
|
45
51
|
begin
|
46
|
-
r
|
52
|
+
r ||= resource
|
47
53
|
rescue
|
48
54
|
end
|
49
55
|
|
50
56
|
unless r.nil?
|
51
|
-
|
52
|
-
|
53
|
-
if auth.eql?(false)
|
54
|
-
raise Authorizer::UserNotAuthorized.new("You are not authorized to access this resource.")
|
55
|
-
end
|
57
|
+
# Use the bang method, it will raise an Exception if needed
|
58
|
+
ret = Authorizer::Base.authorize!( :object => r )
|
56
59
|
end
|
57
60
|
|
58
61
|
ret
|
59
62
|
end
|
60
|
-
|
61
|
-
##############################################################################
|
62
|
-
# end authorizer
|
63
|
-
##############################################################################
|
64
63
|
end
|
65
64
|
|
data/lib/authorizer/base.rb
CHANGED
@@ -40,20 +40,44 @@ module Authorizer
|
|
40
40
|
object_reference = object.id
|
41
41
|
|
42
42
|
ObjectRole.create!( :klazz_name => klazz_name, :object_reference => object_reference, :user => user, :role => role )
|
43
|
-
Rails.logger.debug("Authorizer: created authorization on #{object} for current_user with ID #{user.id}
|
43
|
+
Rails.logger.debug("Authorizer: created authorization on #{object} for current_user with ID #{user.id} with role #{role}")
|
44
44
|
ret = true
|
45
45
|
end
|
46
46
|
|
47
47
|
ret
|
48
48
|
end
|
49
49
|
|
50
|
+
############################################################################
|
51
|
+
# authorize!
|
52
|
+
#
|
53
|
+
# Bang version of authorize
|
54
|
+
############################################################################
|
55
|
+
|
56
|
+
def self.authorize! options = {}
|
57
|
+
auth_ok = user_is_authorized?(options)
|
58
|
+
|
59
|
+
# User can override error message
|
60
|
+
message = options[:message]
|
61
|
+
# Attempt to fetch from I18n
|
62
|
+
begin
|
63
|
+
message ||= I18n.translate!("authorizer.access_denied")
|
64
|
+
rescue
|
65
|
+
end
|
66
|
+
# Default error message
|
67
|
+
message ||= "You are not authorized to access this resource."
|
68
|
+
|
69
|
+
raise Authorizer::UserNotAuthorized.new(message) unless auth_ok
|
70
|
+
|
71
|
+
auth_ok
|
72
|
+
end
|
73
|
+
|
50
74
|
############################################################################
|
51
75
|
# user_is_authorized?
|
52
76
|
#
|
53
77
|
# If no user is specified, current_user is used.
|
54
78
|
############################################################################
|
55
79
|
|
56
|
-
def self.user_is_authorized? options
|
80
|
+
def self.user_is_authorized? options = {}
|
57
81
|
OptionsChecker.check(options, [ :object ])
|
58
82
|
|
59
83
|
ret = false
|
@@ -78,12 +102,17 @@ module Authorizer
|
|
78
102
|
if ret
|
79
103
|
Rails.logger.debug("Authorizer: authorized current_user with ID #{user.id} to access #{or_.description} because of role #{or_.role}") unless user.nil? || or_.nil?
|
80
104
|
else
|
81
|
-
Rails.logger.debug("Authorizer: authorization failed for current_user with ID #{user.id} to access #{object.
|
105
|
+
Rails.logger.debug("Authorizer: authorization failed for current_user with ID #{user.id} to access #{object.inspect}") unless user.nil? || object.nil?
|
82
106
|
end
|
83
107
|
|
84
108
|
ret
|
85
109
|
end
|
86
110
|
|
111
|
+
# Could't get alias_method to work. Don't ask me why.
|
112
|
+
def self.authorize(options = {})
|
113
|
+
user_is_authorized?(options)
|
114
|
+
end
|
115
|
+
|
87
116
|
############################################################################
|
88
117
|
# remove_authorization
|
89
118
|
############################################################################
|
@@ -120,8 +149,7 @@ module Authorizer
|
|
120
149
|
############################################################################
|
121
150
|
# find
|
122
151
|
############################################################################
|
123
|
-
#
|
124
|
-
# External method that maps to the internal_find which is the generic find method.
|
152
|
+
# From the entire collection of Posts, return the subset that belongs to the current user.
|
125
153
|
#
|
126
154
|
# Arguments:
|
127
155
|
# - class_name: which class to use, e.g. "Post"
|
@@ -139,8 +167,6 @@ module Authorizer
|
|
139
167
|
|
140
168
|
############################################################################
|
141
169
|
# is_authorized?
|
142
|
-
#
|
143
|
-
# Checks if the corresponding role.eql?("owner")
|
144
170
|
############################################################################
|
145
171
|
|
146
172
|
def self.is_authorized? object
|
@@ -198,80 +224,54 @@ module Authorizer
|
|
198
224
|
class_name = options[:class_name]
|
199
225
|
what = options[:what]
|
200
226
|
find_options = options[:find_options] || {}
|
201
|
-
user = options[:user] || get_current_user
|
202
|
-
|
203
|
-
# We don't do the what checks anymore, ActiveRecord::Base.find does that for us now.
|
204
|
-
#what_checks = [ :all, :first, :last, :id ]
|
205
|
-
#raise "What must be one of #{what_checks.inspect}" unless what_checks.include?(what)
|
227
|
+
user = options[:user] || get_current_user # Default is current user, but the specified user will override.
|
206
228
|
|
207
229
|
# Check userrrrrrrrrrrr --- =====================- ---= ===-=- *&((28 @((8
|
208
230
|
check_user(user)
|
209
|
-
# rrrr
|
210
231
|
ret = nil
|
211
|
-
# Checks
|
212
232
|
# Checks done. Let's go.
|
213
233
|
# Get the real klazz
|
214
234
|
klazz = nil
|
215
235
|
# Check it
|
216
236
|
begin
|
217
237
|
klazz = eval(class_name)
|
218
|
-
rescue
|
238
|
+
rescue => e
|
239
|
+
# Throw an exception if klazz is nil
|
240
|
+
raise ArgumentError.new("Could not eval class '#{klazz}'. It presumably does not exist. Maybe you mistyped its name? Error was: #{e.inspect}") if klazz.nil?
|
219
241
|
end
|
220
242
|
# oooo ooo ooo ___ --- === __- --_- ++_+_ =--- +- =+=-=- =-= <--- ice beam!
|
221
243
|
unless klazz.nil?
|
222
244
|
# now we know klazz really exists.
|
223
|
-
# let's find the object_role objects that match the user and
|
245
|
+
# let's find the object_role objects that match the user and klazz.
|
224
246
|
# Get the object_role objects
|
225
247
|
object_roles_conditions = { :klazz_name => class_name, :user_id => user.id }
|
226
248
|
object_roles = ObjectRole.find(:all, :conditions => object_roles_conditions )
|
227
|
-
#
|
228
|
-
|
229
|
-
# Make it at least an array if object_role_ids returns nil
|
230
|
-
object_role_ids ||= []
|
231
|
-
# Try to emulate find as good as we can
|
232
|
-
# so don't skip this, try to always pass it on.
|
249
|
+
# OK.
|
250
|
+
# We already have the comprehensive list of object roles we are authorized on.
|
233
251
|
unless object_roles.nil?
|
234
|
-
#
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
# FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND
|
257
|
-
# FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND FIND
|
258
|
-
if safe_what.eql?(:all)
|
259
|
-
ret = klazz.find(:all, my_find_options)
|
260
|
-
elsif safe_what.eql?(:first)
|
261
|
-
ret = klazz.find(object_role_ids.first, my_find_options)
|
262
|
-
elsif safe_what.eql?(:last)
|
263
|
-
ret = klazz.find(object_role_ids.last, my_find_options)
|
264
|
-
else
|
265
|
-
ret = klazz.find(safe_what, my_find_options)
|
252
|
+
# Get a list of IDs. These are objects that are owned by the current_user
|
253
|
+
object_role_ids = object_roles.collect { |or_| or_.object_reference } # [ 1, 1, 1, 1 ]
|
254
|
+
# Make it at least an array if collect returns nil
|
255
|
+
object_role_ids ||= []
|
256
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
257
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
258
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
259
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
260
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
261
|
+
# DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT DO IT
|
262
|
+
unless object_role_ids.nil?
|
263
|
+
# Prepare find_options
|
264
|
+
leading_find_options = {} # insert conventions here if needed, maybe for security or other purposes
|
265
|
+
my_find_options = find_options.merge(leading_find_options)
|
266
|
+
# Big chance object_role_ids equals an Empty Array (TM) or []
|
267
|
+
# That's good, it means this line will be
|
268
|
+
#
|
269
|
+
# Post.scoped_by_id([]).find(:all)
|
270
|
+
#
|
271
|
+
# Which will never ever return anything.
|
272
|
+
# This is also good because it means we can just proxy whatever we get from the user into Find and it will take care of it for us.
|
273
|
+
ret = klazz.scoped_by_id(object_role_ids).find(what, my_find_options) # scoped_by is new in 2.3. sweeeeeeeeeeeet
|
266
274
|
end
|
267
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
268
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
269
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
270
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
271
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
272
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
273
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
274
|
-
# SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT???? SAFE WHAT????
|
275
275
|
end
|
276
276
|
end
|
277
277
|
|
@@ -310,9 +310,18 @@ module Authorizer
|
|
310
310
|
def self.check_user(user)
|
311
311
|
ret = true
|
312
312
|
|
313
|
-
|
314
|
-
|
315
|
-
|
313
|
+
if user.nil?
|
314
|
+
raise Authorizer::RuntimeException.new "User cannot be nil. Maybe you should specify authorizer_options = { :user => user } if you are not calling from a controller?"
|
315
|
+
end
|
316
|
+
|
317
|
+
unless user.is_a?(ActiveRecord::Base)
|
318
|
+
raise Authorizer::RuntimeException.new "User must inherit from ActiveRecord::Base"
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
if user.new_record?
|
323
|
+
raise Authorizer::RuntimeException.new "User must be saved"
|
324
|
+
end
|
316
325
|
|
317
326
|
ret
|
318
327
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
module Authorizer
|
3
|
+
# Thrown when the user is not authorized.
|
3
4
|
class UserNotAuthorized < Exception
|
4
|
-
|
5
|
+
end
|
6
|
+
|
7
|
+
# Thrown when an internal error occurs, such as when an ObjectRole record doesn't exist.
|
8
|
+
class RuntimeException < Exception
|
5
9
|
end
|
6
10
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authorizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- CmdJohnson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-22 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|