cbac 0.3.1 → 0.5.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/Manifest +60 -44
- data/Rakefile +2 -2
- data/cbac.gemspec +31 -31
- data/generators/cbac/cbac_generator.rb +27 -6
- data/generators/cbac/templates/config/cbac.pristine +2 -0
- data/generators/cbac/templates/controllers/permissions_controller.rb +21 -2
- data/generators/cbac/templates/controllers/upgrade_controller.rb +24 -0
- data/generators/cbac/templates/fixtures/cbac_memberships.yml +1 -1
- data/generators/cbac/templates/migrate/create_cbac_from_scratch.rb +59 -0
- data/generators/cbac/templates/migrate/create_cbac_upgrade_path.rb +31 -0
- data/generators/cbac/templates/tasks/cbac.rake +345 -0
- data/generators/cbac/templates/views/layouts/cbac.html.erb +2 -1
- data/generators/cbac/templates/views/memberships/index.html.erb +1 -1
- data/generators/cbac/templates/views/permissions/index.html.erb +14 -6
- data/generators/cbac/templates/views/upgrade/index.html.erb +32 -0
- data/lib/cbac.rb +23 -12
- data/lib/cbac/cbac_pristine/pristine.rb +133 -0
- data/lib/cbac/cbac_pristine/pristine_file.rb +158 -0
- data/lib/cbac/cbac_pristine/pristine_permission.rb +194 -0
- data/lib/cbac/cbac_pristine/pristine_role.rb +42 -0
- data/lib/cbac/known_permission.rb +14 -0
- data/lib/cbac/permission.rb +1 -1
- data/lib/cbac/privilege.rb +44 -0
- data/lib/cbac/privilege_set.rb +5 -4
- data/lib/cbac/privilege_set_record.rb +3 -1
- data/spec/cbac_pristine_file_spec.rb +329 -0
- data/spec/cbac_pristine_permission_spec.rb +358 -0
- data/spec/cbac_pristine_role_spec.rb +85 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +12 -0
- data/tasks/cbac.rake +345 -19
- data/test/test_cbac_privilege.rb +54 -0
- metadata +43 -9
- data/generators/cbac/templates/migrate/create_cbac.rb +0 -40
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'pristine_role'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'pristine_permission'))
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module Cbac
|
6
|
+
module CbacPristine
|
7
|
+
class PristinePermission < ActiveRecord::Base
|
8
|
+
set_table_name 'cbac_staged_permissions'
|
9
|
+
|
10
|
+
belongs_to :pristine_role, :class_name => "Cbac::CbacPristine::PristineRole"
|
11
|
+
|
12
|
+
def privilege_set
|
13
|
+
Cbac::PrivilegeSetRecord.first(:conditions => {:name => privilege_set_name})
|
14
|
+
end
|
15
|
+
|
16
|
+
def operation_string
|
17
|
+
case operation
|
18
|
+
when '+'
|
19
|
+
return "add"
|
20
|
+
when '-'
|
21
|
+
return "revoke"
|
22
|
+
else
|
23
|
+
return "unknown"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#convert this pristine line to a yml statement which can be used to create a yml fixtures file
|
28
|
+
#executing this statement will result in one cbac_permission in the DB
|
29
|
+
def to_yml_fixture(fixture_id = nil)
|
30
|
+
raise ArgumentError, "Error: cannot convert line #{line_number.to_s} to yml because the role is not specified" if pristine_role.nil?
|
31
|
+
raise ArgumentError, "Error: cannot convert line #{line_number.to_s} to yml because the privilege_set_name is not specified" if privilege_set_name.blank?
|
32
|
+
|
33
|
+
fixture_id = line_number if fixture_id.nil?
|
34
|
+
|
35
|
+
yml = "cbac_permission_00" << fixture_id.to_s << ":\n"
|
36
|
+
yml << " id: " << fixture_id.to_s << "\n"
|
37
|
+
yml << " context_role: "
|
38
|
+
yml << pristine_role.name if pristine_role.role_type == PristineRole.ROLE_TYPES[:context]
|
39
|
+
yml << "\n"
|
40
|
+
yml << " generic_role_id: " << pristine_role.role_id.to_s << "\n"
|
41
|
+
yml << " privilege_set_id: <%= Cbac::PrivilegeSetRecord.find(:first, :conditions => {:name => '" << privilege_set_name << "'}).id %>\n"
|
42
|
+
yml << " created_at: " << Time.now.strftime("%Y-%m-%d %H:%M:%S") << "\n"
|
43
|
+
yml << " updated_at: " << Time.now.strftime("%Y-%m-%d %H:%M:%S") << "\n"
|
44
|
+
yml << "\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
# checks if the current cbac permissions contains a permission which is exactly like this one
|
48
|
+
def cbac_permission_exists?
|
49
|
+
if pristine_role.role_type == PristineRole.ROLE_TYPES[:context]
|
50
|
+
Cbac::Permission.count(:joins => [:privilege_set], :conditions => {:cbac_privilege_set => {:name => privilege_set_name}, :context_role => pristine_role.name}) > 0
|
51
|
+
else
|
52
|
+
Cbac::Permission.count(:joins => [:generic_role, :privilege_set], :conditions => {:cbac_privilege_set => {:name => privilege_set_name}, :cbac_generic_roles => {:name => pristine_role.name}}) > 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# checks if a pristine permission with the same properties(except line_number) exists in the database
|
57
|
+
def exists?
|
58
|
+
Cbac::CbacPristine::PristinePermission.count(:conditions => {:privilege_set_name => privilege_set_name, :pristine_role_id => pristine_role_id, :operation => operation}) > 0
|
59
|
+
end
|
60
|
+
|
61
|
+
# checks if a pristine permission with the exact same properties(except line_number), but the reverse operation exists in the database
|
62
|
+
def reverse_exists?
|
63
|
+
Cbac::CbacPristine::PristinePermission.count(:conditions => {:privilege_set_name => privilege_set_name, :pristine_role_id => pristine_role_id, :operation => reverse_operation}) > 0
|
64
|
+
end
|
65
|
+
|
66
|
+
# delete the pristine permission with the reverse operation of this one
|
67
|
+
def delete_reverse_permission
|
68
|
+
reverse_permission = Cbac::CbacPristine::PristinePermission.first(:conditions => {:privilege_set_name => privilege_set_name, :pristine_role_id => pristine_role_id, :operation => reverse_operation})
|
69
|
+
reverse_permission.delete
|
70
|
+
end
|
71
|
+
|
72
|
+
# get the reverse operation of this one
|
73
|
+
def reverse_operation
|
74
|
+
case operation
|
75
|
+
when '+'
|
76
|
+
return '-'
|
77
|
+
when '-'
|
78
|
+
return '+'
|
79
|
+
when 'x', '=>'
|
80
|
+
raise NotImplementedError, "Error: using an x or => in a pristine file is not implemented yet"
|
81
|
+
else
|
82
|
+
raise ArgumentError, "Error: invalid operation #{operation} is used in the pristine file"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# checks if the known_permissions table has an entry for this permission
|
87
|
+
def known_permission_exists?
|
88
|
+
Cbac::KnownPermission.count(:conditions => {:permission_type => pristine_role.known_permission_type, :permission_number => line_number}) > 0
|
89
|
+
end
|
90
|
+
|
91
|
+
# accept this permission and apply to the current cbac permission set
|
92
|
+
def accept
|
93
|
+
case operation
|
94
|
+
when '+'
|
95
|
+
handle_grant_permission
|
96
|
+
when '-'
|
97
|
+
handle_revoke_permission
|
98
|
+
when 'x', '=>'
|
99
|
+
raise NotImplementedError, "Error: using an x or => in a pristine file is not implemented yet"
|
100
|
+
else
|
101
|
+
raise ArgumentError, "Error: invalid operation #{operation} is used in the pristine file"
|
102
|
+
end
|
103
|
+
PristinePermission.delete(id) unless id.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
# reject this permission, but register it as a known permission. The user actually rejected this himself.
|
107
|
+
def reject
|
108
|
+
register_change
|
109
|
+
PristinePermission.delete(id) unless id.nil?
|
110
|
+
end
|
111
|
+
|
112
|
+
# add this permission to the cbac permission set, unless it already exists
|
113
|
+
def handle_grant_permission
|
114
|
+
return if cbac_permission_exists?
|
115
|
+
|
116
|
+
permission = Cbac::Permission.new
|
117
|
+
permission.privilege_set = privilege_set
|
118
|
+
|
119
|
+
if pristine_role.role_type == PristineRole.ROLE_TYPES[:context]
|
120
|
+
permission.context_role = pristine_role.name
|
121
|
+
else
|
122
|
+
generic_role = Cbac::GenericRole.first(:conditions => {:name => pristine_role.name})
|
123
|
+
permission.generic_role = generic_role.nil? ? Cbac::GenericRole.create(:name => pristine_role.name, :remarks => "Autogenerated by Cbac loading / upgrade system") : generic_role
|
124
|
+
end
|
125
|
+
|
126
|
+
register_change if permission.save
|
127
|
+
permission
|
128
|
+
end
|
129
|
+
|
130
|
+
# revoke this permission from the current permission set, raises an error if it doesn't exist yet
|
131
|
+
def handle_revoke_permission
|
132
|
+
raise ArgumentError, "Error: trying to revoke permission #{privilege_set_name} for #{pristine_role.name}, but this permission does not exist" unless cbac_permission_exists?
|
133
|
+
|
134
|
+
if pristine_role.role_type == PristineRole.ROLE_TYPES[:context]
|
135
|
+
permission = Cbac::Permission.first(:joins => [:privilege_set], :conditions => {:cbac_privilege_set => {:name => privilege_set_name}, :context_role => pristine_role.name})
|
136
|
+
else
|
137
|
+
permission = Cbac::Permission.first(:joins => [:generic_role, :privilege_set], :conditions => {:cbac_privilege_set => {:name => privilege_set_name}, :cbac_generic_roles => {:name => pristine_role.name}})
|
138
|
+
end
|
139
|
+
|
140
|
+
register_change if permission.destroy
|
141
|
+
end
|
142
|
+
|
143
|
+
# register this permission as a known permission
|
144
|
+
def register_change
|
145
|
+
Cbac::KnownPermission.create(:permission_number => line_number, :permission_type => pristine_role.known_permission_type)
|
146
|
+
end
|
147
|
+
|
148
|
+
# add this permission to the staging area
|
149
|
+
def stage
|
150
|
+
raise ArgumentError, "Error: this staged permission already exists. Record with line number #{line_number} is a duplicate permission." if exists?
|
151
|
+
return if known_permission_exists?
|
152
|
+
|
153
|
+
if operation == '-'
|
154
|
+
# if the reverse permission is also staged, remove it and do not add this one
|
155
|
+
if reverse_exists?
|
156
|
+
delete_reverse_permission
|
157
|
+
return
|
158
|
+
end
|
159
|
+
# if this is an attempt to revoke a permission, it should exist as a real cbac permission!
|
160
|
+
save if cbac_permission_exists?
|
161
|
+
elsif operation == '+'
|
162
|
+
# if this is an attempt to add a permission, it MUST not exist yet
|
163
|
+
save unless cbac_permission_exists?
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
# clear the staging area of all generic pristine permissions
|
170
|
+
def self.delete_generic_permissions
|
171
|
+
generic_staged_permissions = all(:joins => :pristine_role, :conditions => ["cbac_staged_roles.role_type = ?", PristineRole.ROLE_TYPES[:generic]])
|
172
|
+
generic_staged_permissions.each do |permission|
|
173
|
+
delete(permission.id)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# clear the staging area of all non generic permissions
|
178
|
+
def self.delete_non_generic_permissions
|
179
|
+
staged_permissions = all(:joins => :pristine_role, :conditions => ["cbac_staged_roles.role_type != ?", PristineRole.ROLE_TYPES[:generic]])
|
180
|
+
staged_permissions.each do |permission|
|
181
|
+
delete(permission.id)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.count_generic_permissions
|
186
|
+
count(:joins => :pristine_role, :conditions => ["cbac_staged_roles.role_type = ?", PristineRole.ROLE_TYPES[:generic]])
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.count_non_generic_permissions
|
190
|
+
count(:joins => :pristine_role, :conditions => ["cbac_staged_roles.role_type != ?", PristineRole.ROLE_TYPES[:generic]])
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
module Cbac
|
3
|
+
module CbacPristine
|
4
|
+
class PristineRole < ActiveRecord::Base
|
5
|
+
set_table_name "cbac_staged_roles"
|
6
|
+
|
7
|
+
def self.ROLE_TYPES
|
8
|
+
{:context => "context", :generic => "generic", :admin => "administrator"}
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
#convert this cbac role to a yml statement which can be used to create a yml fixtures file
|
13
|
+
#executing this statement will result in one cbac_generic_role in the DB
|
14
|
+
def to_yml_fixture(fixture_id = nil)
|
15
|
+
fixture_id = role_id if fixture_id.nil?
|
16
|
+
|
17
|
+
return '' if role_type == Cbac::CbacPristine::PristineRole.ROLE_TYPES[:context]
|
18
|
+
raise ArgumentError, "cannot convert role #{id.to_s} to yml, because it has no name" if name.blank?
|
19
|
+
|
20
|
+
yml = "cbac_generic_role_00" << fixture_id.to_s << ":\n"
|
21
|
+
yml << " id: " << fixture_id.to_s << "\n"
|
22
|
+
yml << " name: " << name << "\n"
|
23
|
+
yml << " created_at: " << Time.now.strftime("%Y-%m-%d %H:%M:%S") << "\n"
|
24
|
+
yml << " updated_at: " << Time.now.strftime("%Y-%m-%d %H:%M:%S") << "\n"
|
25
|
+
yml << "\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def known_permission_type
|
29
|
+
# NOTE: known permissions use different type definitions than pristine roles.
|
30
|
+
# They only use the file type to determine if it is a generic or context role.
|
31
|
+
# Context roles include the admin role (same file) while pristine roles use a different type
|
32
|
+
role_type == PristineRole.ROLE_TYPES[:generic] ? Cbac::KnownPermission.PERMISSION_TYPES[:generic] : Cbac::KnownPermission.PERMISSION_TYPES[:context]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.admin_role(use_db = true)
|
36
|
+
admin_role = use_db ? PristineRole.first(:conditions => {:role_type => PristineRole.ROLE_TYPES[:admin]}) : nil
|
37
|
+
|
38
|
+
admin_role.nil? ? PristineRole.new(:role_id => 1, :role_type => PristineRole.ROLE_TYPES[:admin], :name => "administrator") : admin_role
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Cbac::KnownPermission < ActiveRecord::Base
|
2
|
+
set_table_name "cbac_known_permissions"
|
3
|
+
|
4
|
+
cattr_accessor :PERMISSION_TYPES
|
5
|
+
@@PERMISSION_TYPES = {:context => 0, :generic => 1}
|
6
|
+
|
7
|
+
def self.find_context_permissions(conditions = {})
|
8
|
+
all(:conditions => conditions.merge(:permission_type => @@PERMISSION_TYPES[:context]))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find_generic_permissions(conditions = {})
|
12
|
+
all(:conditions => conditions.merge(:permission_type => @@PERMISSION_TYPES[:generic]))
|
13
|
+
end
|
14
|
+
end
|
data/lib/cbac/permission.rb
CHANGED
@@ -2,5 +2,5 @@ class Cbac::Permission < ActiveRecord::Base
|
|
2
2
|
set_table_name "cbac_permissions"
|
3
3
|
|
4
4
|
belongs_to :generic_role, :class_name => "Cbac::GenericRole", :foreign_key => "generic_role_id"
|
5
|
-
belongs_to :
|
5
|
+
belongs_to :privilege_set, :class_name => "Cbac::PrivilegeSetRecord", :foreign_key => "privilege_set_id"
|
6
6
|
end
|
data/lib/cbac/privilege.rb
CHANGED
@@ -7,6 +7,14 @@ class Privilege
|
|
7
7
|
class << self
|
8
8
|
attr_reader :get_resources, :post_resources, :model_attributes, :models
|
9
9
|
|
10
|
+
# The includes hash contains references to inheritence. The key points to the
|
11
|
+
# base class, the value is an array of children.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# If Child inherits from Parent, then the structure would be:
|
15
|
+
# includes[:Parent] = [:Child]
|
16
|
+
attr_reader :includes
|
17
|
+
|
10
18
|
# Links a resource with a PrivilegeSet
|
11
19
|
#
|
12
20
|
# An ArgumentError exception is thrown if the PrivilegeSet does not exist.
|
@@ -22,12 +30,43 @@ class Privilege
|
|
22
30
|
case action_option[0]
|
23
31
|
when "GET"
|
24
32
|
(@get_resources[method] ||= Array.new) << PrivilegeSet.sets[privilege_set]
|
33
|
+
(@includes[privilege_set] || Array.new).each {|child_set| (@get_resources[method] ||= Array.new) << PrivilegeSet.sets[child_set]} unless @includes.nil?
|
25
34
|
when "POST"
|
26
35
|
(@post_resources[method] ||= Array.new) << PrivilegeSet.sets[privilege_set]
|
36
|
+
(@includes[privilege_set] || Array.new).each {|child_set| (@post_resources[method] ||= Array.new) << PrivilegeSet.sets[child_set]} unless @includes.nil?
|
27
37
|
else
|
38
|
+
raise "This should never happen"
|
28
39
|
end
|
29
40
|
end
|
30
41
|
|
42
|
+
# Make a privilege set dependant on other privilege set(s).
|
43
|
+
#
|
44
|
+
# Usage:
|
45
|
+
# Privilege.include :child_set, :base_set
|
46
|
+
# Privilege.include :child_set, [:base_set_1, :base_set_2]
|
47
|
+
#
|
48
|
+
# An ArgumentError exception is thrown if any of the PrivilegeSet methods do not exist.
|
49
|
+
def include(privilege_set, included_privilege_set)
|
50
|
+
@includes = Hash.new if @includes.nil?
|
51
|
+
child_set = privilege_set.to_sym
|
52
|
+
raise ArgumentError, "CBAC: PrivilegeSet does not exist: #{child_set}" unless PrivilegeSet.sets.include?(child_set)
|
53
|
+
included_privilege_set = [included_privilege_set] unless included_privilege_set.is_a?(Enumerable)
|
54
|
+
included_privilege_set.each do |base_set|
|
55
|
+
# Check for existence of PrivilegeSet
|
56
|
+
raise ArgumentError, "CBAC: PrivilegeSet does not exist: #{base_set}" unless PrivilegeSet.sets.include?(base_set)
|
57
|
+
# Adds the references
|
58
|
+
(@includes[base_set.to_sym] ||= Array.new) << child_set
|
59
|
+
# Copies existing resources
|
60
|
+
@get_resources.each do |method, privilege_sets|
|
61
|
+
resource child_set, method, :get if privilege_sets.any? {|set| set.name == base_set.to_s}
|
62
|
+
end
|
63
|
+
@post_resources.each do |method, privilege_sets|
|
64
|
+
resource child_set, method, :post if privilege_sets.any? {|set| set.name == base_set.to_s}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
31
70
|
def model_attribute
|
32
71
|
|
33
72
|
end
|
@@ -39,6 +78,11 @@ class Privilege
|
|
39
78
|
# action_type Valid values for action_type are "get", "post" and "put".
|
40
79
|
# "put" is converted into "post".
|
41
80
|
#
|
81
|
+
# Usage:
|
82
|
+
# Privilege.select "my_controller/action", :get
|
83
|
+
#
|
84
|
+
# Returns an array of PrivilegeSet objects
|
85
|
+
#
|
42
86
|
# If incorrect values are given for action_type the method will raise an
|
43
87
|
# ArgumentError. If the controller and action name are not found, an
|
44
88
|
# exception is being raised.
|
data/lib/cbac/privilege_set.rb
CHANGED
@@ -18,10 +18,11 @@ class Cbac::PrivilegeSet
|
|
18
18
|
@sets = Hash.new if @sets.nil?
|
19
19
|
# check for double creation
|
20
20
|
raise ArgumentError, "CBAC: PrivilegeSet was already defined: #{symbol.to_s}" if @sets.include?(symbol)
|
21
|
-
# Create record if
|
22
|
-
|
23
|
-
record
|
24
|
-
record.
|
21
|
+
# Create record if privilege set doesn't exist
|
22
|
+
record = Cbac::PrivilegeSetRecord.find_or_create_by_name(symbol.to_s)
|
23
|
+
record.set_comment(comment)
|
24
|
+
record.save
|
25
|
+
|
25
26
|
@sets[symbol] = record
|
26
27
|
end
|
27
28
|
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'cbac/cbac_pristine/pristine_permission'
|
3
|
+
require 'cbac/cbac_pristine/pristine_role'
|
4
|
+
require 'cbac/cbac_pristine/pristine_file'
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
6
|
+
include Cbac::CbacPristine
|
7
|
+
|
8
|
+
describe "CbacPristineFile" do
|
9
|
+
before(:each) do
|
10
|
+
@pristine_file = PristineFile.new("cbac.pristine")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "indicate if a line looks like a pristine line" do
|
14
|
+
|
15
|
+
it "should indicate that a ruby style comment line is not a pristine line" do
|
16
|
+
comment_line = "#this is a comment line in Ruby"
|
17
|
+
|
18
|
+
@pristine_file.is_pristine_permission_line?(comment_line, 1).should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error if the line does not look like a pristine line" do
|
22
|
+
line = "this is not pristine line. And it isn't a comment. 1"
|
23
|
+
|
24
|
+
proc{
|
25
|
+
@pristine_file.is_pristine_permission_line?(line, 0)
|
26
|
+
}.should raise_error(SyntaxError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return true in case of a valid pristine line" do
|
30
|
+
line = "0:+:PrivilegeSet(login)ContextRole(everybody)"
|
31
|
+
|
32
|
+
@pristine_file.is_pristine_permission_line?(line, 0).should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should fail if the id of the pristine line contains a character" do
|
36
|
+
line = "0b:+:PrivilegeSet(login)ContextRole(everybody)"
|
37
|
+
|
38
|
+
proc{
|
39
|
+
@pristine_file.is_pristine_permission_line?(line, 0)
|
40
|
+
}.should raise_error(SyntaxError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should succeed if the privilege set name is not provided" do
|
44
|
+
line = "0:+:PrivilegeSet()Admin()"
|
45
|
+
|
46
|
+
@pristine_file.is_pristine_permission_line?(line, 0).should be_true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should succeed if the context role name is not provided" do
|
50
|
+
line = "0:+:PrivilegeSet(login)ContextRole()"
|
51
|
+
|
52
|
+
@pristine_file.is_pristine_permission_line?(line, 0).should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "parse the privilege set name from a pristine line" do
|
58
|
+
it "should fail if the privilege set name is not provided" do
|
59
|
+
line = "0:+:PrivilegeSet()Admin()"
|
60
|
+
|
61
|
+
proc{
|
62
|
+
@pristine_file.parse_privilege_set_name(line, 0)
|
63
|
+
}.should raise_error(SyntaxError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return the name of the privilege set provided in the line" do
|
67
|
+
privilege_set_name = "chat"
|
68
|
+
line = "0:+:PrivilegeSet(#{privilege_set_name})Admin()"
|
69
|
+
|
70
|
+
@pristine_file.parse_privilege_set_name(line, 0).should == privilege_set_name
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should fail if an invalid line is provided" do
|
74
|
+
line = "0:+:ContextRole(toeteraars)"
|
75
|
+
|
76
|
+
proc{
|
77
|
+
@pristine_file.parse_privilege_set_name(line, 0)
|
78
|
+
}.should raise_error(SyntaxError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "parse the role from a pristine line" do
|
83
|
+
it "should return the admin role if the role is Admin()" do
|
84
|
+
admin_role = PristineRole.new(:role_id => 0, :role_type => PristineRole.ROLE_TYPES[:admin], :name => 'administrators')
|
85
|
+
PristineRole.stub!(:admin_role).and_return(admin_role)
|
86
|
+
line = "0:+:PrivilegeSet(chat)Admin()"
|
87
|
+
|
88
|
+
@pristine_file.parse_role(line, 0).should == admin_role
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return a context role if the role specified as ContextRole" do
|
92
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"
|
93
|
+
|
94
|
+
@pristine_file.parse_role(line, 0).role_type.should == PristineRole.ROLE_TYPES[:context]
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should return a context role with specified name if the role specified as ContextRole" do
|
98
|
+
context_role_name = "logged_in_user"
|
99
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(#{context_role_name})"
|
100
|
+
|
101
|
+
@pristine_file.parse_role(line, 0).name.should == context_role_name
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return an existing context role with specified name if possible" do
|
105
|
+
context_role_name = "logged_in_user"
|
106
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(#{context_role_name})"
|
107
|
+
existing_context_role = PristineRole.create(:name => context_role_name, :role_id => 0, :role_type => PristineRole.ROLE_TYPES[:context])
|
108
|
+
|
109
|
+
@pristine_file.parse_role(line, 0).should == existing_context_role
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should not return an existing context role with specified name if db should not be used" do
|
113
|
+
context_role_name = "logged_in_user"
|
114
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(#{context_role_name})"
|
115
|
+
existing_context_role = PristineRole.create(:name => context_role_name, :role_id => 0, :role_type => PristineRole.ROLE_TYPES[:context])
|
116
|
+
|
117
|
+
@pristine_file.parse_role(line, 0, false).should_not == existing_context_role
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should return a context role with id of 0 if the role specified as ContextRole" do
|
121
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"
|
122
|
+
|
123
|
+
@pristine_file.parse_role(line, 0).role_id.should == 0
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should fail if an invalid line is provided" do
|
127
|
+
line = "0:+:PrivilegeSet(toeteraars)"
|
128
|
+
|
129
|
+
proc{
|
130
|
+
@pristine_file.parse_role(line, 0)
|
131
|
+
}.should raise_error(SyntaxError)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should fail if a generic role is provided for the normal (non-generic) pristine file" do
|
135
|
+
line = "0:+:PrivilegeSet(chat)GenericRole(group_admins)"
|
136
|
+
|
137
|
+
proc{
|
138
|
+
@pristine_file.parse_role(line, 0)
|
139
|
+
}.should raise_error(SyntaxError)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
it "should return a generic role if a generic pristine file is used" do
|
144
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
145
|
+
line = "0:+:PrivilegeSet(chat)GenericRole(group_admins)"
|
146
|
+
|
147
|
+
@pristine_file.parse_role(line, 0).role_type.should == PristineRole.ROLE_TYPES[:generic]
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should return an existing generic role if use_db is not specified" do
|
151
|
+
generic_role_name = 'group_admins'
|
152
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
153
|
+
line = "0:+:PrivilegeSet(chat)GenericRole(#{generic_role_name})"
|
154
|
+
existing_role = PristineRole.create(:role_id => 1, :role_type => PristineRole.ROLE_TYPES[:generic], :name => generic_role_name)
|
155
|
+
|
156
|
+
@pristine_file.parse_role(line, 0).should == existing_role
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not use an existing role if use_db is set to false" do
|
160
|
+
generic_role_name = 'group_admins'
|
161
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
162
|
+
line = "0:+:PrivilegeSet(chat)GenericRole(#{generic_role_name})"
|
163
|
+
existing_role = PristineRole.create(:role_id => 1, :role_type => PristineRole.ROLE_TYPES[:generic], :name => generic_role_name)
|
164
|
+
|
165
|
+
@pristine_file.parse_role(line, 0, false).should_not == existing_role
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should fail if an Admin role is used in a generic pristine file" do
|
169
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
170
|
+
line = "0:+:PrivilegeSet(chat)Admin()"
|
171
|
+
|
172
|
+
proc{
|
173
|
+
@pristine_file.parse_role(line, 0)
|
174
|
+
}.should raise_error(SyntaxError)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should fail if an context role is used in a generic pristine file" do
|
178
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
179
|
+
line = "0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"
|
180
|
+
|
181
|
+
proc{
|
182
|
+
@pristine_file.parse_role(line, 0)
|
183
|
+
}.should raise_error(SyntaxError)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should fail if an invalid line is provided in a generic pristine file" do
|
187
|
+
@pristine_file = GenericPristineFile.new("cbac.pristine")
|
188
|
+
line = "0:+:PrivilegeSet(toeteraars)"
|
189
|
+
|
190
|
+
proc{
|
191
|
+
@pristine_file.parse_role(line, 0)
|
192
|
+
}.should raise_error(SyntaxError)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "parsing a cbac_pristine file" do
|
197
|
+
|
198
|
+
it "should fail if a row number is used twice" do
|
199
|
+
pristine_file_lines = ["0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
200
|
+
pristine_file_lines.push("0:+:PrivilegeSet(log_in)ContextRole(everybody)")
|
201
|
+
|
202
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
203
|
+
|
204
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
205
|
+
|
206
|
+
proc{
|
207
|
+
pristine_file.parse
|
208
|
+
}.should raise_error(SyntaxError)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should fill the lines array with an object for each file line" do
|
212
|
+
pristine_file_lines = ["0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
213
|
+
pristine_file_lines.push("1:+:PrivilegeSet(log_in)ContextRole(everybody)")
|
214
|
+
pristine_file_lines.push("2:+:PrivilegeSet(log_out)ContextRole(logged_in_user)")
|
215
|
+
|
216
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
217
|
+
|
218
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
219
|
+
pristine_file.parse
|
220
|
+
|
221
|
+
pristine_file.permissions.length.should == pristine_file_lines.length
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should not create an object for a comment line" do
|
225
|
+
pristine_file_lines = ["0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
226
|
+
pristine_file_lines.push("1:+:PrivilegeSet(log_in)ContextRole(everybody)")
|
227
|
+
pristine_file_lines.push("#this is a Ruby comment line")
|
228
|
+
|
229
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
230
|
+
|
231
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
232
|
+
pristine_file.parse
|
233
|
+
|
234
|
+
pristine_file.permissions.length.should == 2
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should also add a permission object if permission is revoked (operand - is used)" do
|
238
|
+
pristine_file_lines = ["0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
239
|
+
pristine_file_lines.push("1:+:PrivilegeSet(log_in)ContextRole(everybody)")
|
240
|
+
pristine_file_lines.push("2:-:PrivilegeSet(chat)ContextRole(logged_in_user)")
|
241
|
+
|
242
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
243
|
+
|
244
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
245
|
+
pristine_file.parse
|
246
|
+
|
247
|
+
pristine_file.permissions.length.should == 3
|
248
|
+
pristine_file.permissions[2].operation.should == '-'
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should fail if a permission is revoked which wasn't added before" do
|
252
|
+
pristine_file_lines = ["0:+:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
253
|
+
pristine_file_lines.push("1:+:PrivilegeSet(log_in)ContextRole(everybody)")
|
254
|
+
pristine_file_lines.push("2:-:PrivilegeSet(chat)ContextRole(everybody)")
|
255
|
+
|
256
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
257
|
+
|
258
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
259
|
+
proc{
|
260
|
+
pristine_file.parse
|
261
|
+
}.should raise_error(SyntaxError)
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should fail if an x is used as an operand" do
|
265
|
+
pristine_file_lines = ["0:x:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
266
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
267
|
+
|
268
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
269
|
+
proc{
|
270
|
+
pristine_file.parse
|
271
|
+
}.should raise_error(NotImplementedError)
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should fail if an => is used as an operand" do
|
275
|
+
pristine_file_lines = ["0:=>:PrivilegeSet(chat)ContextRole(logged_in_user)"]
|
276
|
+
File.stub!(:open).and_return(pristine_file_lines)
|
277
|
+
|
278
|
+
pristine_file = PristineFile.new("cbac.pristine")
|
279
|
+
proc{
|
280
|
+
pristine_file.parse
|
281
|
+
}.should raise_error(NotImplementedError)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "permission set" do
|
286
|
+
before(:each) do
|
287
|
+
@context_role = PristineRole.new(:role_id => 0, :role_type => PristineRole.ROLE_TYPES[:context], :name => "logged_in_user")
|
288
|
+
@admin_role = PristineRole.new(:role_id => 1, :role_type => PristineRole.ROLE_TYPES[:admin],:name => "administrator")
|
289
|
+
@pristine_file = PristineFile.new("cbac.pristine")
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should filter out the permissions which were revoked" do
|
293
|
+
permission_to_revoke = PristinePermission.new(:privilege_set_name => "chat", :pristine_role => @context_role, :operation => '+')
|
294
|
+
@pristine_file.permissions.push(permission_to_revoke)
|
295
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => permission_to_revoke.privilege_set_name, :pristine_role => permission_to_revoke.pristine_role, :operation => '-'))
|
296
|
+
|
297
|
+
@pristine_file.permission_set.should_not include(permission_to_revoke)
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should not include the revoke permission itself" do
|
301
|
+
revoke_permission = PristinePermission.new(:privilege_set_name => "chat", :pristine_role => @context_role, :operation => '-')
|
302
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => revoke_permission.privilege_set_name, :pristine_role => revoke_permission.pristine_role, :operation => '+'))
|
303
|
+
@pristine_file.permissions.push(revoke_permission)
|
304
|
+
|
305
|
+
@pristine_file.permission_set.should_not include(revoke_permission)
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should contain the permission if it is re-applied" do
|
309
|
+
re_applied_permission = PristinePermission.new(:privilege_set_name => "chat", :pristine_role => @context_role, :operation => '+')
|
310
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => re_applied_permission.privilege_set_name, :pristine_role => re_applied_permission.pristine_role, :operation => '+'))
|
311
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => re_applied_permission.privilege_set_name, :pristine_role => re_applied_permission.pristine_role, :operation => '-'))
|
312
|
+
@pristine_file.permissions.push(re_applied_permission)
|
313
|
+
|
314
|
+
@pristine_file.permission_set.should include(re_applied_permission)
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should raise an error if a permission is revoked which wasn't created before" do
|
318
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => "chat", :pristine_role => @context_role, :operation => '+'))
|
319
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => "login", :pristine_role => @context_role, :operation => '+'))
|
320
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => "blog_read", :pristine_role => @context_role, :operation => '-'))
|
321
|
+
@pristine_file.permissions.push(PristinePermission.new(:privilege_set_name => "update_blog", :pristine_role => @context_role, :operation => '+'))
|
322
|
+
|
323
|
+
proc {
|
324
|
+
@pristine_file.permission_set
|
325
|
+
}.should raise_error(ArgumentError)
|
326
|
+
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|