stffn-declarative_authorization 0.2.4 → 0.2.5
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/CHANGELOG +16 -0
- data/README.rdoc +6 -1
- data/app/controllers/authorization_rules_controller.rb +5 -1
- data/app/controllers/authorization_usages_controller.rb +3 -1
- data/app/helpers/authorization_rules_helper.rb +16 -0
- data/app/views/authorization_rules/index.html.erb +2 -1
- data/lib/declarative_authorization/authorization.rb +77 -13
- data/lib/declarative_authorization/authorization_rules_analyzer.rb +138 -0
- data/lib/declarative_authorization/helper.rb +5 -0
- data/lib/declarative_authorization/in_controller.rb +11 -0
- data/lib/declarative_authorization/in_model.rb +12 -17
- data/lib/declarative_authorization/obligation_scope.rb +34 -23
- data/lib/declarative_authorization/reader.rb +48 -9
- data/test/authorization_rules_analyzer_test.rb +123 -0
- data/test/authorization_test.rb +203 -0
- data/test/helper_test.rb +38 -0
- data/test/model_test.rb +323 -1
- data/test/schema.sql +22 -1
- metadata +4 -2
data/test/helper_test.rb
CHANGED
@@ -92,4 +92,42 @@ class HelperTest < ActionController::TestCase
|
|
92
92
|
assert !block_evaled
|
93
93
|
end
|
94
94
|
|
95
|
+
def test_has_role_with_hierarchy
|
96
|
+
reader = Authorization::Reader::DSLReader.new
|
97
|
+
reader.parse %{
|
98
|
+
authorization do
|
99
|
+
role :test_role do
|
100
|
+
has_permission_on :mocks, :to => :show
|
101
|
+
end
|
102
|
+
role :other_role do
|
103
|
+
has_permission_on :another_mocks, :to => :show
|
104
|
+
end
|
105
|
+
|
106
|
+
role :root do
|
107
|
+
includes :test_role
|
108
|
+
end
|
109
|
+
end
|
110
|
+
}
|
111
|
+
|
112
|
+
user = MockUser.new(:root)
|
113
|
+
request!(user, :action, reader)
|
114
|
+
|
115
|
+
assert has_role_with_hierarchy?(:test_role)
|
116
|
+
assert !has_role_with_hierarchy?(:other_role)
|
117
|
+
|
118
|
+
block_evaled = false
|
119
|
+
has_role_with_hierarchy?(:test_role) do
|
120
|
+
block_evaled = true
|
121
|
+
end
|
122
|
+
assert block_evaled
|
123
|
+
|
124
|
+
block_evaled = false
|
125
|
+
has_role_with_hierarchy?(:test_role2) do
|
126
|
+
block_evaled = true
|
127
|
+
end
|
128
|
+
assert !block_evaled
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
95
133
|
end
|
data/test/model_test.rb
CHANGED
@@ -24,7 +24,10 @@ class TestModel < ActiveRecord::Base
|
|
24
24
|
has_one :test_attr_throughs_with_attr_and_has_one, :through => :test_attrs,
|
25
25
|
:class_name => "TestAttrThrough", :source => :test_attr_throughs,
|
26
26
|
:conditions => "test_attrs.attr = 1"
|
27
|
-
|
27
|
+
|
28
|
+
has_and_belongs_to_many :test_attr_throughs_habtm, :join_table => :test_attrs,
|
29
|
+
:class_name => "TestAttrThrough"
|
30
|
+
|
28
31
|
# Primary key test
|
29
32
|
# take this out for Rails prior to 2.2
|
30
33
|
if ([Rails::VERSION::MAJOR, Rails::VERSION::MINOR] <=> [2, 2]) > -1
|
@@ -44,7 +47,11 @@ end
|
|
44
47
|
class TestAttr < ActiveRecord::Base
|
45
48
|
belongs_to :test_model
|
46
49
|
belongs_to :test_another_model, :class_name => "TestModel", :foreign_key => :test_another_model_id
|
50
|
+
belongs_to :test_a_third_model, :class_name => "TestModel", :foreign_key => :test_a_third_model_id
|
47
51
|
belongs_to :n_way_join_item
|
52
|
+
belongs_to :test_attr
|
53
|
+
belongs_to :branch
|
54
|
+
belongs_to :company
|
48
55
|
has_many :test_attr_throughs
|
49
56
|
attr_reader :role_symbols
|
50
57
|
def initialize (*args)
|
@@ -68,6 +75,20 @@ class TestModelSecurityModelWithFind < ActiveRecord::Base
|
|
68
75
|
:context => :test_model_security_models
|
69
76
|
end
|
70
77
|
|
78
|
+
class Branch < ActiveRecord::Base
|
79
|
+
has_many :test_attrs
|
80
|
+
belongs_to :company
|
81
|
+
end
|
82
|
+
class Company < ActiveRecord::Base
|
83
|
+
has_many :test_attrs
|
84
|
+
has_many :branches
|
85
|
+
belongs_to :country
|
86
|
+
end
|
87
|
+
class Country < ActiveRecord::Base
|
88
|
+
has_many :test_models
|
89
|
+
has_many :companies
|
90
|
+
end
|
91
|
+
|
71
92
|
class ModelTest < Test::Unit::TestCase
|
72
93
|
def test_named_scope_multiple_deep_ored_belongs_to
|
73
94
|
reader = Authorization::Reader::DSLReader.new
|
@@ -213,6 +234,34 @@ class ModelTest < Test::Unit::TestCase
|
|
213
234
|
assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length
|
214
235
|
TestModel.delete_all
|
215
236
|
end
|
237
|
+
|
238
|
+
def test_named_scope_multiple_roles
|
239
|
+
reader = Authorization::Reader::DSLReader.new
|
240
|
+
reader.parse %{
|
241
|
+
authorization do
|
242
|
+
role :test_role do
|
243
|
+
has_permission_on :test_attrs, :to => :read do
|
244
|
+
if_attribute :attr => [1,2]
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
role :test_role_2 do
|
249
|
+
has_permission_on :test_attrs, :to => :read do
|
250
|
+
if_attribute :attr => [2,3]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
}
|
255
|
+
Authorization::Engine.instance(reader)
|
256
|
+
|
257
|
+
TestAttr.create! :attr => 1
|
258
|
+
TestAttr.create! :attr => 2
|
259
|
+
TestAttr.create! :attr => 3
|
260
|
+
|
261
|
+
user = MockUser.new(:test_role)
|
262
|
+
assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length
|
263
|
+
TestAttr.delete_all
|
264
|
+
end
|
216
265
|
|
217
266
|
def test_named_scope_multiple_and_empty_obligations
|
218
267
|
reader = Authorization::Reader::DSLReader.new
|
@@ -358,6 +407,33 @@ class ModelTest < Test::Unit::TestCase
|
|
358
407
|
TestAttr.delete_all
|
359
408
|
end
|
360
409
|
|
410
|
+
def test_named_scope_with_anded_rules
|
411
|
+
reader = Authorization::Reader::DSLReader.new
|
412
|
+
reader.parse %{
|
413
|
+
authorization do
|
414
|
+
role :test_role do
|
415
|
+
has_permission_on :test_attrs, :to => :read, :join_by => :and do
|
416
|
+
if_attribute :test_model => is { user.test_model }
|
417
|
+
if_attribute :attr => 1
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
}
|
422
|
+
Authorization::Engine.instance(reader)
|
423
|
+
|
424
|
+
test_model_1 = TestModel.create!
|
425
|
+
test_model_1.test_attrs.create!(:attr => 1)
|
426
|
+
TestModel.create!.test_attrs.create!(:attr => 1)
|
427
|
+
TestModel.create!.test_attrs.create!
|
428
|
+
|
429
|
+
user = MockUser.new(:test_role, :test_model => test_model_1)
|
430
|
+
assert_equal 1, TestAttr.with_permissions_to(:read,
|
431
|
+
:context => :test_attrs, :user => user).length
|
432
|
+
|
433
|
+
TestModel.delete_all
|
434
|
+
TestAttr.delete_all
|
435
|
+
end
|
436
|
+
|
361
437
|
def test_named_scope_with_contains
|
362
438
|
reader = Authorization::Reader::DSLReader.new
|
363
439
|
reader.parse %{
|
@@ -476,6 +552,36 @@ class ModelTest < Test::Unit::TestCase
|
|
476
552
|
TestAttrThrough.delete_all
|
477
553
|
TestAttr.delete_all
|
478
554
|
end
|
555
|
+
|
556
|
+
def test_named_scope_with_contains_habtm
|
557
|
+
reader = Authorization::Reader::DSLReader.new
|
558
|
+
reader.parse %{
|
559
|
+
authorization do
|
560
|
+
role :test_role do
|
561
|
+
has_permission_on :test_models, :to => :read do
|
562
|
+
if_attribute :test_attr_throughs_habtm => contains { user.test_attr_through_id }
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
}
|
567
|
+
Authorization::Engine.instance(reader)
|
568
|
+
|
569
|
+
test_model_1 = TestModel.create!
|
570
|
+
test_model_2 = TestModel.create!
|
571
|
+
test_attr_through_1 = TestAttrThrough.create!
|
572
|
+
test_attr_through_2 = TestAttrThrough.create!
|
573
|
+
TestAttr.create! :test_model_id => test_model_1.id, :test_attr_through_id => test_attr_through_1.id
|
574
|
+
TestAttr.create! :test_model_id => test_model_2.id, :test_attr_through_id => test_attr_through_2.id
|
575
|
+
|
576
|
+
user = MockUser.new(:test_role,
|
577
|
+
:test_attr_through_id => test_model_1.test_attr_throughs_habtm.first.id)
|
578
|
+
assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length
|
579
|
+
assert_equal test_model_1, TestModel.with_permissions_to(:read, :user => user)[0]
|
580
|
+
|
581
|
+
TestModel.delete_all
|
582
|
+
TestAttrThrough.delete_all
|
583
|
+
TestAttr.delete_all
|
584
|
+
end
|
479
585
|
|
480
586
|
# take this out for Rails prior to 2.2
|
481
587
|
if ([Rails::VERSION::MAJOR, Rails::VERSION::MINOR] <=> [2, 2]) > -1
|
@@ -507,6 +613,38 @@ class ModelTest < Test::Unit::TestCase
|
|
507
613
|
TestAttr.delete_all
|
508
614
|
end
|
509
615
|
end
|
616
|
+
|
617
|
+
def test_named_scope_with_intersects_with
|
618
|
+
reader = Authorization::Reader::DSLReader.new
|
619
|
+
reader.parse %{
|
620
|
+
authorization do
|
621
|
+
role :test_role do
|
622
|
+
has_permission_on :test_models, :to => :read do
|
623
|
+
if_attribute :test_attrs => intersects_with { user.test_attrs }
|
624
|
+
end
|
625
|
+
end
|
626
|
+
end
|
627
|
+
}
|
628
|
+
Authorization::Engine.instance(reader)
|
629
|
+
|
630
|
+
test_model_1 = TestModel.create!
|
631
|
+
test_model_2 = TestModel.create!
|
632
|
+
test_model_1.test_attrs.create!
|
633
|
+
test_model_1.test_attrs.create!
|
634
|
+
test_model_1.test_attrs.create!
|
635
|
+
test_model_2.test_attrs.create!
|
636
|
+
|
637
|
+
user = MockUser.new(:test_role,
|
638
|
+
:test_attrs => [test_model_1.test_attrs.first, TestAttr.create!])
|
639
|
+
assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length
|
640
|
+
|
641
|
+
user = MockUser.new(:test_role,
|
642
|
+
:test_attrs => [TestAttr.create!])
|
643
|
+
assert_equal 0, TestModel.with_permissions_to(:read, :user => user).length
|
644
|
+
|
645
|
+
TestModel.delete_all
|
646
|
+
TestAttr.delete_all
|
647
|
+
end
|
510
648
|
|
511
649
|
def test_named_scope_with_is_and_has_one
|
512
650
|
reader = Authorization::Reader::DSLReader.new
|
@@ -693,6 +831,55 @@ class ModelTest < Test::Unit::TestCase
|
|
693
831
|
TestModel.delete_all
|
694
832
|
TestAttr.delete_all
|
695
833
|
end
|
834
|
+
|
835
|
+
def test_named_scope_with_if_permitted_to_nil
|
836
|
+
reader = Authorization::Reader::DSLReader.new
|
837
|
+
reader.parse %{
|
838
|
+
authorization do
|
839
|
+
role :test_role do
|
840
|
+
has_permission_on :test_models, :to => :read do
|
841
|
+
if_attribute :test_attrs => contains { user }
|
842
|
+
end
|
843
|
+
has_permission_on :test_attrs, :to => :read do
|
844
|
+
if_permitted_to :read, :test_model
|
845
|
+
end
|
846
|
+
end
|
847
|
+
end
|
848
|
+
}
|
849
|
+
Authorization::Engine.instance(reader)
|
850
|
+
|
851
|
+
test_attr_1 = TestAttr.create!
|
852
|
+
|
853
|
+
user = MockUser.new(:test_role, :id => test_attr_1.id)
|
854
|
+
assert_equal 0, TestAttr.with_permissions_to(:read, :user => user).length
|
855
|
+
TestAttr.delete_all
|
856
|
+
end
|
857
|
+
|
858
|
+
def test_named_scope_with_if_permitted_to_self
|
859
|
+
reader = Authorization::Reader::DSLReader.new
|
860
|
+
reader.parse %{
|
861
|
+
authorization do
|
862
|
+
role :test_role do
|
863
|
+
has_permission_on :test_models, :to => :read do
|
864
|
+
if_attribute :test_attrs => contains { user }
|
865
|
+
end
|
866
|
+
has_permission_on :test_models, :to => :update do
|
867
|
+
if_permitted_to :read
|
868
|
+
end
|
869
|
+
end
|
870
|
+
end
|
871
|
+
}
|
872
|
+
Authorization::Engine.instance(reader)
|
873
|
+
|
874
|
+
test_model_1 = TestModel.create!
|
875
|
+
test_attr_1 = test_model_1.test_attrs.create!
|
876
|
+
test_attr_2 = TestAttr.create!
|
877
|
+
|
878
|
+
user = MockUser.new(:test_role, :id => test_attr_1.id)
|
879
|
+
assert_equal 1, TestModel.with_permissions_to(:update, :user => user).length
|
880
|
+
TestAttr.delete_all
|
881
|
+
TestModel.delete_all
|
882
|
+
end
|
696
883
|
|
697
884
|
def test_model_security
|
698
885
|
reader = Authorization::Reader::DSLReader.new
|
@@ -818,4 +1005,139 @@ class ModelTest < Test::Unit::TestCase
|
|
818
1005
|
:user => MockUser.new(:test_role))
|
819
1006
|
TestModel.delete_all
|
820
1007
|
end
|
1008
|
+
|
1009
|
+
def test_multiple_roles_with_has_many_through
|
1010
|
+
reader = Authorization::Reader::DSLReader.new
|
1011
|
+
reader.parse %{
|
1012
|
+
authorization do
|
1013
|
+
role :test_role_1 do
|
1014
|
+
has_permission_on :test_models, :to => :read do
|
1015
|
+
if_attribute :test_attr_throughs => contains {user.test_attr_through_id},
|
1016
|
+
:content => 'test_1'
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
role :test_role_2 do
|
1021
|
+
has_permission_on :test_models, :to => :read do
|
1022
|
+
if_attribute :test_attr_throughs_2 => contains {user.test_attr_through_2_id},
|
1023
|
+
:content => 'test_2'
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
}
|
1028
|
+
Authorization::Engine.instance(reader)
|
1029
|
+
|
1030
|
+
test_model_1 = TestModel.create! :content => 'test_1'
|
1031
|
+
test_model_2 = TestModel.create! :content => 'test_2'
|
1032
|
+
test_model_1.test_attrs.create!.test_attr_throughs.create!
|
1033
|
+
test_model_2.test_attrs.create!.test_attr_throughs.create!
|
1034
|
+
|
1035
|
+
user = MockUser.new(:test_role_1, :test_role_2,
|
1036
|
+
:test_attr_through_id => test_model_1.test_attr_throughs.first.id,
|
1037
|
+
:test_attr_through_2_id => test_model_2.test_attr_throughs.first.id)
|
1038
|
+
assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length
|
1039
|
+
TestModel.delete_all
|
1040
|
+
TestAttr.delete_all
|
1041
|
+
TestAttrThrough.delete_all
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
def test_named_scope_with_has_many_and_reoccuring_tables
|
1045
|
+
reader = Authorization::Reader::DSLReader.new
|
1046
|
+
reader.parse %{
|
1047
|
+
authorization do
|
1048
|
+
role :test_role do
|
1049
|
+
has_permission_on :test_attrs, :to => :read do
|
1050
|
+
if_attribute :test_another_model => { :content => 'test_1_2' },
|
1051
|
+
:test_model => { :content => 'test_1_1' }
|
1052
|
+
end
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
}
|
1056
|
+
Authorization::Engine.instance(reader)
|
1057
|
+
|
1058
|
+
test_attr_1 = TestAttr.create!(
|
1059
|
+
:test_model => TestModel.create!(:content => 'test_1_1'),
|
1060
|
+
:test_another_model => TestModel.create!(:content => 'test_1_2')
|
1061
|
+
)
|
1062
|
+
test_attr_2 = TestAttr.create!(
|
1063
|
+
:test_model => TestModel.create!(:content => 'test_2_1'),
|
1064
|
+
:test_another_model => TestModel.create!(:content => 'test_2_2')
|
1065
|
+
)
|
1066
|
+
|
1067
|
+
user = MockUser.new(:test_role)
|
1068
|
+
assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length
|
1069
|
+
TestModel.delete_all
|
1070
|
+
TestAttr.delete_all
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def test_named_scope_with_ored_rules_and_reoccuring_tables
|
1074
|
+
reader = Authorization::Reader::DSLReader.new
|
1075
|
+
reader.parse %{
|
1076
|
+
authorization do
|
1077
|
+
role :test_role do
|
1078
|
+
has_permission_on :test_attrs, :to => :read do
|
1079
|
+
if_attribute :test_another_model => { :content => 'test_1_2' },
|
1080
|
+
:test_model => { :content => 'test_1_1' }
|
1081
|
+
end
|
1082
|
+
has_permission_on :test_attrs, :to => :read do
|
1083
|
+
if_attribute :test_another_model => { :content => 'test_2_2' },
|
1084
|
+
:test_model => { :test_attrs => contains {user.test_attr} }
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
end
|
1088
|
+
}
|
1089
|
+
Authorization::Engine.instance(reader)
|
1090
|
+
|
1091
|
+
test_attr_1 = TestAttr.create!(
|
1092
|
+
:test_model => TestModel.create!(:content => 'test_1_1'),
|
1093
|
+
:test_another_model => TestModel.create!(:content => 'test_1_2')
|
1094
|
+
)
|
1095
|
+
test_attr_2 = TestAttr.create!(
|
1096
|
+
:test_model => TestModel.create!(:content => 'test_2_1'),
|
1097
|
+
:test_another_model => TestModel.create!(:content => 'test_2_2')
|
1098
|
+
)
|
1099
|
+
test_attr_2.test_model.test_attrs.create!
|
1100
|
+
|
1101
|
+
user = MockUser.new(:test_role, :test_attr => test_attr_2.test_model.test_attrs.last)
|
1102
|
+
assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length
|
1103
|
+
TestModel.delete_all
|
1104
|
+
TestAttr.delete_all
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
def test_named_scope_with_many_ored_rules_and_reoccuring_tables
|
1108
|
+
reader = Authorization::Reader::DSLReader.new
|
1109
|
+
reader.parse %{
|
1110
|
+
authorization do
|
1111
|
+
role :test_role do
|
1112
|
+
has_permission_on :test_attrs, :to => :read do
|
1113
|
+
if_attribute :branch => { :company => { :country => {
|
1114
|
+
:test_models => contains { user.test_model }
|
1115
|
+
}} }
|
1116
|
+
if_attribute :company => { :country => {
|
1117
|
+
:test_models => contains { user.test_model }
|
1118
|
+
}}
|
1119
|
+
end
|
1120
|
+
end
|
1121
|
+
end
|
1122
|
+
}
|
1123
|
+
Authorization::Engine.instance(reader)
|
1124
|
+
|
1125
|
+
country = Country.create!(:name => 'country_1')
|
1126
|
+
country.test_models.create!
|
1127
|
+
test_attr_1 = TestAttr.create!(
|
1128
|
+
:branch => Branch.create!(:name => 'branch_1',
|
1129
|
+
:company => Company.create!(:name => 'company_1',
|
1130
|
+
:country => country))
|
1131
|
+
)
|
1132
|
+
test_attr_2 = TestAttr.create!(
|
1133
|
+
:company => Company.create!(:name => 'company_2',
|
1134
|
+
:country => country)
|
1135
|
+
)
|
1136
|
+
|
1137
|
+
user = MockUser.new(:test_role, :test_model => country.test_models.first)
|
1138
|
+
|
1139
|
+
assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length
|
1140
|
+
TestModel.delete_all
|
1141
|
+
TestAttr.delete_all
|
1142
|
+
end
|
821
1143
|
end
|
data/test/schema.sql
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
CREATE TABLE 'test_models' (
|
2
2
|
'id' INTEGER PRIMARY KEY NOT NULL,
|
3
3
|
'test_attr_through_id' INTEGER,
|
4
|
-
'content' text,
|
4
|
+
'content' text,
|
5
|
+
'country_id' integer,
|
5
6
|
'created_at' datetime,
|
6
7
|
'updated_at' datetime
|
7
8
|
);
|
@@ -10,6 +11,9 @@ CREATE TABLE 'test_attrs' (
|
|
10
11
|
'id' INTEGER PRIMARY KEY NOT NULL,
|
11
12
|
'test_model_id' integer,
|
12
13
|
'test_another_model_id' integer,
|
14
|
+
'test_a_third_model_id' integer,
|
15
|
+
'branch_id' integer,
|
16
|
+
'company_id' integer,
|
13
17
|
'test_attr_through_id' INTEGER,
|
14
18
|
'n_way_join_item_id' INTEGER,
|
15
19
|
'test_model_security_model_id' integer,
|
@@ -30,3 +34,20 @@ CREATE TABLE 'test_model_security_models' (
|
|
30
34
|
CREATE TABLE 'n_way_join_items' (
|
31
35
|
'id' INTEGER PRIMARY KEY NOT NULL
|
32
36
|
);
|
37
|
+
|
38
|
+
CREATE TABLE 'branches' (
|
39
|
+
'id' INTEGER PRIMARY KEY NOT NULL,
|
40
|
+
'company_id' integer,
|
41
|
+
'name' text
|
42
|
+
);
|
43
|
+
|
44
|
+
CREATE TABLE 'companies' (
|
45
|
+
'id' INTEGER PRIMARY KEY NOT NULL,
|
46
|
+
'country_id' integer,
|
47
|
+
'name' text
|
48
|
+
);
|
49
|
+
|
50
|
+
CREATE TABLE 'countries' (
|
51
|
+
'id' INTEGER PRIMARY KEY NOT NULL,
|
52
|
+
'name' text
|
53
|
+
);
|