cbac 0.3.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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