langalex-totally-restful-authorization 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +56 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/lib/totally_restful_authorization.rb +16 -0
- data/lib/totally_restful_authorization/permission_check.rb +82 -0
- data/lib/totally_restful_authorization/permission_dsl.rb +130 -0
- data/rails/init.rb +1 -0
- data/test/test_helper.rb +12 -0
- data/test/unit/permission_check_test.rb +168 -0
- data/test/unit/permission_dsl_test.rb +121 -0
- metadata +66 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Alexander Lang
|
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,56 @@
|
|
1
|
+
totally restful authorization
|
2
|
+
==============================
|
3
|
+
|
4
|
+
This plugin adds an authorization layer to your rails app that is <del>completely</del> totally transparent to your restful controllers. all you have to is include a module in your controller and provide 4 methods in your model that control who is allowed to access it or not. the controllers will then automatically block or allow the usual crud actions (new, create, edit, update, show, destroy) to run or not.
|
5
|
+
|
6
|
+
How it works
|
7
|
+
============
|
8
|
+
|
9
|
+
Include the PermisionCheck Module in your restful controller...
|
10
|
+
|
11
|
+
class ApplicationController < ActionController::Base
|
12
|
+
include PermissionCheck
|
13
|
+
end
|
14
|
+
|
15
|
+
... and then declare the permissions in your model:
|
16
|
+
|
17
|
+
class User
|
18
|
+
updatable_by :admin # updatable if updater.admin? return true
|
19
|
+
updatable_by :self, :except => [:admin] # special role self, allow all attributes except some to be updated
|
20
|
+
updatable_by :newbie, :only => [:description] # only allow some attribute to be updated
|
21
|
+
|
22
|
+
viewable_by :anyone # special role, includes nil
|
23
|
+
viewable_by :developer, :condition => lambda{|user, viewer| user.non_developer? && viewer.account_activated?} # use conditions for more complex permissions
|
24
|
+
|
25
|
+
destroyable_by [:admin, :root] # declare multiple roles at once
|
26
|
+
end
|
27
|
+
|
28
|
+
Or implement one or more of these four methods directly:
|
29
|
+
|
30
|
+
class User
|
31
|
+
def updatable_by?(user, field = nil)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def creatable_by?(user, field = nil)
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroyable_by?(user)
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def viewable_by?(user)
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
The fields parameter is either nil to determine if an object can be updated at all or a symbol of a field name. The user parameter is taken from the current_user in your controller (so you have to provide a current_user method, or install restful_authentication or something like that).
|
49
|
+
|
50
|
+
From now on your controller will run a before filter before the new/create/edit/update/destroy/show actions to make sure that the current_user is allowed to update/create/destroy/view the model. If you don't declare any permissions no actions can be performed on your model.
|
51
|
+
|
52
|
+
=================================================================
|
53
|
+
|
54
|
+
For questions, patches etc. contact alex[at]upstream-berlin.com
|
55
|
+
|
56
|
+
Copyright (c) 2008 Alexander Lang, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "totally-restful-authorization"
|
8
|
+
gem.summary = %Q{This plugin adds an authorization layer to your rails app that is totally transparent to your restful controllers and a DSL for declaring permissions on your models.}
|
9
|
+
gem.email = "alex@upstream-berlin.com"
|
10
|
+
gem.homepage = "http://github.com/langalex/totally_restful_authorization"
|
11
|
+
gem.authors = ["Alexander Lang"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
23
|
+
test.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__) + '/lib'
|
2
|
+
|
3
|
+
require 'totally_restful_authorization/permission_check'
|
4
|
+
require 'totally_restful_authorization/permission_dsl'
|
5
|
+
|
6
|
+
if defined?(ActiveRecord::Base)
|
7
|
+
ActiveRecord::Base.send :include, PermissionDsl
|
8
|
+
end
|
9
|
+
|
10
|
+
if defined?(ActionController::Base)
|
11
|
+
ActionController::Base.class_eval do
|
12
|
+
def self.check_authorization
|
13
|
+
include TotallyRestfulAuthorization::PermissionCheck
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module TotallyRestfulAuthorization
|
2
|
+
module PermissionCheck
|
3
|
+
def self.included(base)
|
4
|
+
base.before_filter :check_instance_permissions, :only => [:update, :destroy, :edit, :show]
|
5
|
+
base.before_filter :check_create_permissions, :only => [:create, :new]
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def check_instance_permissions
|
11
|
+
begin
|
12
|
+
deny_access_unless permission_granted?(object)
|
13
|
+
rescue => e
|
14
|
+
p e.message
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_create_permissions
|
20
|
+
begin
|
21
|
+
deny_access_unless permission_granted?(build_object)
|
22
|
+
rescue => e
|
23
|
+
p e.message
|
24
|
+
raise e
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def object
|
29
|
+
object_class.find params[:id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_object
|
33
|
+
object_class.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def object_class
|
37
|
+
Class.const_get self.class.name[0..-12]
|
38
|
+
end
|
39
|
+
|
40
|
+
def permission_granted?(_object)
|
41
|
+
if _object.respond_to? actionable_method.to_sym
|
42
|
+
_object.send(actionable_method, current_user)
|
43
|
+
else
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def actionable_method
|
49
|
+
"#{map_to_permission(actionable_name)}_by?"
|
50
|
+
end
|
51
|
+
|
52
|
+
def deny_access_unless(boolean)
|
53
|
+
if boolean
|
54
|
+
true
|
55
|
+
else
|
56
|
+
permission_denied
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def permission_denied
|
62
|
+
render :text => 'Permission Denied', :status => 403
|
63
|
+
end
|
64
|
+
|
65
|
+
def actionable_name
|
66
|
+
if params[:action][-1,1] == 'e'
|
67
|
+
"#{params[:action][0..-2]}able"
|
68
|
+
else
|
69
|
+
"#{params[:action]}able"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def map_to_permission(actionable)
|
74
|
+
{
|
75
|
+
'editable' => 'updatable',
|
76
|
+
'showable' => 'viewable',
|
77
|
+
'newable' => 'creatable'
|
78
|
+
}[actionable] || actionable
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module TotallyRestfulAuthorization
|
2
|
+
module PermissionDsl
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def self.view_permissions
|
11
|
+
@@view_permissions ||= {self.name => {}}
|
12
|
+
@@view_permissions[self.name] ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.create_permissions
|
16
|
+
@@create_permissions ||= {self.name => {}}
|
17
|
+
@@create_permissions[self.name] ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.update_permissions
|
21
|
+
@@update_permissions ||= {self.name => {}}
|
22
|
+
@@update_permissions[self.name] ||= {}
|
23
|
+
@@update_permissions[self.name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.destroy_permissions
|
27
|
+
@@destroy_permissions ||= {self.name => {}}
|
28
|
+
@@destroy_permissions[self.name] ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
def updatable_by(role, options = {})
|
36
|
+
add_options update_permissions, role, options
|
37
|
+
end
|
38
|
+
|
39
|
+
def viewable_by(role, options = {})
|
40
|
+
add_options view_permissions, role, options
|
41
|
+
end
|
42
|
+
|
43
|
+
def creatable_by(role, options = {})
|
44
|
+
add_options create_permissions, role, options
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroyable_by(role, options = {})
|
48
|
+
add_options destroy_permissions, role, options
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def add_options(permissions, role, options)
|
54
|
+
if role.respond_to?(:each)
|
55
|
+
role.each do |_role|
|
56
|
+
add_options permissions, _role, options
|
57
|
+
end
|
58
|
+
else
|
59
|
+
permissions[role] ||= []
|
60
|
+
permissions[role] << options
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def updatable_by?(user, field = nil)
|
66
|
+
check_permissions self.class.update_permissions, user, field
|
67
|
+
end
|
68
|
+
|
69
|
+
def viewable_by?(user, field = nil)
|
70
|
+
check_permissions self.class.view_permissions, user, field
|
71
|
+
end
|
72
|
+
|
73
|
+
def creatable_by?(user, field = nil)
|
74
|
+
check_permissions self.class.create_permissions, user, field
|
75
|
+
end
|
76
|
+
|
77
|
+
def destroyable_by?(user, field = nil)
|
78
|
+
check_permissions self.class.destroy_permissions, user, field
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def check_permissions(permissions, user, field)
|
84
|
+
permissions.keys.inject(false) do |result, role|
|
85
|
+
result || check_permission(permissions[role], role, user, field)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def check_permission(permission, role, user, field)
|
90
|
+
permission.inject(false) do |result, role_options|
|
91
|
+
result || (user_has_role(user, role) && field_in_only_list(field, role_options) &&
|
92
|
+
!field_in_except_list(field, role_options) && condition_met(user, role_options))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def user_has_role(user, role)
|
97
|
+
if role == :self
|
98
|
+
user == self
|
99
|
+
elsif role == :anyone
|
100
|
+
true
|
101
|
+
else
|
102
|
+
user && user.send("#{role}?")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def field_in_only_list(field, options)
|
107
|
+
if options[:only]
|
108
|
+
options[:only].include?(field)
|
109
|
+
else
|
110
|
+
true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def field_in_except_list(field, options)
|
115
|
+
if options[:except]
|
116
|
+
options[:except].include?(field)
|
117
|
+
else
|
118
|
+
false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def condition_met(user, options)
|
123
|
+
if options[:condition]
|
124
|
+
options[:condition].call(self, user)
|
125
|
+
else
|
126
|
+
true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '../lib/totally_restful_authorization'
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'mocha'
|
3
|
+
gem 'actionpack'
|
4
|
+
require 'actionpack'
|
5
|
+
require 'action_controller'
|
6
|
+
require 'action_controller/test_process'
|
7
|
+
require 'test/unit'
|
8
|
+
require 'mocha'
|
9
|
+
|
10
|
+
require File.dirname(__FILE__) + '/../lib/totally_restful_authorization'
|
11
|
+
|
12
|
+
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
ActionController::Routing::Routes.draw do |map|
|
4
|
+
map.connect ':controller/:action/:id'
|
5
|
+
end
|
6
|
+
|
7
|
+
class Model; end
|
8
|
+
|
9
|
+
class ModelsController < ActionController::Base
|
10
|
+
attr_accessor :current_user
|
11
|
+
check_authorization
|
12
|
+
|
13
|
+
def update
|
14
|
+
@model = Model.find params[:id]
|
15
|
+
@model.attributes= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def show
|
19
|
+
@model = Model.find params[:id]
|
20
|
+
render :text => 'show'
|
21
|
+
end
|
22
|
+
|
23
|
+
def edit
|
24
|
+
render :text => 'edit'
|
25
|
+
end
|
26
|
+
|
27
|
+
def new
|
28
|
+
render :text => 'new'
|
29
|
+
end
|
30
|
+
|
31
|
+
def create
|
32
|
+
Model.create
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy
|
36
|
+
@model = Model.find params[:id]
|
37
|
+
@model.destroy
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class PermissionCheckTest < ActionController::TestCase
|
42
|
+
|
43
|
+
def setup
|
44
|
+
@user = stub 'user'
|
45
|
+
@controller = ModelsController.new
|
46
|
+
@controller.current_user = @user
|
47
|
+
@request = ActionController::TestRequest.new
|
48
|
+
@response = ActionController::TestResponse.new
|
49
|
+
@model = stub 'test'
|
50
|
+
Model.stubs(:find).with('1').returns(@model)
|
51
|
+
Model.stubs(:new).returns(@model)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_doesnt_update_if_model_not_updatable
|
55
|
+
@model.stubs(:respond_to?).with(:updatable_by?).returns(true)
|
56
|
+
@model.stubs(:updatable_by?).with(@user).returns(false)
|
57
|
+
@model.expects(:attributes=).never
|
58
|
+
post :update, :id => 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_updates_if_model_updatable
|
62
|
+
@model.stubs(:respond_to?).with(:updatable_by?).returns(true)
|
63
|
+
@model.stubs(:updatable_by?).with(@user).returns(true)
|
64
|
+
@model.expects(:attributes=)
|
65
|
+
post :update, :id => 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_updates_if_model_doesnt_respond_to_updatable
|
69
|
+
@model.expects(:attributes=)
|
70
|
+
post :update, :id => 1
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_doesnt_show_if_not_viewable
|
74
|
+
@model.stubs(:respond_to?).with(:viewable_by?).returns(true)
|
75
|
+
@model.stubs(:viewable_by?).with(@user).returns(false)
|
76
|
+
get :show, :id => 1
|
77
|
+
assert_response 403
|
78
|
+
assert_nil assigns(:model)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_shows_if_viewable
|
82
|
+
@model.stubs(:respond_to?).with(:viewable_by?).returns(true)
|
83
|
+
@model.stubs(:viewable_by?).with(@user).returns(true)
|
84
|
+
get :show, :id => 1
|
85
|
+
assert_response :success
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_shows_if_models_doesnt_respond_to_viewable
|
89
|
+
get :show, :id => 1
|
90
|
+
assert_response :success
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_doesnt_edit_if_model_not_updatable
|
94
|
+
@model.stubs(:respond_to?).with(:updatable_by?).returns(true)
|
95
|
+
@model.stubs(:updatable_by?).with(@user).returns(false)
|
96
|
+
get :edit, :id => 1
|
97
|
+
assert_response 403
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_does_edit_if_model_updatable
|
101
|
+
@model.stubs(:respond_to?).with(:updatable_by?).returns(true)
|
102
|
+
@model.stubs(:updatable_by?).with(@user).returns(true)
|
103
|
+
get :edit, :id => 1
|
104
|
+
assert_response 200
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_does_edit_if_model_doesnt_respond_to_viewable
|
108
|
+
get :edit, :id => 1
|
109
|
+
assert_response 200
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_doesnt_new_if_model_not_creatable
|
113
|
+
@model.stubs(:respond_to?).with(:creatable_by?).returns(true)
|
114
|
+
@model.stubs(:creatable_by?).with(@user).returns(false)
|
115
|
+
get :new
|
116
|
+
assert_response 403
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_does_new_if_model_creatable
|
120
|
+
@model.stubs(:respond_to?).with(:creatable_by?).returns(true)
|
121
|
+
@model.stubs(:creatable_by?).with(@user).returns(true)
|
122
|
+
get :new
|
123
|
+
assert_response :success
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_does_new_if_model_doesnt_respond_to_creatable
|
127
|
+
get :new
|
128
|
+
assert_response :success
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_doesnt_create_if_model_not_creatable
|
132
|
+
@model.stubs(:respond_to?).with(:creatable_by?).returns(true)
|
133
|
+
@model.stubs(:creatable_by?).with(@user).returns(false)
|
134
|
+
Model.expects(:create).never
|
135
|
+
post :create
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_creates_if_model_creatable
|
139
|
+
@model.stubs(:respond_to?).with(:creatable_by?).returns(true)
|
140
|
+
@model.stubs(:creatable_by?).with(@user).returns(true)
|
141
|
+
Model.expects(:create)
|
142
|
+
post :create
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_creates_if_model_doesnt_respond_to_creatable
|
146
|
+
Model.expects(:create)
|
147
|
+
post :create
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_doesnt_destroy_if_model_not_destroyable
|
151
|
+
@model.stubs(:respond_to?).with(:destroyable_by?).returns(true)
|
152
|
+
@model.stubs(:destroyable_by?).with(@user).returns(false)
|
153
|
+
@model.expects(:destroy).never
|
154
|
+
post :destroy, :id => 1
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_destroy_if_model_destroyable
|
158
|
+
@model.stubs(:respond_to?).with(:destroyable_by?).returns(true)
|
159
|
+
@model.stubs(:destroyable_by?).with(@user).returns(true)
|
160
|
+
@model.expects(:destroy)
|
161
|
+
post :destroy, :id => 1
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_destroy_if_model_doesnt_respond_to_destroyable
|
165
|
+
@model.expects(:destroy)
|
166
|
+
post :destroy, :id => 1
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class PermissionDslTest < Test::Unit::TestCase
|
4
|
+
class Model
|
5
|
+
include TotallyRestfulAuthorization::PermissionDsl
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@clazz = Model
|
10
|
+
@clazz.update_permissions.clear
|
11
|
+
@clazz.view_permissions.clear
|
12
|
+
@clazz.update_permissions.clear
|
13
|
+
@clazz.destroy_permissions.clear
|
14
|
+
@clazz.create_permissions.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_is_not_updatable_if_no_permissions_declared
|
18
|
+
assert !@clazz.new.updatable_by?(stub('user'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_understands_multiple_roles_at_once
|
22
|
+
@clazz.send :updatable_by, [:admin, :superadmin]
|
23
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true, :superadmin? => false))
|
24
|
+
assert @clazz.new.updatable_by?(stub('superadmin', :admin? => false, :superadmin? => true))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_is_not_updatable_for_nil
|
28
|
+
@clazz.send :updatable_by, :admin
|
29
|
+
assert !@clazz.new.updatable_by?(nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_special_role_self_is_interpreted_as_user_is_same_as_object
|
33
|
+
@clazz.send :updatable_by, :self
|
34
|
+
_self = @clazz.new
|
35
|
+
assert _self.updatable_by?(_self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_special_role_anyone_is_interpreted_as_any_object
|
39
|
+
@clazz.send :updatable_by, :anyone
|
40
|
+
assert @clazz.new.updatable_by?('yet another object')
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_anyone_allows_nil
|
44
|
+
@clazz.send :updatable_by, :anyone
|
45
|
+
assert @clazz.new.updatable_by?(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_allows_role_access_to_entire_object
|
49
|
+
@clazz.send :updatable_by, :admin
|
50
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_forbids_user_without_role_access_to_object
|
54
|
+
@clazz.send :updatable_by, :admin
|
55
|
+
assert !@clazz.new.updatable_by?(stub('admin', :admin? => false))
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_allows_role_access_only_to_specific_field
|
59
|
+
@clazz.send :updatable_by, :admin, :only => [:name]
|
60
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true), :name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_forbids_role_access_to_fields_not_in_only_array
|
64
|
+
@clazz.send :updatable_by, :admin, :only => [:name]
|
65
|
+
assert !@clazz.new.updatable_by?(stub('admin', :admin? => true), :email)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_allows_role_access_to_fields_not_in_except_array
|
69
|
+
@clazz.send :updatable_by, :admin, :except => [:email]
|
70
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true), :name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_forbids_role_access_to_fields_in_except_array
|
74
|
+
@clazz.send :updatable_by, :admin, :except => [:email]
|
75
|
+
assert !@clazz.new.updatable_by?(stub('admin', :admin? => true), :email)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_allows_access_if_conditions_met
|
79
|
+
@clazz.send :updatable_by, :admin, :condition => lambda{|model, updater| updater.admin?}
|
80
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true))
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_forbids_access_if_condition_not_met
|
84
|
+
@clazz.send :updatable_by, :admin, :condition => lambda{|model, updater| !updater.admin?}
|
85
|
+
assert !@clazz.new.updatable_by?(stub('admin', :admin? => true))
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_multiple_role_declarations_dont_overwrite_one_another
|
89
|
+
@clazz.send :updatable_by, :admin
|
90
|
+
@clazz.send :updatable_by, :user
|
91
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true, :user? => false))
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_multiple_option_declarations_per_role_dont_overwrite_one_another
|
95
|
+
@clazz.send :updatable_by, :admin, :only => [:user]
|
96
|
+
@clazz.send :updatable_by, :admin, :only => [:email]
|
97
|
+
assert @clazz.new.updatable_by?(stub('admin', :admin? => true), :user)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_viewable_by?
|
101
|
+
@clazz.send :viewable_by, :admin
|
102
|
+
assert @clazz.new.viewable_by?(stub('admin', :admin? => true))
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_creatable_by?
|
106
|
+
@clazz.send :creatable_by, :admin
|
107
|
+
assert @clazz.new.creatable_by?(stub('admin', :admin? => true))
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_destroyable_by?
|
111
|
+
@clazz.send :destroyable_by, :admin
|
112
|
+
assert @clazz.new.destroyable_by?(stub('admin', :admin? => true))
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_declarations_in_inherited_class_dont_interferce_with_superclass
|
116
|
+
@clazz2 = Class.new @clazz
|
117
|
+
@clazz2.send :destroyable_by, :admin
|
118
|
+
assert !@clazz.new.destroyable_by?(stub('admin', :admin? => true))
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: langalex-totally-restful-authorization
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Lang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: alex@upstream-berlin.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- lib/totally_restful_authorization.rb
|
31
|
+
- lib/totally_restful_authorization/permission_check.rb
|
32
|
+
- lib/totally_restful_authorization/permission_dsl.rb
|
33
|
+
- rails/init.rb
|
34
|
+
- test/test_helper.rb
|
35
|
+
- test/unit/permission_check_test.rb
|
36
|
+
- test/unit/permission_dsl_test.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/langalex/totally_restful_authorization
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --charset=UTF-8
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.2.0
|
60
|
+
signing_key:
|
61
|
+
specification_version: 2
|
62
|
+
summary: This plugin adds an authorization layer to your rails app that is totally transparent to your restful controllers and a DSL for declaring permissions on your models.
|
63
|
+
test_files:
|
64
|
+
- test/test_helper.rb
|
65
|
+
- test/unit/permission_check_test.rb
|
66
|
+
- test/unit/permission_dsl_test.rb
|