allows 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/README.md +6 -0
- data/Rakefile +18 -0
- data/allows.gemspec +17 -0
- data/lib/allows.rb +121 -0
- data/lib/exceptions.rb +14 -0
- data/test/allows_test.rb +154 -0
- metadata +115 -0
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
task :default => [:test_units]
|
5
|
+
|
6
|
+
desc "Run tests"
|
7
|
+
Rake::TestTask.new("test_units") do |t|
|
8
|
+
t.pattern = 'test/*_test.rb'
|
9
|
+
t.verbose = true
|
10
|
+
t.warning = false
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
desc "Open an irb session"
|
15
|
+
task :console do
|
16
|
+
sh "irb -I lib -r allows.rb"
|
17
|
+
end
|
18
|
+
|
data/allows.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'allows'
|
3
|
+
s.version = '0.2.1'
|
4
|
+
s.date = '2012-09-24'
|
5
|
+
s.summary = "Simple Authorization library"
|
6
|
+
s.description = "Simple Authorization for Rails"
|
7
|
+
s.authors = ["Jose Goncalves"]
|
8
|
+
s.email = 'zetoeu@gmail.com'
|
9
|
+
s.homepage = 'http://github.com/zeto/allows'
|
10
|
+
s.files = Dir["**/*"] - Dir["*.gem"] - ["Gemfile.lock"]
|
11
|
+
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.add_dependency 'actionpack'
|
14
|
+
s.add_development_dependency "turn"
|
15
|
+
s.add_development_dependency "debugger"
|
16
|
+
s.add_development_dependency "rake"
|
17
|
+
end
|
data/lib/allows.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'exceptions'
|
3
|
+
|
4
|
+
module Allows
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
|
9
|
+
base.send :before_filter, :set_permissions
|
10
|
+
base.send :before_filter, :check_permissions
|
11
|
+
|
12
|
+
class << base
|
13
|
+
attr_accessor :permissions
|
14
|
+
cattr_accessor :permission_checker
|
15
|
+
end
|
16
|
+
|
17
|
+
# set default permission_checker
|
18
|
+
base.permission_checker = :current_user
|
19
|
+
end
|
20
|
+
|
21
|
+
public
|
22
|
+
|
23
|
+
def check_permissions
|
24
|
+
im_allowed = false
|
25
|
+
|
26
|
+
klass = self.class
|
27
|
+
if klass.permission_checker && respond_to?(klass.permission_checker)
|
28
|
+
if klass.permissions
|
29
|
+
permissions_for_action = klass.permissions[action_name.to_sym]
|
30
|
+
if permissions_for_action
|
31
|
+
permissions_for_action.each do |permission|
|
32
|
+
if assert_permission(permission)
|
33
|
+
im_allowed = true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
# Can execute the action. No "allow" rule affects this action.
|
38
|
+
im_allowed = true
|
39
|
+
end
|
40
|
+
else
|
41
|
+
# Can execute any action. Controller does not declare any "allow" rule
|
42
|
+
im_allowed = true
|
43
|
+
end
|
44
|
+
else
|
45
|
+
raise NoPermissionChecker # Permission checker isnt defined, so no permissions can be validated
|
46
|
+
end
|
47
|
+
raise Unauthorized unless im_allowed
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def set_permissions
|
53
|
+
self.class.set_permissions # Call class method instead
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def assert_permission(permission)
|
59
|
+
targetted_permission = /(?<method>.+)_of_(?<target>.+)/.match(permission.to_s)
|
60
|
+
|
61
|
+
# Permission is something like: allow reader_of_post (<permission>_of_<target>)
|
62
|
+
if targetted_permission && targetted_permission.captures.size == 2
|
63
|
+
raise NoInstanceVariable unless instance_variable_get("@#{targetted_permission[:target]}")
|
64
|
+
(self.send self.class.permission_checker).send "#{targetted_permission[:method]}?", instance_variable_get("@#{targetted_permission[:target]}")
|
65
|
+
else
|
66
|
+
(self.send self.class.permission_checker).send "#{permission.to_s}?"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module ClassMethods
|
71
|
+
def allow(*options, &block)
|
72
|
+
@allows ||= Array.new
|
73
|
+
@allows << options
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_permissions
|
77
|
+
# Permissions are calculated only once per class for performance considerations
|
78
|
+
# This behaviour is overridden in development so permissions are always calculated
|
79
|
+
if (!@permissions && @allows) || (defined?(RAILS_ENV) && RAILS_ENV == 'development')
|
80
|
+
@permissions = Hash.new
|
81
|
+
|
82
|
+
if @allows
|
83
|
+
@allows.each do |p|
|
84
|
+
allowed = Hash.new
|
85
|
+
hash = p.select{|o| o.is_a?(Hash)}
|
86
|
+
|
87
|
+
allowed[:permissions] = p - hash
|
88
|
+
|
89
|
+
actions = hash.first
|
90
|
+
if hash.first
|
91
|
+
allowed[:except] = actions[:except]
|
92
|
+
allowed[:only] = actions[:only]
|
93
|
+
end
|
94
|
+
|
95
|
+
if allowed[:only] # Only for the specified actions
|
96
|
+
allowed_actions = Array(allowed[:only])
|
97
|
+
elsif allowed[:except] # All available actions EXCEPT the ones specified
|
98
|
+
allowed_actions = controller_actions - Array(allowed[:except])
|
99
|
+
else # All available actions
|
100
|
+
allowed_actions = controller_actions
|
101
|
+
end
|
102
|
+
|
103
|
+
allowed_actions.each do |action|
|
104
|
+
@permissions[action.to_sym] = (Array(@permissions[action.to_sym]) + allowed[:permissions]).uniq
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def clear_permissions
|
112
|
+
@permissions = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def controller_actions
|
118
|
+
(self.new.action_methods - ActionController::Base.new.action_methods).map {|am| am.to_sym} - [:check_permissions]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/exceptions.rb
ADDED
data/test/allows_test.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'turn'
|
5
|
+
require 'allows'
|
6
|
+
require 'rubygems'
|
7
|
+
#require 'action_pack'
|
8
|
+
require 'action_controller'
|
9
|
+
|
10
|
+
class AllowsTest < MiniTest::Unit::TestCase
|
11
|
+
def test_simple_permissions
|
12
|
+
TestController.set_permissions
|
13
|
+
|
14
|
+
assert TestController.permissions.count == 5
|
15
|
+
|
16
|
+
assert TestController.permissions[:index].include? :admin
|
17
|
+
refute TestController.permissions[:show].include? :gpd
|
18
|
+
assert TestController.permissions[:index].include? :dds
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_complex_permissions
|
22
|
+
TestController.set_permissions
|
23
|
+
|
24
|
+
assert TestController.permissions.count == 5
|
25
|
+
|
26
|
+
assert TestController.permissions[:index].include? :a
|
27
|
+
assert TestController.permissions[:create].include? :b
|
28
|
+
assert TestController.permissions[:update].include? :c
|
29
|
+
|
30
|
+
assert TestController.permissions[:create].include? :d
|
31
|
+
refute TestController.permissions[:index].include? :d
|
32
|
+
refute TestController.permissions[:new].include? :d
|
33
|
+
refute TestController.permissions[:show].include? :d
|
34
|
+
|
35
|
+
assert TestController.permissions[:create].include? :e
|
36
|
+
refute TestController.permissions[:index].include? :f
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_must_not_include_nonexistant_action
|
40
|
+
TestController.set_permissions
|
41
|
+
|
42
|
+
refute TestController.permissions[:showw]
|
43
|
+
refute TestController.permissions[:accao_que_nao_existe]
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_all_actions
|
47
|
+
TestController.set_permissions
|
48
|
+
|
49
|
+
assert TestController.permissions.count == 5
|
50
|
+
|
51
|
+
assert TestController.permissions.keys.include? :index
|
52
|
+
assert TestController.permissions.keys.include? :show
|
53
|
+
assert TestController.permissions.keys.include? :update
|
54
|
+
assert TestController.permissions.keys.include? :new
|
55
|
+
assert TestController.permissions.keys.include? :create
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_generate_unauthorized
|
59
|
+
TestControllerNone.set_permissions
|
60
|
+
|
61
|
+
assert_raises Unauthorized do
|
62
|
+
TestControllerNone.new.check_permissions
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_allow_that_depends_on_instance_variable
|
67
|
+
TestControllerComplex.set_permissions
|
68
|
+
|
69
|
+
assert TestControllerComplex.permissions.count == 1
|
70
|
+
|
71
|
+
tcc = TestControllerComplex.new
|
72
|
+
tcc.instance_variable_set(:@requirement,RequirementStub.new)
|
73
|
+
tcc.instance_variable_set(:@post,3)
|
74
|
+
|
75
|
+
tcc.check_permissions
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class TestController < ActionController::Base
|
81
|
+
include Allows
|
82
|
+
|
83
|
+
allow :admin
|
84
|
+
allow :gpd, :only => :index
|
85
|
+
allow :dds, :except => :show
|
86
|
+
|
87
|
+
allow :a, :b, :c
|
88
|
+
allow :d, :only => :create
|
89
|
+
allow :e, :f, :except => [:index, :update, :show]
|
90
|
+
|
91
|
+
def index; end
|
92
|
+
def show; end
|
93
|
+
def update; end
|
94
|
+
def new; end
|
95
|
+
def create; end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def action_name; :show; end
|
100
|
+
def current_user; PermissionCheckerDeluxe.new; end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class PermissionCheckerDeluxe
|
105
|
+
def admin?; true; end
|
106
|
+
def gpd?; true; end
|
107
|
+
def dds?; false; end
|
108
|
+
def a?; false; end
|
109
|
+
def b?; true; end
|
110
|
+
def c?; false; end
|
111
|
+
def d?; true; end
|
112
|
+
def e?; false; end
|
113
|
+
def f?; true; end
|
114
|
+
end
|
115
|
+
|
116
|
+
class TestControllerComplex < ActionController::Base
|
117
|
+
include Allows
|
118
|
+
|
119
|
+
allow :reader_of_requirement, :editor_of_post
|
120
|
+
|
121
|
+
def show; end
|
122
|
+
|
123
|
+
protected
|
124
|
+
|
125
|
+
def action_name; :show; end
|
126
|
+
def current_user; PermissionCheckerForRequirement.new; end
|
127
|
+
end
|
128
|
+
|
129
|
+
class PermissionCheckerForRequirement
|
130
|
+
def reader?(requirement); requirement.message == 'testing'; end
|
131
|
+
def editor?(post); post == 3; end
|
132
|
+
end
|
133
|
+
|
134
|
+
class RequirementStub
|
135
|
+
def message; 'testing'; end
|
136
|
+
end
|
137
|
+
|
138
|
+
class TestControllerNone < ActionController::Base
|
139
|
+
include Allows
|
140
|
+
|
141
|
+
allow :admin
|
142
|
+
|
143
|
+
def show; end
|
144
|
+
|
145
|
+
protected
|
146
|
+
|
147
|
+
def action_name; :show; end
|
148
|
+
def current_user; PermissionCheckerNone.new; end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
class PermissionCheckerNone
|
153
|
+
def admin?; false; end
|
154
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: allows
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jose Goncalves
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: actionpack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: turn
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: debugger
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Simple Authorization for Rails
|
79
|
+
email: zetoeu@gmail.com
|
80
|
+
executables: []
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files: []
|
83
|
+
files:
|
84
|
+
- README.md
|
85
|
+
- lib/allows.rb
|
86
|
+
- lib/exceptions.rb
|
87
|
+
- test/allows_test.rb
|
88
|
+
- Gemfile
|
89
|
+
- allows.gemspec
|
90
|
+
- Rakefile
|
91
|
+
homepage: http://github.com/zeto/allows
|
92
|
+
licenses: []
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.8.24
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Simple Authorization library
|
115
|
+
test_files: []
|