controlist 0.1.0

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.
@@ -0,0 +1,233 @@
1
+ require 'test_helper'
2
+
3
+ include Controlist::Permissions
4
+
5
+ class FeatureTest < ActiveSupport::TestCase
6
+
7
+ def setup
8
+ if Controlist.is_activerecord3?
9
+ Controlist.skip do
10
+ load "test/migrate.rb"
11
+ Clazz.create id: 1, name: "Grade 1"
12
+ Clazz.create id: 2, name: "Grade 2"
13
+ User.create id: 1, name: "Tom", clazz_id: 1, age: 1
14
+ User.create id: 2, name: "Jerry", clazz_id: 1, age: 1
15
+ User.create id: 3, name: "Henry", clazz_id: 2, age: 1
16
+ User.create id: 4, name: "Tom", clazz_id: 2, age: 7
17
+ User.create id: 5, name: "MAF", clazz_id: 2, age: 1
18
+ end
19
+ end
20
+ end
21
+
22
+ def test_read_constrains
23
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
24
+ Controlist::Permission.new(User, READ, true, [
25
+ SimpleConstrain.new("name", "Tom"),
26
+ SimpleConstrain.new("name", ["Grade 1", "Grade 2"], relation: "clazz"),
27
+ AdvancedConstrain.new(property: "age", value: 5, operator: ">="),
28
+ SimpleConstrain.new("age", "null"),
29
+ SimpleConstrain.new("age", [1,2,3]),
30
+ SimpleConstrain.new("clazz_id", -> { Clazz.select(:id).map(&:id) }),
31
+ AdvancedConstrain.new(clause: "age != 100"),
32
+ Controlist.is_activerecord3? ? nil : AdvancedConstrain.new(proc_read: lambda{|relation| relation.order("id DESC").limit(3) })
33
+ ])))
34
+
35
+ relation = User.unscoped
36
+ relation.to_sql
37
+ assert_equal [:clazz], relation.joins_values
38
+ assert_equal ["(users.name = 'Tom') and (clazzs.name in ('Grade 1','Grade 2'))" +
39
+ " and (users.age >= 5) and (users.age is null) and (users.age in (1,2,3))" +
40
+ " and (users.clazz_id in (1,2)) and (age != 100)"], relation.where_values
41
+ unless Controlist.is_activerecord3?
42
+ assert_equal 3, relation.limit_value
43
+ assert_equal ["id DESC"], relation.order_values
44
+ end
45
+ end
46
+
47
+ def test_permission_empty
48
+ Controlist.permission_provider.set_permission_package(nil)
49
+ relation = User.unscoped
50
+ relation.to_sql
51
+ assert_equal ["1 != 1"], relation.where_values
52
+ end
53
+
54
+ def test_read_constrains_sql_only
55
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
56
+ Controlist::Permission.new(User, READ, true, "age != 100")
57
+ ))
58
+ relation = User.unscoped
59
+ relation.to_sql
60
+ assert_equal ["age != 100"], relation.where_values
61
+ end
62
+
63
+
64
+ def test_read_apply_properties
65
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
66
+ Controlist::Permission.new(User, READ).apply(:name)
67
+ ))
68
+
69
+ relation = User.unscoped
70
+ assert_nil relation.first._value_object.clazz_id
71
+ assert_nil relation.first._val(:clazz_id)
72
+ assert_raise(ActiveModel::MissingAttributeError) { assert_nil relation.first.clazz_id }
73
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
74
+ Controlist::Permission.new(User, READ)
75
+ ))
76
+
77
+ relation = User.unscoped
78
+ assert_not_nil relation.first._value_object.clazz_id
79
+ assert_not_nil relation.first._val(:clazz_id)
80
+ assert_not_nil relation.first.clazz_id
81
+ end
82
+
83
+ def test_update_fail_without_permissions
84
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
85
+ Controlist::Permission.new(User, READ)
86
+ ))
87
+ user = User.find 1
88
+ assert_raise(Controlist::NoPermissionError) {
89
+ user.name = "Test"
90
+ user.save
91
+ }
92
+ end
93
+
94
+ def test_persistence_constrains
95
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
96
+ Controlist::Permission.new(Clazz, READ),
97
+ Controlist::Permission.new(User, READ),
98
+ Controlist::Permission.new(User, UPDATE, false, AdvancedConstrain.new(property: "name", value: "To", operator: "include?")),
99
+ Controlist.is_activerecord3? ? nil : Controlist::Permission.new(User, UPDATE, false, AdvancedConstrain.new(proc_persistence: lambda{|object, operation| object.name == 'Block'})),
100
+ Controlist::Permission.new(User, [UPDATE, DELETE], false, SimpleConstrain.new("name", "Grade 1", relation: 'clazz')),
101
+ Controlist::Permission.new(User, UPDATE)
102
+ ))
103
+
104
+ user = User.find 3
105
+ assert_not_equal "Tom", user.name
106
+ assert_not_equal "Grade 1", user.clazz.name
107
+ user.name = 'Test'
108
+ assert_equal true, user.save
109
+
110
+ unless Controlist.is_activerecord3?
111
+ assert_raise(Controlist::PermissionForbidden) {
112
+ user.name = "Block"
113
+ user.save
114
+ }
115
+ end
116
+
117
+ assert_raise(Controlist::NoPermissionError) {
118
+ user.destroy
119
+ }
120
+
121
+ Controlist.permission_provider.get_permission_package.add_permissions(Controlist::Permission.new(User, DELETE))
122
+ assert_instance_of User, user.destroy
123
+
124
+ assert_raise(Controlist::PermissionForbidden) {
125
+ user = User.find 1
126
+ assert_equal "Tom", user.name
127
+ user.name = "Test"
128
+ user.save
129
+ }
130
+
131
+ assert_raise(Controlist::PermissionForbidden) {
132
+ user = User.find 2
133
+ assert_equal "Grade 1", user.clazz.name
134
+ user.name = "Test"
135
+ user.save
136
+ }
137
+
138
+ assert_raise(Controlist::PermissionForbidden) {
139
+ user = User.find 2
140
+ assert_equal "Grade 1", user.clazz.name
141
+ user.delete
142
+ }
143
+
144
+ end
145
+
146
+ def test_persistence_apply_properties
147
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
148
+ Controlist::Permission.new(User, READ),
149
+ Controlist::Permission.new(User, UPDATE, true, SimpleConstrain.new("name", "Tom")).apply(name: "Test", clazz_id: [1, 2]),
150
+ ))
151
+
152
+ assert_raise(Controlist::NoPermissionError) {
153
+ user = User.find 2
154
+ assert_not_equal "Tom", user.name
155
+ user.name = "Test"
156
+ user.save
157
+ }
158
+
159
+ assert_raise(Controlist::NoPermissionError) {
160
+ user = User.find 1
161
+ assert_equal "Tom", user.name
162
+ user.name = "Jerry"
163
+ user.save
164
+ }
165
+
166
+ user = User.find 1
167
+ assert_equal "Tom", user.name
168
+ user.clazz_id = 2
169
+ assert_equal true, user.save
170
+ assert_raise(Controlist::NoPermissionError) {
171
+ user.clazz_id = 3
172
+ user.save
173
+ }
174
+
175
+ user = User.find 1
176
+ assert_equal "Tom", user.name
177
+ user.name = "Test"
178
+ assert_equal true, user.save
179
+
180
+ end
181
+
182
+ def test_modify_permissions_on_the_fly
183
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
184
+ Controlist::Permission.new(User, READ),
185
+ ))
186
+
187
+ assert_instance_of User, User.find(1)
188
+
189
+ package = Controlist.permission_provider.get_permission_package
190
+ package.remove_permissions package.permissions.last
191
+
192
+ assert_raise(ActiveRecord::RecordNotFound) {
193
+ User.find 1
194
+ }
195
+
196
+ package.add_permissions Controlist::Permission.new(User, READ)
197
+ assert_instance_of User, User.find(1)
198
+ end
199
+
200
+ def test_constrains_argument_error
201
+ assert_raise(ArgumentError) {
202
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
203
+ Controlist::Permission.new(User, READ, true, Object.new)
204
+ ))
205
+ }
206
+ end
207
+
208
+ def test_relation_not_reuseable
209
+ assert_raise(Controlist::NotReuseableError) {
210
+ relation = User.unscoped
211
+ relation.to_sql
212
+ relation_new = relation.where("1 = 1")
213
+ relation_new.to_sql
214
+ }
215
+ relation = User.unscoped
216
+ reuseable_relation = relation.clone
217
+ relation.to_sql
218
+ relation_new = reuseable_relation.where("1 = 1")
219
+ relation_new.to_sql
220
+ end
221
+
222
+ def test_skip
223
+ Controlist.permission_provider.set_permission_package(OrderedPackage.new(
224
+ Controlist::Permission.new(User, READ, true, "age != 100")
225
+ ))
226
+ Controlist.skip do
227
+ relation = User.unscoped
228
+ relation.to_sql
229
+ assert_equal [], relation.where_values
230
+ end
231
+ end
232
+
233
+ end
@@ -0,0 +1,6 @@
1
+ one:
2
+ id: 1
3
+ name: Grade 1
4
+ two:
5
+ id: 2
6
+ name: Grade 2
@@ -0,0 +1,25 @@
1
+ one:
2
+ id: 1
3
+ name: Tom
4
+ clazz_id: 1
5
+ age: 1
6
+ two:
7
+ id: 2
8
+ name: Jerry
9
+ clazz_id: 1
10
+ age: 1
11
+ three:
12
+ id: 3
13
+ name: Henry
14
+ clazz_id: 2
15
+ age: 1
16
+ four:
17
+ id: 4
18
+ name: Tom
19
+ clazz_id: 2
20
+ age: 7
21
+ five:
22
+ id: 5
23
+ name: MAF
24
+ clazz_id: 2
25
+ age: 1
data/test/migrate.rb ADDED
@@ -0,0 +1,20 @@
1
+ `rm test/test.sqlite3`
2
+ ActiveRecord::Base.establish_connection(
3
+ :adapter => "sqlite3",
4
+ :database => "test/test.sqlite3",
5
+ :pool=>5,
6
+ :timeout=>5000)
7
+ class CreateSchema < ActiveRecord::Migration
8
+ def change
9
+ create_table :users do |t|
10
+ t.string :name
11
+ t.integer :clazz_id
12
+ t.integer :age
13
+ end
14
+ create_table :clazzs do |t|
15
+ t.string :name
16
+ end
17
+ end
18
+ end
19
+ CreateSchema.new.change
20
+
@@ -0,0 +1,5 @@
1
+ class Clazz < ActiveRecord::Base
2
+
3
+ has_many :users
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ belongs_to :clazz
4
+
5
+ end
data/test/test.sqlite3 ADDED
Binary file
@@ -0,0 +1,40 @@
1
+ ROOT_PATH = File.expand_path("../..", __FILE__)
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ add_filter '/test/'
6
+ end
7
+
8
+ require 'rails'
9
+ require 'active_record'
10
+ require 'rails/test_help'
11
+ require 'minitest/autorun'
12
+ require 'minitest/unit'
13
+ require 'minitest/pride'
14
+ require "minitest/reporters"
15
+ Minitest::Reporters.use!
16
+ require 'sqlite3'
17
+
18
+ # require controlist
19
+ require 'models/user'
20
+ require 'models/clazz'
21
+ load "test/migrate.rb"
22
+
23
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
24
+
25
+ require 'controlist'
26
+ require 'controlist/managers/thread_based_manager'
27
+ #Controlist.initialize Controlist::Manager::ThreadBasedManager, attribute_proxy: "_val", value_object_proxy: "_value_object", logger: Logger.new(STDOUT)
28
+ Controlist.initialize Controlist::Managers::ThreadBasedManager
29
+
30
+ unless Controlist.is_activerecord3?
31
+ class ActiveSupport::TestCase
32
+ ActiveRecord::Migration.check_pending!
33
+
34
+ self.fixture_path = ROOT_PATH + "/test/fixtures"
35
+ self.test_order = :random if self.respond_to?(:test_order=)
36
+ fixtures :all
37
+
38
+ # Add more helper methods to be used by all tests here...
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,208 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: controlist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Leon Li
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.1.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.1.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.17
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.17
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 5.7.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 5.7.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.10.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.10.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.3.10
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.3.10
111
+ - !ruby/object:Gem::Dependency
112
+ name: activesupport
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 4.2.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 4.2.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: activerecord
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 4.2.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 4.2.1
139
+ description: 'Use Case: RBAC (Role-Based Access Control), security for API Server
140
+ and any scenario that need fine-grained or flexible access control'
141
+ email:
142
+ - qianthinking@gmail.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - Gemfile
149
+ - Gemfile.lock.3.2
150
+ - Gemfile.lock.4.1
151
+ - Gemfile.lock.4.2
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - controlist.gemspec
156
+ - lib/controlist.rb
157
+ - lib/controlist/errors.rb
158
+ - lib/controlist/interceptor.rb
159
+ - lib/controlist/managers/base_manager.rb
160
+ - lib/controlist/managers/thread_based_manager.rb
161
+ - lib/controlist/permission.rb
162
+ - lib/controlist/permissions/advanced_constrain.rb
163
+ - lib/controlist/permissions/constrain.rb
164
+ - lib/controlist/permissions/operation.rb
165
+ - lib/controlist/permissions/ordered_package.rb
166
+ - lib/controlist/permissions/simple_constrain.rb
167
+ - lib/controlist/version.rb
168
+ - test/feature_test.rb
169
+ - test/fixtures/clazz.yml
170
+ - test/fixtures/user.yml
171
+ - test/migrate.rb
172
+ - test/models/clazz.rb
173
+ - test/models/user.rb
174
+ - test/test.sqlite3
175
+ - test/test_helper.rb
176
+ homepage: ''
177
+ licenses:
178
+ - MIT
179
+ metadata: {}
180
+ post_install_message:
181
+ rdoc_options: []
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ requirements: []
195
+ rubyforge_project:
196
+ rubygems_version: 2.4.5
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: Fine-grained access control library for Ruby ActiveRecord
200
+ test_files:
201
+ - test/feature_test.rb
202
+ - test/fixtures/clazz.yml
203
+ - test/fixtures/user.yml
204
+ - test/migrate.rb
205
+ - test/models/clazz.rb
206
+ - test/models/user.rb
207
+ - test/test.sqlite3
208
+ - test/test_helper.rb