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.
Files changed (35) hide show
  1. data/Manifest +60 -44
  2. data/Rakefile +2 -2
  3. data/cbac.gemspec +31 -31
  4. data/generators/cbac/cbac_generator.rb +27 -6
  5. data/generators/cbac/templates/config/cbac.pristine +2 -0
  6. data/generators/cbac/templates/controllers/permissions_controller.rb +21 -2
  7. data/generators/cbac/templates/controllers/upgrade_controller.rb +24 -0
  8. data/generators/cbac/templates/fixtures/cbac_memberships.yml +1 -1
  9. data/generators/cbac/templates/migrate/create_cbac_from_scratch.rb +59 -0
  10. data/generators/cbac/templates/migrate/create_cbac_upgrade_path.rb +31 -0
  11. data/generators/cbac/templates/tasks/cbac.rake +345 -0
  12. data/generators/cbac/templates/views/layouts/cbac.html.erb +2 -1
  13. data/generators/cbac/templates/views/memberships/index.html.erb +1 -1
  14. data/generators/cbac/templates/views/permissions/index.html.erb +14 -6
  15. data/generators/cbac/templates/views/upgrade/index.html.erb +32 -0
  16. data/lib/cbac.rb +23 -12
  17. data/lib/cbac/cbac_pristine/pristine.rb +133 -0
  18. data/lib/cbac/cbac_pristine/pristine_file.rb +158 -0
  19. data/lib/cbac/cbac_pristine/pristine_permission.rb +194 -0
  20. data/lib/cbac/cbac_pristine/pristine_role.rb +42 -0
  21. data/lib/cbac/known_permission.rb +14 -0
  22. data/lib/cbac/permission.rb +1 -1
  23. data/lib/cbac/privilege.rb +44 -0
  24. data/lib/cbac/privilege_set.rb +5 -4
  25. data/lib/cbac/privilege_set_record.rb +3 -1
  26. data/spec/cbac_pristine_file_spec.rb +329 -0
  27. data/spec/cbac_pristine_permission_spec.rb +358 -0
  28. data/spec/cbac_pristine_role_spec.rb +85 -0
  29. data/spec/rcov.opts +2 -0
  30. data/spec/spec.opts +4 -0
  31. data/spec/spec_helper.rb +12 -0
  32. data/tasks/cbac.rake +345 -19
  33. data/test/test_cbac_privilege.rb +54 -0
  34. metadata +43 -9
  35. data/generators/cbac/templates/migrate/create_cbac.rb +0 -40
@@ -12,6 +12,7 @@
12
12
  <%= link_to "Permissions", cbac_permissions_path %>
13
13
  <%= link_to "Generic roles", cbac_generic_roles_path %>
14
14
  <%= link_to "Memberships", cbac_memberships_path %>
15
+ <%= link_to "Upgrade", cbac_upgrade_path %>
15
16
  <%= yield %>
16
17
  </body>
17
- </html>
18
+ </html>
@@ -7,7 +7,7 @@
7
7
  <th><%= role.name %></th>
8
8
  <% end %>
9
9
  </tr>
10
- <% @users.each do |u| %>
10
+ <% (@users.sort do |x,y| x.name.downcase <=> y.name.downcase end).each do |u| %>
11
11
  <tr>
12
12
  <td><%= u.name %></td>
13
13
  <% @generic_roles.each do |generic_role| %>
@@ -1,25 +1,33 @@
1
1
  <div class="cbac">
2
+
3
+ <h2>Subset:</h2>
4
+ <form action="<%= request.request_uri %>" method="get" name="subset_view_form">
5
+ <b>Privilege set</b> starts with: <input type="text" name="priv_substr" value="<%= params[:priv_substr] %>" /><br />
6
+ <b>Role</b> starts with: <input type="text" name="role_substr" value="<%= params[:role_substr] %>" /><br/>
7
+ <input type="submit" value="Submit" />
8
+ </form>
9
+
2
10
  <h1>Permissions</h1>
3
11
  <table>
4
12
  <tr>
5
13
  <th>Privilegeset</th>
6
- <% @context_roles.each do |name, comment| %>
14
+ <% (@context_roles.sort { |x, y| x[0].to_s <=> y[0].to_s }).each do |name, comment| %>
7
15
  <th><%= name %></th>
8
16
  <% end %>
9
- <% @generic_roles.each do |role| %>
17
+ <% (@generic_roles.sort { |x, y| x.name <=> y.name }).each do |role| %>
10
18
  <th><%= role.name %></th>
11
19
  <% end %>
12
20
  </tr>
13
- <% PrivilegeSet.sets.each do |token, set| %>
21
+ <% (@sets.sort do |x,y| x[0].to_s <=> y[0].to_s end).each do |token, set| %>
14
22
  <tr>
15
- <td><%= set.name %></td>
16
- <% @context_roles.each do |context_role, comment| %>
23
+ <td><span title ="<%= set.comment %>"><%= set.name %></span></td>
24
+ <% (@context_roles.sort { |x, y| x[0].to_s <=> y[0].to_s }).each do |context_role, comment| %>
17
25
  <td class="checked">
18
26
  <%= render :partial => "cbac/permissions/update_context_role.html", :locals => {:context_role => context_role.to_s,
19
27
  :set_id => set.id.to_s, :update_partial => false} %>
20
28
  </td>
21
29
  <% end %>
22
- <% @generic_roles.each do |role| %>
30
+ <% (@generic_roles.sort { |x, y| x.name <=> y.name }).each do |role| %>
23
31
  <td class="checked">
24
32
  <%= render :partial => "cbac/permissions/update_generic_role.html", :locals => {:role => role,
25
33
  :set_id => set.id.to_s, :update_partial => false} %>
@@ -0,0 +1,32 @@
1
+ <div class="cbac">
2
+ <h1>Permissions: available upgrades</h1>
3
+ <span>Choose which of these available permissions you want to accept or reject.
4
+ Each upgrade either adds a new permission or revokes an existing permission.
5
+ You can also leave the available upgrade for another time.</span><br/><br/>
6
+ <% form_tag cbac_upgrade_update_path do %>
7
+ <table>
8
+ <tr>
9
+ <th class="medium">Add /revoke</th>
10
+ <th class="large">Privilegeset</th>
11
+ <th class="medium">Roletype</th>
12
+ <th class="medium">Role</th>
13
+ <th class="small">Accept</th>
14
+ <th class="small">Reject</th>
15
+ <th class="small">Leave</th>
16
+ </tr>
17
+ <% @permissions.each_with_index do |permission, index| %>
18
+ <tr>
19
+ <td><span><%=permission.operation_string.capitalize%></span><input type="hidden" name="permissions[<%=index.to_s%>][id]" value="<%=permission.id.to_s%>"/></td>
20
+ <td><span title='<%=permission.privilege_set.comment%>'><%=permission.privilege_set_name%></span></td>
21
+ <td><span><%=permission.pristine_role.role_type%></span></td>
22
+ <td><span><%=permission.pristine_role.name%></span></td>
23
+ <td><input type="radio" name="permissions[<%=index.to_s%>][action]" value="accept"/></td>
24
+ <td><input type="radio" name="permissions[<%=index.to_s%>][action]" value="reject"/></td>
25
+ <td><input type="radio" name="permissions[<%=index.to_s%>][action]" value="leave" checked="checked"/></td>
26
+ </tr>
27
+ <% end %>
28
+ </table>
29
+ <input type="button" value="Cancel" onclick="window.location.reload();"/>
30
+ <input type="submit" value="OK"/>
31
+ <% end %>
32
+ </div>
data/lib/cbac.rb CHANGED
@@ -6,10 +6,13 @@
6
6
  module Cbac
7
7
  if Cbac::Setup.check
8
8
  puts "CBAC properly installed"
9
-
10
- require File.dirname(__FILE__) + '/cbac/privilege.rb'
11
- require File.dirname(__FILE__) + '/cbac/privilege_set.rb'
12
- require File.dirname(__FILE__) + '/cbac/context_role.rb'
9
+
10
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/privilege'))
11
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/privilege_set'))
12
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/context_role'))
13
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/cbac_pristine/pristine'))
14
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/cbac_pristine/pristine_file'))
15
+ require File.expand_path(File.join(File.dirname(__FILE__), '/cbac/cbac_pristine/pristine_permission'))
13
16
 
14
17
  # check performs a check to see if the user is allowed to access the given
15
18
  # resource. Example: authorization_check("BlogController", "index", :get)
@@ -31,13 +34,21 @@ module Cbac
31
34
  # Check the given privilege_sets
32
35
  def check_privilege_sets(privilege_sets, context = {})
33
36
  # Check the generic roles
34
- return true if privilege_sets.any? { |set| Cbac::GenericRole.find(:all, :conditions => ["user_id= ? AND privilege_set_id = ?", current_user, set.id],:joins => [:generic_role_members, :permissions]).length > 0 }
37
+ return true if privilege_sets.any? { |set| Cbac::GenericRole.find(:all, :conditions => ["user_id= ? AND privilege_set_id = ?", current_user_id, set.id],:joins => [:generic_role_members, :permissions]).length > 0 }
35
38
  # Check the context roles Get the permissions
36
39
  privilege_sets.collect{|privilege_set|Cbac::Permission.find(:all, :conditions => ["privilege_set_id = ? AND generic_role_id = 0", privilege_set.id.to_s])}.flatten.each do |permission|
37
- puts "Checking for context_role:#{permission.context_role} on privilege_set:#{permission.privilegeset.name}" if Cbac::Config.verbose
40
+ puts "Checking for context_role:#{permission.context_role} on privilege_set:#{permission.privilege_set.name}" if Cbac::Config.verbose
38
41
  eval_string = ContextRole.roles[permission.context_role.to_sym]
39
42
  # Not sure if this will work everywhere
40
- return true if eval_string.call(context)
43
+ # TODO: sort this out
44
+ context[:session] = session
45
+ context["session"] = session
46
+ begin
47
+ return true if eval_string.call(context)
48
+ rescue Exception => e
49
+ puts "Error in context role: #{permission.context_role} on privilege_set: #{permission.privilege_set.name}. Context: #{context}"
50
+ raise e if RAILS_ENV == "development" or RAILS_ENV == "test" # In development mode, this should crash as hard as possible, but in further stages, it should not
51
+ end
41
52
  end
42
53
  # not authorized
43
54
  puts "Not authorized for: #{controller_method}" if Cbac::Config.verbose
@@ -56,7 +67,7 @@ module Cbac
56
67
  end
57
68
 
58
69
  # Default implementation of the current_user method
59
- def current_user
70
+ def current_user_id
60
71
  session[:currentuser].to_i
61
72
  end
62
73
 
@@ -79,15 +90,15 @@ module Cbac
79
90
  # ### Initializer Include privileges file - contains the privilege and
80
91
  # privilege definitions
81
92
  begin
82
- require File.join(RAILS_ROOT, "config", "privileges.rb")
93
+ require File.join(RAILS_ROOT, "config", "cbac", "privileges.rb")
83
94
  rescue MissingSourceFile
84
- puts "CBAC warning: Could not load config/privileges.rb (Did you run ./script/generate cbac)"
95
+ puts "CBAC warning: Could not load config/cbac/privileges.rb (Did you run ./script/generate cbac?)"
85
96
  end
86
97
  # Include context roles file - contains the context role definitions
87
98
  begin
88
- require File.join(RAILS_ROOT, "config", "context_roles.rb")
99
+ require File.join(RAILS_ROOT, "config", "cbac", "context_roles.rb")
89
100
  rescue MissingSourceFile
90
- puts "CBAC warning: Could not load config/context_roles.rb (Did you run ./script/generate cbac)"
101
+ puts "CBAC warning: Could not load config/cbac/context_roles.rb (Did you run ./script/generate cbac?)"
91
102
  end
92
103
 
93
104
  # ### Database autoload code
@@ -0,0 +1,133 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'pristine_file'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'pristine_permission'))
3
+
4
+ module Cbac
5
+ module CbacPristine
6
+ #creates a yml file containing all generic roles from the specified pristine file objects
7
+ def create_generic_role_fixtures_file(pristine_files, fixtures_file_name)
8
+ roles = []
9
+
10
+ pristine_files.each do |pristine_file|
11
+ #if the pristine file wasn't parsed yet, we'll do it here
12
+ pristine_file.parse(false) if pristine_file.permissions.empty?
13
+ pristine_file.generic_roles.each do |generic_role|
14
+ # we only want the unique generic roles, because the yml file cannot have duplicates
15
+ has_role = false
16
+ roles.each do |role|
17
+ if role.name == generic_role.name
18
+ has_role = true
19
+ end
20
+ end
21
+ roles.push(generic_role) unless has_role
22
+ end
23
+ end
24
+ create_fixtures_file(roles, fixtures_file_name)
25
+ end
26
+
27
+ # creates a yml file containing all cbac_permissions from the specified pristine file objects
28
+ def create_permissions_fixtures_file(pristine_files, fixtures_file_name)
29
+ permissions = []
30
+
31
+ pristine_files.each do |pristine_file|
32
+ pristine_file.parse(false) if pristine_file.permissions.empty?
33
+ pristine_file.permission_set.each do |line|
34
+ permissions.push(line)
35
+ end
36
+ end
37
+ create_fixtures_file(permissions, fixtures_file_name)
38
+ end
39
+
40
+ # turns the fixtures into yml and writes them to a file with specified name.
41
+ def create_fixtures_file(fixtures, fixtures_file_name)
42
+ File.delete(fixtures_file_name) if File.exists?(fixtures_file_name)
43
+ f = File.new(fixtures_file_name, "w")
44
+ flock(f, File::LOCK_EX) do |f|
45
+ fixtures.each_with_index do |fixture, index|
46
+ f.write(fixture.to_yml_fixture(index + 1))
47
+ end
48
+ end
49
+ end
50
+
51
+ # set all cbac permissions and generic roles to the state in the specified pristine file objects
52
+ def set_pristine_state(pristine_files, clear_tables)
53
+ clear_cbac_tables if clear_tables
54
+ pristine_files.each do |pristine_file|
55
+ pristine_file.parse if pristine_file.permissions.empty?
56
+ pristine_file.permissions.each do |permission|
57
+ permission.accept
58
+ end
59
+ end
60
+ end
61
+
62
+ # stage all unknown cbac_permissions
63
+ def stage_permissions(pristine_files)
64
+
65
+ pristine_files.each do |pristine_file|
66
+ pristine_file.parse(true) if pristine_file.permissions.empty?
67
+ pristine_file.permissions.each do |permission|
68
+ permission.stage
69
+ end
70
+ end
71
+ end
72
+
73
+ def clear_cbac_tables
74
+ Cbac::GenericRole.delete_all
75
+ Cbac::Membership.delete_all
76
+ Cbac::Permission.delete_all
77
+ Cbac::KnownPermission.delete_all
78
+ Cbac::CbacPristine::PristinePermission.delete_all
79
+ Cbac::CbacPristine::PristineRole.delete_all
80
+ end
81
+
82
+ def delete_generic_known_permissions
83
+ known_permissions = Cbac::KnownPermission.find(:all, :conditions => {:permission_type => Cbac::KnownPermission.PERMISSION_TYPES[:generic]})
84
+ known_permissions.each { |p| p.destroy }
85
+ end
86
+
87
+ def delete_generic_permissions
88
+ permissions = Cbac::Permission.find(:all, :conditions => {:context_role => nil})
89
+ (permissions.select { |perm| perm.generic_role.name != "administrators" }).each { |p| p.destroy }
90
+ end
91
+
92
+ def delete_non_generic_staged_permissions
93
+ PristinePermission.delete_non_generic_permissions
94
+ end
95
+
96
+ def delete_generic_staged_permissions
97
+ PristinePermission.delete_generic_permissions
98
+ end
99
+
100
+ def database_contains_cbac_data?
101
+ return (Cbac::GenericRole.count != 0 or Cbac::Membership.count != 0 or Cbac::Permission.count != 0 or Cbac::KnownPermission.count != 0 or Cbac::CbacPristine::PristinePermission.count != 0 or Cbac::CbacPristine::PristineRole.count != 0)
102
+ end
103
+
104
+ def create_generic_pristine_file(file_name)
105
+ GenericPristineFile.new(file_name)
106
+ end
107
+
108
+ def create_pristine_file(file_name)
109
+ PristineFile.new(file_name)
110
+ end
111
+
112
+ def number_of_generic_staged_permissions
113
+ PristinePermission.count_generic_permissions
114
+ end
115
+
116
+ def number_of_non_generic_staged_permissions
117
+ PristinePermission.count_non_generic_permissions
118
+ end
119
+
120
+ def flock(file, mode)
121
+ success = file.flock(mode)
122
+ if success
123
+ begin
124
+ yield file
125
+ ensure
126
+ file.flock(File::LOCK_UN)
127
+ end
128
+ end
129
+ return success
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,158 @@
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
+
4
+ module Cbac
5
+ module CbacPristine
6
+ class AbstractPristineFile
7
+ attr_accessor :file_name, :permissions, :generic_roles
8
+
9
+ def initialize(file_name)
10
+ @file_name = file_name
11
+ @generic_roles = []
12
+ @permissions = []
13
+ @admin_role = nil
14
+ end
15
+
16
+ def parse(use_db = true)
17
+ @permissions = Array.new
18
+
19
+ f = File.open(@file_name, "r")
20
+ last_row_number = -1
21
+ f.each_with_index do |l, line_number|
22
+ pristine_permission = PristinePermission.new
23
+ permission_line = l.chomp
24
+ # if this is not a line we can convert into a permission, go to next line (or fail.....)
25
+ next unless is_pristine_permission_line?(permission_line, line_number)
26
+
27
+ # check if the row numbers are constructed properly.
28
+ # this is needed for migration purposes, each permission should have an unique and persistent row number
29
+ header_match = permission_line.match(/^(\d+):([\+-x]|=>):\s*/)
30
+ pristine_permission.line_number = header_match.captures[0].to_i
31
+ if pristine_permission.line_number != last_row_number.succ
32
+ raise SyntaxError, "Error: row numbers in pristine file do not increase monotonously"
33
+ else
34
+ last_row_number = pristine_permission.line_number
35
+ end
36
+ pristine_permission.operation = header_match.captures[1]
37
+ # parse the role and privilege set name
38
+ pristine_permission.privilege_set_name = parse_privilege_set_name(permission_line, line_number)
39
+ pristine_permission.pristine_role = parse_role(permission_line, line_number, use_db)
40
+ # it's pristine, so changes should be treated as such
41
+ # if a permission was created and later revoked, we should remove the pristine line which was created before
42
+ case pristine_permission.operation
43
+ when '+'
44
+ @permissions.push(pristine_permission)
45
+ when '-'
46
+ permission_to_delete = nil
47
+ #check if this is actually a permission that can be revoked.
48
+ @permissions.each do |known_permission|
49
+ if known_permission.privilege_set_name == pristine_permission.privilege_set_name and known_permission.pristine_role.name == pristine_permission.pristine_role.name
50
+ permission_to_delete = known_permission
51
+ break
52
+ end
53
+ end
54
+ if permission_to_delete.nil?
55
+ raise SyntaxError, "Error: trying to remove a privilege set with \"#{permission_line}\" on line #{(line_number + 1).to_s}, but this privilege set wasn't created!"
56
+ else
57
+ @permissions.push(pristine_permission)
58
+ end
59
+ when 'x', '=>'
60
+ raise NotImplementedError, "Using an x or => in a pristine file is not implemented yet"
61
+ end
62
+ end
63
+ end
64
+
65
+ def is_pristine_permission_line?(line, line_number)
66
+ if line.match(/^\s*(\d+)\s*:\s*([\+-x]|=>)\s*:(\s*[A-Za-z]+\(\s*[A-Za-z_]*\s*\))+\s*\Z/) #looks like pristine line.....
67
+ return true
68
+ end
69
+ if line.match(/^\s*(#.*|\s*)$/) # line is whitespace or comment line
70
+ return false
71
+ end
72
+ raise SyntaxError, "Error: garbage found in input file on line #{(line_number + 1).to_s}" #line is rubbish
73
+ end
74
+
75
+ def parse_privilege_set_name(line, line_number)
76
+ if match_data= line.match(/^.*PrivilegeSet\(\s*([A-Za-z0-9_]+)\s*\)\s*/)
77
+ return match_data.captures[0]
78
+ end
79
+ raise SyntaxError, "Error: PrivilegeSet expected, but found: \"#{line}\" on line #{(line_number + 1).to_s}"
80
+ end
81
+
82
+ def parse_role(line, line_number, use_db = true)
83
+ raise NotImplementedError("Error: the AbstractPristineFile cannot parse roles, use a PristineFile or GenericPristineFile instead")
84
+ end
85
+
86
+ def permission_set
87
+ permission_set = Array.new(@permissions)
88
+ @permissions.each do |pristine_permission|
89
+ case pristine_permission.operation
90
+ when '+'
91
+ permission_set.push(pristine_permission)
92
+ when '-'
93
+ permission_to_delete = nil
94
+ #check if this is actually a permission that can be revoked.
95
+ permission_set.each do |known_permission|
96
+ if known_permission.privilege_set_name == pristine_permission.privilege_set_name and known_permission.pristine_role.name == pristine_permission.pristine_role.name and known_permission.operation == '+'
97
+ permission_to_delete = known_permission
98
+ break
99
+ end
100
+ end
101
+ if permission_to_delete.nil?
102
+ raise ArgumentError, "Error: trying to remove permission #{pristine_permission.privilege_set_name}\" for #{pristine_permission.pristine_role.name}, but this permission wasn't created!"
103
+ else
104
+ permission_set.delete(permission_to_delete)
105
+ permission_set.delete(pristine_permission)
106
+ end
107
+ when 'x', '=>'
108
+ raise NotImplementedError, "Using an x or => in a pristine file is not implemented yet"
109
+ end
110
+ end
111
+ permission_set
112
+ end
113
+
114
+ end
115
+
116
+
117
+ class PristineFile < Cbac::CbacPristine::AbstractPristineFile
118
+ def parse_role(line, line_number, use_db = true)
119
+ if line.match(/^.*Admin\(\)/)
120
+ return @admin_role unless @admin_role.nil?
121
+
122
+ @admin_role = PristineRole.admin_role(use_db)
123
+ @generic_roles.push(@admin_role)
124
+ return @admin_role
125
+ end
126
+ if context_role_name = line.match(/^.*ContextRole\(\s*([A-Za-z0-9_]+)\s*\)/)
127
+ # NOTE: the 0 for an ID is very important! In CBAC a context role permission MUST have 0 as generic_role_id
128
+ # if not, the context role is not found by CBAC and thus will not work
129
+ context_role = use_db ? PristineRole.first(:conditions => {:role_type => PristineRole.ROLE_TYPES[:context], :name => context_role_name.captures[0]}) : nil
130
+ context_role = PristineRole.new(:role_id => 0, :role_type => PristineRole.ROLE_TYPES[:context], :name => context_role_name.captures[0]) if context_role.nil?
131
+ return context_role
132
+ end
133
+ raise SyntaxError, "Error: ContextRole or Admin expected, but found: \"#{line}\" on line #{(line_number + 1).to_s}"
134
+ end
135
+
136
+
137
+ end
138
+
139
+ class GenericPristineFile < Cbac::CbacPristine::AbstractPristineFile
140
+ def parse_role(line, line_number, use_db = true)
141
+ # generic pristine files differ, because they create generic roles when needed
142
+ # but those generic roles should be re-used if one with that name already exists
143
+ if generic_role= line.match(/^.*GenericRole\(\s*([A-Za-z0-9_]+)\s*\)/)
144
+ @generic_roles.each do |generic_cbac_role|
145
+ if generic_cbac_role.name == generic_role.captures[0]
146
+ return generic_cbac_role
147
+ end
148
+ end
149
+ role = use_db ? PristineRole.first(:conditions => {:role_type => PristineRole.ROLE_TYPES[:generic], :name => generic_role.captures[0]}) : nil
150
+ role = PristineRole.new(:role_id => @generic_roles.length + 2, :role_type => PristineRole.ROLE_TYPES[:generic], :name => generic_role.captures[0]) if role.nil?
151
+ @generic_roles.push(role)
152
+ return role
153
+ end
154
+ raise SyntaxError, "Error: GenericRole expected, but found: \"#{line}\" on line #{(line_number + 1).to_s}"
155
+ end
156
+ end
157
+ end
158
+ end