role_based_authorization 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/MIT-LICENSE +20 -0
- data/README +150 -0
- data/Rakefile +40 -0
- data/VERSION +1 -0
- data/lib/role_based_authorization.rb +2 -0
- data/lib/role_based_authorization/authorization_logger.rb +7 -0
- data/lib/role_based_authorization/role_based_authorization.rb +215 -0
- data/rails/init.rb +2 -0
- data/role_based_authorization.gemspec +52 -0
- data/test/role_based_authorization_test.rb +86 -0
- data/test/test_helper.rb +9 -0
- metadata +67 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
= RoleBasedAuthorization
|
2
|
+
|
3
|
+
|
4
|
+
This plugin provide a very simple authorization system. It should work fine with
|
5
|
+
most of the authentication plugins (and gems) out there, even though little testing
|
6
|
+
has been done in this regard. There are a lot of similar plugin/gems and probably
|
7
|
+
this is not better than any others (see for instance the)
|
8
|
+
|
9
|
+
Installation:
|
10
|
+
* install the plugin using:
|
11
|
+
---
|
12
|
+
---
|
13
|
+
* in your application controller: include the module RoleBasedAuthorization:
|
14
|
+
|
15
|
+
class ApplicationController < ActionController::Base
|
16
|
+
[...]
|
17
|
+
include RoleBasedAuthorization
|
18
|
+
[...]
|
19
|
+
end
|
20
|
+
|
21
|
+
* in your controller classes: use the permission statements (described below) to grant and deny authorizations to the controller methods.
|
22
|
+
|
23
|
+
|
24
|
+
The inclusion of RoleBasedAuthorization serves three purposes: it allows subclasses of the application controller to use the 'permit' method during their definition, it and provides an "authorized?" method that implements the authorization logic, and it creates an helper method to be used in views.
|
25
|
+
|
26
|
+
== Requirements
|
27
|
+
|
28
|
+
|
29
|
+
The plugin poses few and very reasonable constraints on your application. Namely, it requires:
|
30
|
+
|
31
|
+
|
32
|
+
* that your controllers provide a 'current_user' method
|
33
|
+
* that the user object (returned by the 'current_user' method) implements the following two methods:
|
34
|
+
* role: returning the role of the current user; roles can be anything (I personally use integers). This is usually implemented by adding a 'role' column to your model.
|
35
|
+
* description: used for logging purposes
|
36
|
+
|
37
|
+
== Permission statements
|
38
|
+
|
39
|
+
|
40
|
+
You can specify your authorization logic by adding a number of 'permit' calls to your controllers. Permissions granted in a controller apply to all its subclasses. Since usually all controllers inherit from the application controller, this allows one to authorize all actions for the 'admin' role by telling it so in the application controller.
|
41
|
+
|
42
|
+
An important thing to keep in mind is that the plugin assumes that EVERYTHING IS FORBIDDEN unless otherwise specified. Then, if you do not specify any permission rule, you will end up with a very secure (though useless) application.
|
43
|
+
|
44
|
+
The permission statement takes the form:
|
45
|
+
|
46
|
+
permit :actions => [list of actions],
|
47
|
+
:to => [list of roles],
|
48
|
+
:if => lambda_expression,
|
49
|
+
:object_id => object_id_symbol
|
50
|
+
|
51
|
+
you can add any number of these in anyone of your controller.
|
52
|
+
|
53
|
+
permit options:
|
54
|
+
|
55
|
+
<b>:to</b>::
|
56
|
+
the list of roles interested by this rule. The actual contents of this list depends on what your application defines to be a role. If you use integers, it could be a vector like [1,4] or as [ROOT, ADMIN], where ROOT and ADMIN are symbolic costants containing the corresponding integer values. You can specify all roles by specifying :all in place of the role list.
|
57
|
+
|
58
|
+
<b>:actions</b>::
|
59
|
+
the list of actions that are permitted to the mentioned roles. Actions are actual method names of the current controller and can be given as symbols or as strings. For instance ['index', 'show'] is equivalent to [:index, :show]. You can grant access to all actions by specifying :all instead of the action list.
|
60
|
+
|
61
|
+
<b>:if</b>::
|
62
|
+
a lambda expression that verifies additional conditions. The lambda expression takes two arguments: the current user and the id of an object. For instance you may want to verify that "normal" users could only modify objects that they own. You can say that by specifying:
|
63
|
+
permit :actions => [:edit, :update],
|
64
|
+
:to => [NORMAL],
|
65
|
+
:if => lambda { |user, obj_id| TheObject.find(obj_id).owner == user }
|
66
|
+
|
67
|
+
<b>:object_id</b>::
|
68
|
+
normally the object id passed to the lambda expression of the :if option is retrieved from the params hash using :id (i.e. normally obj_id = params[:id]), you can specify other identifiers using this option, e.g.:
|
69
|
+
:object_id => :product_id
|
70
|
+
specifies that :product_id should be used instead of :id.
|
71
|
+
|
72
|
+
== authorized?
|
73
|
+
|
74
|
+
The plugin adds an authorized? method to your application controller. The method returns false if one of the following conditions occur:
|
75
|
+
* your controller defines a logged_in? method and the method returns false
|
76
|
+
* no permit rule matches the current settings
|
77
|
+
|
78
|
+
== authorize_action?
|
79
|
+
|
80
|
+
This is a more general version of :authorized?. The difference between the two is that authorized? uses the current environment (action called, controller name, etc.) to decide whether the current action is to be authorized, authorize_action? instead gets an hash of options containing an action name, a controller name, and some other optional parameters and returns if the specified action on the given controller is authorized for the current user (or for the user specified in the option hash).
|
81
|
+
|
82
|
+
|
83
|
+
== if_authorized? helper method
|
84
|
+
|
85
|
+
It often happens that parts of a view is to be displayed only if a given action is authorized. This clutters your view with code like:
|
86
|
+
|
87
|
+
if authorize_action?(:controller => xxx, :action => yyy) .... link_to 'zzz', :controller => xxx, :action => yyy end
|
88
|
+
|
89
|
+
clearly there is a lot of duplication in this code. if_authorized? takes the same parameters as authorize_action? and a block. The block is called only if authorize_action? returns true and the parameters are passed to the block. This allows to clean up your view as follows:
|
90
|
+
|
91
|
+
if_authorized?(:controller => xxx, :action => yyy) do |opts|
|
92
|
+
...
|
93
|
+
link_to 'zzz', opts
|
94
|
+
end
|
95
|
+
|
96
|
+
This works also if you use resource paths as in:
|
97
|
+
|
98
|
+
if_authorized?( edit_product_path ) do |opts|
|
99
|
+
link_to 'zzz', opts
|
100
|
+
end
|
101
|
+
|
102
|
+
== Logging
|
103
|
+
|
104
|
+
The authorization system logs each access attempt to RAILS_ROOT/log/authorization.log. If the log level is high enough, you will also view an explanation of what is happening and why.
|
105
|
+
|
106
|
+
|
107
|
+
== Examples
|
108
|
+
|
109
|
+
I usually add a Roles class to my project (I place it in the model directory even though it is not connected to any db table). It's definition is:
|
110
|
+
|
111
|
+
class Role
|
112
|
+
# define below valid roles for your application
|
113
|
+
ROLES = { :user => 1, :administrator => 2, :root => 3 }
|
114
|
+
|
115
|
+
# call this function in your permit actions
|
116
|
+
def Role.[](role)
|
117
|
+
role = ROLES[role]
|
118
|
+
raise "given role '#{role}' is not valid" if role.nil?
|
119
|
+
return role
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
This allows me to write Role[:root] to specify the root role.
|
124
|
+
|
125
|
+
Example 1: Grant all powers to the root role (this rule is usually found in your application controller)
|
126
|
+
|
127
|
+
permit :actions => :all, :to => Role[:root]
|
128
|
+
|
129
|
+
Example 2: Grant view actions to normal users, edit actions to administrators
|
130
|
+
|
131
|
+
permit :actions => [:index, :show],
|
132
|
+
:to => Role[:user]
|
133
|
+
permit :actions => [:edit, :update, :destroy],
|
134
|
+
:to => Role[:admin]
|
135
|
+
|
136
|
+
Example 3: Adding a rule to allow users to edit their own data (let us assume that the controller manages objects of type Product):
|
137
|
+
|
138
|
+
permit :actions => [:edit, :update],
|
139
|
+
:to => Role[:user].
|
140
|
+
:if => lambda { |user, obj_id| Product.find(obj_id).owner == user }
|
141
|
+
|
142
|
+
Example 4: Let us assume that the current controller does not manage products, but that you want to check for the product owner anyway. In this case, the product id will not be passed as the :id object into your params hash and the above rule will fail. Amend this problem by telling the permit action how to retrieve the correct id:
|
143
|
+
|
144
|
+
permit :actions => [:edit, :update],
|
145
|
+
:to => Role[:user].
|
146
|
+
:if => lambda { |user, obj_id| Product.find(obj_id).owner == user },
|
147
|
+
:object_id => :product_id
|
148
|
+
|
149
|
+
|
150
|
+
Copyright (c) 2010 Roberto Esposito, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the role_based_authorization plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the role_based_authorization plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'RoleBasedAuthorization'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'jeweler'
|
28
|
+
Jeweler::Tasks.new do |gemspec|
|
29
|
+
gemspec.name = "role_based_authorization"
|
30
|
+
gemspec.summary = "Basic authorization module for rails"
|
31
|
+
gemspec.description = "Provides a simple DSL for specifying the authorization logic" +
|
32
|
+
" of your application. Install the gem, add a role attribute" +
|
33
|
+
" to your user model and your almost ready to go."
|
34
|
+
gemspec.email = "boborbt@gmail.com"
|
35
|
+
gemspec.homepage = "http://github.com/boborbt/role_based_authorization"
|
36
|
+
gemspec.authors = ["Roberto Esposito"]
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
40
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,215 @@
|
|
1
|
+
module RoleBasedAuthorization
|
2
|
+
# AuthorizationLogger instance that is used throughout the plugin for logging
|
3
|
+
# events.
|
4
|
+
AUTHORIZATION_LOGGER = AuthorizationLogger.new(File.join(RAILS_ROOT,'log','authorization.log'))
|
5
|
+
|
6
|
+
module ClassMethods; end
|
7
|
+
|
8
|
+
# Fires when the module is included into the controllers. It adds all class methods
|
9
|
+
# defined in the ClassMethods sub-module and the authorize_action? and if_authorized?
|
10
|
+
# instance methods.
|
11
|
+
def self.included(klass)
|
12
|
+
klass.extend(ClassMethods)
|
13
|
+
|
14
|
+
klass.class_eval do
|
15
|
+
helper_method :authorize_action?
|
16
|
+
helper_method :if_authorized?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Defines the class methods that are to be added to the application controller
|
21
|
+
module ClassMethods
|
22
|
+
# Returns the set of rules defined on this controller
|
23
|
+
def role_auth_rules
|
24
|
+
@@rules||={}
|
25
|
+
@@rules
|
26
|
+
end
|
27
|
+
|
28
|
+
# Defines the DSL for the authorization system. The syntax is:
|
29
|
+
# permit :actions => [list of actions],
|
30
|
+
# :to => [list of roles],
|
31
|
+
# :if => lambda_expression,
|
32
|
+
# :object_id => object_id_symbol
|
33
|
+
#
|
34
|
+
# you can add any number of these in anyone of your controller.
|
35
|
+
#
|
36
|
+
# options:
|
37
|
+
#
|
38
|
+
# <b>:to</b>::
|
39
|
+
# the list of roles interested by this rule. The actual contents of this list depends on what your application defines to be a role. If you use integers, it could be a vector like [1,4] or as [ROOT, ADMIN], where ROOT and ADMIN are symbolic costants containing the corresponding integer values. You can specify all roles by specifying :all in place of the role list.
|
40
|
+
#
|
41
|
+
# <b>:actions</b>::
|
42
|
+
# the list of actions that are permitted to the mentioned roles. Actions are actual method names of the current controller and can be given as symbols or as strings. For instance ['index', 'show'] is equivalent to [:index, :show]. You can grant access to all actions by specifying :all instead of the action list.
|
43
|
+
#
|
44
|
+
# <b>:if</b>::
|
45
|
+
# a lambda expression that verifies additional conditions. The lambda expression takes two arguments: the current user and the id of an object. For instance you may want to verify that "normal" users could only modify objects that they own. You can say that by specifying:
|
46
|
+
# permit :actions => [:edit, :update],
|
47
|
+
# :to => [NORMAL],
|
48
|
+
# :if => lambda { |user, obj_id| TheObject.find(obj_id).owner == user }
|
49
|
+
#
|
50
|
+
# <b>:object_id</b>::
|
51
|
+
# normally the object id passed to the lambda expression of the :if option is retrieved from the params hash using :id (i.e. normally obj_id = params[:id]), you can specify other identifiers using this option, e.g.:
|
52
|
+
# :object_id => :product_id
|
53
|
+
# specifies that :product_id should be used instead of :id.
|
54
|
+
|
55
|
+
def permit options
|
56
|
+
options[:controller] ||= controller_name
|
57
|
+
controller = options[:controller]
|
58
|
+
role_auth_rules[controller] ||= {}
|
59
|
+
|
60
|
+
if options[:actions] == :all
|
61
|
+
role_auth_rules[controller][:all] ||= []
|
62
|
+
role_auth_rules[controller][:all] << RoleBasedAuthorization::Rule.new(options[:to], options[:if], options[:object_id])
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
options[:actions].each do |action|
|
67
|
+
action = action.to_s # this allows for both symbols and strings to be used for action names
|
68
|
+
role_auth_rules[controller][action] ||= []
|
69
|
+
role_auth_rules[controller][action] << RoleBasedAuthorization::Rule.new(options[:to], options[:if], options[:object_id])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Model an authorization rule. A rule is a triplet: <roles, cond, object_id>
|
76
|
+
# a rule match if the user role is in roles and cond (if not nil) is satisfied when objects
|
77
|
+
# are retrieved using object_id.
|
78
|
+
class Rule
|
79
|
+
# rule initialization. roles is mandatory, cond is optional, object_id defaults
|
80
|
+
# to :id if nil.
|
81
|
+
def initialize roles, cond, object_id
|
82
|
+
roles = [roles] unless roles.respond_to? :each
|
83
|
+
|
84
|
+
@roles = roles
|
85
|
+
@cond = cond
|
86
|
+
@object_id = object_id || :id
|
87
|
+
end
|
88
|
+
|
89
|
+
# return true if this rule matches the given user and objects
|
90
|
+
def match(user, objects)
|
91
|
+
AUTHORIZATION_LOGGER.debug('trying '+self.inspect)
|
92
|
+
|
93
|
+
matching = @roles.include?(:all)
|
94
|
+
|
95
|
+
# checking for right role (no need to check them if already matching)
|
96
|
+
matching = !@roles.find { |role| role == user.role }.nil? if !matching
|
97
|
+
|
98
|
+
if @cond.nil?
|
99
|
+
return matching
|
100
|
+
else
|
101
|
+
# to have a proper match, also the condition must hold
|
102
|
+
return matching && @cond.call(user,objects[@object_id])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# string representation for this rule
|
107
|
+
def inspect
|
108
|
+
str = "rule(#{self.object_id}): allow roles [" + @roles.join(',') + "]"
|
109
|
+
str += " (only under condition object_id will be retrieved using '#{@object_id}')" if @cond
|
110
|
+
|
111
|
+
str
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Main authorization logic. opts is an hash with the following keys
|
116
|
+
# :user, :controller, :action:: self explanatory
|
117
|
+
# :ids:: id to be used to retrieve relevant objects
|
118
|
+
def authorize_action? opts = {}
|
119
|
+
if defined?(logged_in?) && !logged_in?
|
120
|
+
AUTHORIZATION_LOGGER.info("returning false (not logged in)")
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
|
124
|
+
opts[:ids] ||= {}
|
125
|
+
opts[:ids].reverse_merge!( opts.reject { |k,v| k.to_s !~ /(_id\Z)|(\Aid\Z)/ } )
|
126
|
+
|
127
|
+
if opts[:user].nil? && defined?(current_user)
|
128
|
+
opts[:user] = current_user
|
129
|
+
end
|
130
|
+
|
131
|
+
if opts[:controller].nil? && defined?(controller_name)
|
132
|
+
opts[:controller] = controller_name
|
133
|
+
end
|
134
|
+
|
135
|
+
AUTHORIZATION_LOGGER.info("user %s requested access to method %s:%s using ids:%s" %
|
136
|
+
[ opts[:user] && opts[:user].description + "(id:#{opts[:user].id} role:#{opts[:user].role})" || 'none',
|
137
|
+
opts[:controller],
|
138
|
+
opts[:action],
|
139
|
+
opts[:ids].inspect])
|
140
|
+
|
141
|
+
rules = self.class.role_auth_rules
|
142
|
+
AUTHORIZATION_LOGGER.debug("current set of rules: %s" % [rules.inspect])
|
143
|
+
|
144
|
+
([opts[:controller]] | ['application']).each do |controller|
|
145
|
+
if( !controller.blank? && rules[controller].nil? )
|
146
|
+
# tries to load the controller. Rails automagically loads classes if their name
|
147
|
+
# is used anywhere. By trying to constantize the name of the controller, we
|
148
|
+
# force rails to load it.
|
149
|
+
controller_klass = (controller.to_s+'_controller').camelize.constantize
|
150
|
+
end
|
151
|
+
|
152
|
+
AUTHORIZATION_LOGGER.debug("current controller: %s" % [controller])
|
153
|
+
|
154
|
+
[:all, opts[:action]].each do |action|
|
155
|
+
AUTHORIZATION_LOGGER.debug('current action: %s' % [action])
|
156
|
+
|
157
|
+
raise "Action should be a string -- not a #{action.class.name}!" if action!=:all && action.class!=String
|
158
|
+
|
159
|
+
next if rules[controller].nil? || rules[controller][action].nil?
|
160
|
+
if rules[controller][action].find { |rule| rule.match(opts[:user], opts[:ids]) }
|
161
|
+
AUTHORIZATION_LOGGER.info('returning true (access granted)')
|
162
|
+
return true
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
AUTHORIZATION_LOGGER.info('returning false (access denied)')
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
# This is a helper method that provides a conditional execution syntax for
|
173
|
+
# a block of code. It is mainly useful because in most cases the same options
|
174
|
+
# that are needed for the authorization are also needed for url generation.
|
175
|
+
# Since this method forward those options to the block, it allows to write
|
176
|
+
# something like:
|
177
|
+
# if_authorized? {:controller => xxx, :action => yyy} {|opts| link_to('yyy', opts) }
|
178
|
+
# instead of:
|
179
|
+
# if authorized_action? {:controller => xxx, :action => yyy}
|
180
|
+
# link_to 'yyy', {:controller => xxx, :action => yyy}
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# As an additional benefit, this method also accepts urls instead of parameter
|
184
|
+
# hashes. e.g.
|
185
|
+
# if_authorized?( '/xxx/yyy' ) { |opts| link_to('yyy', opts) }
|
186
|
+
# this comes particularly handy when you use resource based url generation
|
187
|
+
# as in the case:
|
188
|
+
# if_authorized?( edit_item_path ) { |opts| link_to('yyy', opts) }
|
189
|
+
|
190
|
+
def if_authorized? opts, &block
|
191
|
+
url_options = nil
|
192
|
+
if opts.class == String
|
193
|
+
path = opts
|
194
|
+
|
195
|
+
url_options = ActionController::Routing::Routes.recognize_path(path)
|
196
|
+
else
|
197
|
+
url_options = opts.dup
|
198
|
+
end
|
199
|
+
|
200
|
+
if authorize_action? url_options
|
201
|
+
block.call(opts)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns true if the current user is authorized to perform the current action
|
206
|
+
# on the current controller. It is mainly used in a before_filter (usually
|
207
|
+
# the method implementing the authentication logic calls this method immediately
|
208
|
+
# after checking the validity of the credentials.)
|
209
|
+
def authorized?
|
210
|
+
authorize_action? :controller => controller_name,
|
211
|
+
:action => action_name,
|
212
|
+
:ids => params.reject { |k,v| k.to_s !~ /(_id\Z)|(\Aid\Z)/ },
|
213
|
+
:user => current_user
|
214
|
+
end
|
215
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{role_based_authorization}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Roberto Esposito"]
|
12
|
+
s.date = %q{2010-02-16}
|
13
|
+
s.description = %q{Provides a simple DSL for specifying the authorization logic of your application. Install the gem, add a role attribute to your user model and your almost ready to go.}
|
14
|
+
s.email = %q{boborbt@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"lib/role_based_authorization.rb",
|
25
|
+
"lib/role_based_authorization/authorization_logger.rb",
|
26
|
+
"lib/role_based_authorization/role_based_authorization.rb",
|
27
|
+
"rails/init.rb",
|
28
|
+
"role_based_authorization.gemspec",
|
29
|
+
"test/role_based_authorization_test.rb",
|
30
|
+
"test/test_helper.rb"
|
31
|
+
]
|
32
|
+
s.homepage = %q{http://github.com/boborbt/role_based_authorization}
|
33
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = %q{1.3.5}
|
36
|
+
s.summary = %q{Basic authorization module for rails}
|
37
|
+
s.test_files = [
|
38
|
+
"test/role_based_authorization_test.rb",
|
39
|
+
"test/test_helper.rb"
|
40
|
+
]
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
47
|
+
else
|
48
|
+
end
|
49
|
+
else
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
require 'role_based_authorization'
|
4
|
+
|
5
|
+
class DummyUser
|
6
|
+
def id() return (@id || 1) end
|
7
|
+
def id=(new_id) @id = new_id end
|
8
|
+
def login() return 'test' end
|
9
|
+
def role() return @role end
|
10
|
+
def role=(new_role) @role = new_role end
|
11
|
+
def description() return "user" end
|
12
|
+
end
|
13
|
+
|
14
|
+
class DummyController < ActionController::Base
|
15
|
+
include RoleBasedAuthorization
|
16
|
+
|
17
|
+
def initialize() return @user = DummyUser.new end
|
18
|
+
def logged_in?() return true end
|
19
|
+
def current_user() return @user end
|
20
|
+
def current_user=(user) @user = user end
|
21
|
+
|
22
|
+
permit :actions => 'very_low_security',
|
23
|
+
:to => :all
|
24
|
+
|
25
|
+
permit :actions => 'high_security',
|
26
|
+
:to => 3
|
27
|
+
|
28
|
+
permit :actions => 'medium_security',
|
29
|
+
:to => [2,3]
|
30
|
+
|
31
|
+
permit :actions => 'low_security_with_param',
|
32
|
+
:to => :all,
|
33
|
+
:if => lambda { |user, object|
|
34
|
+
# to simplify things we directly compare object with a string
|
35
|
+
# in real life, we probably want to retrieve the object value
|
36
|
+
# using the provided object. e.g.
|
37
|
+
# Product.find(object).user == user
|
38
|
+
object == 'object_id'
|
39
|
+
}
|
40
|
+
|
41
|
+
permit :actions => 'low_security_with_param_identified_by_other_id',
|
42
|
+
:to => :all,
|
43
|
+
:if => lambda { |user, object| object == 'object_id' },
|
44
|
+
:object_id => :other_id
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
class RoleBasedAuthorizationTest < ActiveSupport::TestCase
|
50
|
+
def setup
|
51
|
+
@controller = DummyController.new
|
52
|
+
end
|
53
|
+
|
54
|
+
test "Should permit action very_low_security to everyone" do
|
55
|
+
assert_equal true, @controller.authorize_action?(:action => 'very_low_security')
|
56
|
+
end
|
57
|
+
|
58
|
+
test "Should permit action high_security only to root (role 3)" do
|
59
|
+
assert_equal false, @controller.authorize_action?(:action => 'high_security')
|
60
|
+
@controller.current_user.role=3
|
61
|
+
assert_equal true, @controller.authorize_action?(:action => 'high_security')
|
62
|
+
end
|
63
|
+
|
64
|
+
test "Should permit action medium_security only to roles 2 and 3" do
|
65
|
+
assert_equal false, @controller.authorize_action?(:action => 'medium_security')
|
66
|
+
@controller.current_user.role=2
|
67
|
+
assert_equal true, @controller.authorize_action?(:action => 'medium_security')
|
68
|
+
@controller.current_user.role=3
|
69
|
+
assert_equal true, @controller.authorize_action?(:action => 'medium_security')
|
70
|
+
end
|
71
|
+
|
72
|
+
test "Should permit action low_security_with_param only if the runtime check holds" do
|
73
|
+
assert_equal false, @controller.authorize_action?(:action => 'low_security_with_param')
|
74
|
+
assert_equal true, @controller.authorize_action?(:action => 'low_security_with_param',
|
75
|
+
:id => 'object_id')
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
test "Should permit action low_security_with_param_identified_by_other_id only if the runtime check holds" do
|
80
|
+
assert_equal false, @controller.authorize_action?(:action => 'low_security_with_param_identified_by_other_id')
|
81
|
+
assert_equal true, @controller.authorize_action?(:action => 'low_security_with_param_identified_by_other_id',
|
82
|
+
:other_id => 'object_id')
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/test_case'
|
4
|
+
|
5
|
+
ENV['RAILS_ENV'] = 'test'
|
6
|
+
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: role_based_authorization
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roberto Esposito
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-16 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Provides a simple DSL for specifying the authorization logic of your application. Install the gem, add a role attribute to your user model and your almost ready to go.
|
17
|
+
email: boborbt@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- lib/role_based_authorization.rb
|
31
|
+
- lib/role_based_authorization/authorization_logger.rb
|
32
|
+
- lib/role_based_authorization/role_based_authorization.rb
|
33
|
+
- rails/init.rb
|
34
|
+
- role_based_authorization.gemspec
|
35
|
+
- test/role_based_authorization_test.rb
|
36
|
+
- test/test_helper.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/boborbt/role_based_authorization
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.3.5
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Basic authorization module for rails
|
65
|
+
test_files:
|
66
|
+
- test/role_based_authorization_test.rb
|
67
|
+
- test/test_helper.rb
|