cbac 0.3.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 (45) hide show
  1. data/Manifest +44 -0
  2. data/README.rdoc +48 -0
  3. data/Rakefile +36 -0
  4. data/cbac.gemspec +31 -0
  5. data/generators/cbac/USAGE +34 -0
  6. data/generators/cbac/cbac_generator.rb +45 -0
  7. data/generators/cbac/templates/config/context_roles.rb +10 -0
  8. data/generators/cbac/templates/config/privileges.rb +30 -0
  9. data/generators/cbac/templates/controllers/generic_roles_controller.rb +30 -0
  10. data/generators/cbac/templates/controllers/memberships_controller.rb +22 -0
  11. data/generators/cbac/templates/controllers/permissions_controller.rb +42 -0
  12. data/generators/cbac/templates/fixtures/cbac_generic_roles.yml +9 -0
  13. data/generators/cbac/templates/fixtures/cbac_memberships.yml +8 -0
  14. data/generators/cbac/templates/fixtures/cbac_permissions.yml +8 -0
  15. data/generators/cbac/templates/migrate/create_cbac.rb +40 -0
  16. data/generators/cbac/templates/stylesheets/cbac.css +65 -0
  17. data/generators/cbac/templates/views/generic_roles/index.html.erb +59 -0
  18. data/generators/cbac/templates/views/layouts/cbac.html.erb +17 -0
  19. data/generators/cbac/templates/views/memberships/_update.html.erb +12 -0
  20. data/generators/cbac/templates/views/memberships/index.html.erb +22 -0
  21. data/generators/cbac/templates/views/permissions/_update_context_role.html.erb +12 -0
  22. data/generators/cbac/templates/views/permissions/_update_generic_role.html.erb +12 -0
  23. data/generators/cbac/templates/views/permissions/index.html.erb +31 -0
  24. data/init.rb +11 -0
  25. data/lib/cbac.rb +104 -0
  26. data/lib/cbac/config.rb +10 -0
  27. data/lib/cbac/context_role.rb +27 -0
  28. data/lib/cbac/generic_role.rb +6 -0
  29. data/lib/cbac/membership.rb +4 -0
  30. data/lib/cbac/permission.rb +6 -0
  31. data/lib/cbac/privilege.rb +72 -0
  32. data/lib/cbac/privilege_set.rb +28 -0
  33. data/lib/cbac/privilege_set_record.rb +5 -0
  34. data/lib/cbac/setup.rb +31 -0
  35. data/tasks/cbac.rake +19 -0
  36. data/test/fixtures/cbac_generic_roles.yml +9 -0
  37. data/test/fixtures/cbac_memberships.yml +8 -0
  38. data/test/fixtures/cbac_permissions.yml +15 -0
  39. data/test/fixtures/cbac_privilege_set.yml +18 -0
  40. data/test/test_cbac_authorize_context_roles.rb +43 -0
  41. data/test/test_cbac_authorize_generic_roles.rb +37 -0
  42. data/test/test_cbac_context_role.rb +51 -0
  43. data/test/test_cbac_privilege.rb +99 -0
  44. data/test/test_cbac_privilege_set.rb +52 -0
  45. metadata +118 -0
@@ -0,0 +1,65 @@
1
+ /****
2
+ * General
3
+ */
4
+
5
+ div.cbac h1 {
6
+
7
+ }
8
+
9
+ div.cbac table {
10
+ padding: 0px;
11
+ margin: 0px;
12
+ border-collapse: collapse;
13
+ }
14
+
15
+ div.cbac div.linebreak {
16
+ height: 20px;
17
+ }
18
+
19
+ /****
20
+ * Table
21
+ */
22
+
23
+ div.cbac th {
24
+ background-color: #ABEB71;
25
+ }
26
+
27
+ div.cbac td, div.cbac th {
28
+ border: 1px solid black;
29
+ }
30
+
31
+ div.cbac td.small, div.cbac th.small {
32
+ width: 50px;
33
+ }
34
+
35
+ div.cbac td.medium, div.cbac th.medium {
36
+ width: 150px;
37
+ }
38
+
39
+ div.cbac td.large, div.cbac th.large {
40
+ width: 600px;
41
+ }
42
+
43
+ div.cbac td.checked {
44
+ text-align: center;
45
+ }
46
+
47
+ div.cbac td.submit {
48
+ text-align: right;
49
+ }
50
+
51
+ /****
52
+ * Controls
53
+ */
54
+
55
+ div.cbac input[type="text"] {
56
+ margin: 2px;
57
+ }
58
+
59
+ div.cbac td.medium input[type="text"] {
60
+ width: 138px;
61
+ }
62
+
63
+ div.cbac td.large input[type="text"] {
64
+ width: 588px;
65
+ }
@@ -0,0 +1,59 @@
1
+ <div class="cbac">
2
+ <h1>Generic roles</h1>
3
+ <table>
4
+ <tr>
5
+ <th class="medium">Name</th>
6
+ <th class="large">Remarks</th>
7
+ <th class="small">&nbsp;</th>
8
+ </tr>
9
+
10
+ <% Cbac::GenericRole.find(:all).each do |role| %>
11
+ <tr class="row">
12
+ <% form_for role do |r| %>
13
+ <td class="medium"><%= r.text_field :name %></td>
14
+ <td class="large"><%= r.text_field :remarks, :rows => 1 %></td>
15
+ <td class="small"><%= r.submit "OK" %></td>
16
+ <% end %>
17
+ </tr>
18
+ <% end%>
19
+ </table>
20
+
21
+ <div class="linebreak"></div>
22
+
23
+ <table>
24
+ <% form_for(Cbac::GenericRole.new) do |new_role| %>
25
+ <tr class="row">
26
+ <th colspan="2">New generic role</th>
27
+ </tr>
28
+ <tr class="row">
29
+ <td class="medium">Name</td>
30
+ <td class="medium"><%= new_role.text_field :name %></td>
31
+ </tr>
32
+ <tr class="row">
33
+ <td class="medium">Remarks</td>
34
+ <td class="large"><%= new_role.text_field :remarks %></td>
35
+ </tr>
36
+ <tr class="row">
37
+ <td colspan="2" class="submit"><%= new_role.submit "Create" %></td>
38
+ </tr>
39
+ <% end %>
40
+ </table>
41
+
42
+ <div class="linebreak"></div>
43
+
44
+ <table>
45
+ <% form_tag(:controller => "cbac/generic_roles", :action => "delete") do |f| %>
46
+ <tr>
47
+ <th colspan="2">Delete generic role</th>
48
+ </tr>
49
+ <tr>
50
+ <td class="medium">Select role</td>
51
+ <td class="medium"><%= select_tag "id", Cbac::GenericRole.find(:all).collect{|role|"<option value='#{role.id}'>#{role.name}</option>"} %>
52
+ </td>
53
+ </tr>
54
+ <tr>
55
+ <td colspan="2" class="submit"><%= submit_tag "Delete" %></td>
56
+ </tr>
57
+ <% end %>
58
+ </table>
59
+ </div>
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
7
+ <title>Context Based Access Control</title>
8
+ <%= javascript_include_tag :defaults %>
9
+ <%= stylesheet_link_tag "cbac" %>
10
+ </head>
11
+ <body>
12
+ <%= link_to "Permissions", cbac_permissions_path %>
13
+ <%= link_to "Generic roles", cbac_generic_roles_path %>
14
+ <%= link_to "Memberships", cbac_memberships_path %>
15
+ <%= yield %>
16
+ </body>
17
+ </html>
@@ -0,0 +1,12 @@
1
+ <% update_name = generic_role.id.to_s + "__" + user_id.to_s %>
2
+ <% unless update_partial %><div id="<%= update_name %>"><% end %>
3
+ <% remote_form_for "/cbac/memberships/update", :url => {:controller => "cbac/memberships", :action => "update"},
4
+ :update => update_name, :before => "$('#{update_name}').style.visibility = 'hidden';",
5
+ :complete => "$('#{update_name}').style.visibility = 'visible';" do %>
6
+ <%= hidden_field_tag "generic_role_id" + update_name, generic_role.id.to_s, :name => "generic_role_id" %>
7
+ <%= hidden_field_tag "user_id" + update_name, user_id.to_s, :name => "user_id" %>
8
+ <%= check_box_tag "member" + update_name, "1",
9
+ (Cbac::Membership.find(:all, :conditions => ["generic_role_id = ? AND user_id = ?", generic_role.id.to_s, user_id.to_s]).length > 0),
10
+ {:onclick => "this.form.onsubmit();", :name => "member"}%>
11
+ <% end %>
12
+ <% unless update_partial %></div><% end %>
@@ -0,0 +1,22 @@
1
+ <div class="cbac">
2
+ <h1>Memberships</h1>
3
+ <table>
4
+ <tr>
5
+ <th class="medium">Users</th>
6
+ <% @generic_roles.each do |role| %>
7
+ <th><%= role.name %></th>
8
+ <% end %>
9
+ </tr>
10
+ <% @users.each do |u| %>
11
+ <tr>
12
+ <td><%= u.name %></td>
13
+ <% @generic_roles.each do |generic_role| %>
14
+ <td class="checked">
15
+ <%= render :partial => "cbac/memberships/update.html", :locals => {:generic_role => generic_role,
16
+ :user_id => u.id.to_s,:update_partial => false} %>
17
+ </td>
18
+ <% end %>
19
+ </tr>
20
+ <% end %>
21
+ </table>
22
+ </div>
@@ -0,0 +1,12 @@
1
+ <% update_name = "cr__" + context_role.to_s + "__" + set_id.to_s %>
2
+ <% unless update_partial %><div id="<%= update_name %>"><% end %>
3
+ <% remote_form_for "/cbac/permissions/update", :url => cbac_permissions_update_path,
4
+ :update => update_name, :before => "$('#{update_name}').style.visibility = 'hidden';",
5
+ :complete => "$('#{update_name}').style.visibility = 'visible';" do %>
6
+ <%= hidden_field_tag "context_role" + update_name, context_role.to_s, :name => "context_role" %>
7
+ <%= hidden_field_tag "privilege_set_id" + update_name, set_id.to_s, :name => "privilege_set_id" %>
8
+ <%= check_box_tag "permission" + update_name, "1",
9
+ (Cbac::Permission.find(:all, :conditions => ["context_role = ? AND privilege_set_id = ?", context_role.to_s, set_id.to_s]).length > 0),
10
+ {:onclick => "this.form.onsubmit();", :name => "permission"}%>
11
+ <% end %>
12
+ <% unless update_partial %></div><% end %>
@@ -0,0 +1,12 @@
1
+ <% update_name = "gr__" + role.id.to_s + "__" + set_id.to_s %>
2
+ <% unless update_partial %><div id="<%= update_name %>"><% end %>
3
+ <% remote_form_for "/cbac/permissions/update", :url => cbac_permissions_update_path,
4
+ :update => update_name, :before => "$('#{update_name}').style.visibility = 'hidden';",
5
+ :complete => "$('#{update_name}').style.visibility = 'visible';" do %>
6
+ <%= hidden_field_tag "generic_role_id" + update_name, role.id.to_s, :name => "generic_role_id" %>
7
+ <%= hidden_field_tag "privilege_set_id" + update_name, set_id.to_s, :name => "privilege_set_id" %>
8
+ <%= check_box_tag "permission" + update_name, "1",
9
+ (Cbac::Permission.find(:all, :conditions => ["generic_role_id = ? AND privilege_set_id = ?", role.id.to_s, set_id.to_s]).length > 0),
10
+ {:onclick => "this.form.onsubmit();", :name => "permission"}%>
11
+ <% end %>
12
+ <% unless update_partial %></div><% end %>
@@ -0,0 +1,31 @@
1
+ <div class="cbac">
2
+ <h1>Permissions</h1>
3
+ <table>
4
+ <tr>
5
+ <th>Privilegeset</th>
6
+ <% @context_roles.each do |name, comment| %>
7
+ <th><%= name %></th>
8
+ <% end %>
9
+ <% @generic_roles.each do |role| %>
10
+ <th><%= role.name %></th>
11
+ <% end %>
12
+ </tr>
13
+ <% PrivilegeSet.sets.each do |token, set| %>
14
+ <tr>
15
+ <td><%= set.name %></td>
16
+ <% @context_roles.each do |context_role, comment| %>
17
+ <td class="checked">
18
+ <%= render :partial => "cbac/permissions/update_context_role.html", :locals => {:context_role => context_role.to_s,
19
+ :set_id => set.id.to_s, :update_partial => false} %>
20
+ </td>
21
+ <% end %>
22
+ <% @generic_roles.each do |role| %>
23
+ <td class="checked">
24
+ <%= render :partial => "cbac/permissions/update_generic_role.html", :locals => {:role => role,
25
+ :set_id => set.id.to_s, :update_partial => false} %>
26
+ </td>
27
+ <% end %>
28
+ </tr>
29
+ <% end %>
30
+ </table>
31
+ </div>
data/init.rb ADDED
@@ -0,0 +1,11 @@
1
+ # Configuration file
2
+ require File.dirname(__FILE__) + '/lib/cbac/config.rb'
3
+
4
+ # The following code contains configuration options. You can turn them on for
5
+ # gem development. For actual usage, it is advisable to set the configuration
6
+ # options in the environment files.
7
+ Cbac::Config.verbose = false
8
+
9
+ # Include CBAC core file
10
+ require File.dirname(__FILE__) + '/lib/cbac.rb'
11
+
@@ -0,0 +1,104 @@
1
+ # TODO: Check the permission table for double entries, ie: both an entry in the
2
+ # generic_role_id field and an entry in the context_role field. Solution: solve
3
+ # via model. Update model & add test
4
+
5
+
6
+ module Cbac
7
+ if Cbac::Setup.check
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'
13
+
14
+ # check performs a check to see if the user is allowed to access the given
15
+ # resource. Example: authorization_check("BlogController", "index", :get)
16
+ def authorization_check(controller, action, request, context = {})
17
+ # Determine the controller to look for
18
+ controller_method = [controller, action].join("/")
19
+ # Get the privilegesets
20
+ privilege_sets = Privilege.select(controller_method, request)
21
+ # Check the privilege sets
22
+ check_privilege_sets(privilege_sets, context)
23
+ end
24
+
25
+ # Check the given privilege_set symbol
26
+ # TODO following code is not yet tested
27
+ def check_privilege_set(privilege_set, context = {})
28
+ check_privilege_sets([PrivilegeSet.sets[privilege_set.to_sym]], context)
29
+ end
30
+
31
+ # Check the given privilege_sets
32
+ def check_privilege_sets(privilege_sets, context = {})
33
+ # 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 }
35
+ # Check the context roles Get the permissions
36
+ 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
38
+ eval_string = ContextRole.roles[permission.context_role.to_sym]
39
+ # Not sure if this will work everywhere
40
+ return true if eval_string.call(context)
41
+ end
42
+ # not authorized
43
+ puts "Not authorized for: #{controller_method}" if Cbac::Config.verbose
44
+ false
45
+ end
46
+
47
+ # Code that performs authorization
48
+ def authorize
49
+ authorization_check(params[:controller], params[:action], request.request_method) || unauthorized
50
+ end
51
+
52
+ # Default unauthorized method Override this method to supply your own code
53
+ # for incorrect authorization
54
+ def unauthorized
55
+ render :text => "You are not authorized to perform this action", :status => 401
56
+ end
57
+
58
+ # Default implementation of the current_user method
59
+ def current_user
60
+ session[:currentuser].to_i
61
+ end
62
+
63
+ # Load controller classes and methods
64
+ def load_controller_methods
65
+ begin
66
+ Dir.glob("app/controllers/**/*.rb").each{|file| require file}
67
+ rescue LoadError
68
+ raise "Could not load controller classes"
69
+ end
70
+ # Make this iterative TODO
71
+ @classes = ApplicationController.subclasses
72
+ end
73
+
74
+ # Extracts the class name from the filename
75
+ def extract_class_name(filename)
76
+ File.basename(filename).chomp(".rb").camelize
77
+ end
78
+
79
+ # ### Initializer Include privileges file - contains the privilege and
80
+ # privilege definitions
81
+ begin
82
+ require File.join(RAILS_ROOT, "config", "privileges.rb")
83
+ rescue MissingSourceFile
84
+ puts "CBAC warning: Could not load config/privileges.rb (Did you run ./script/generate cbac)"
85
+ end
86
+ # Include context roles file - contains the context role definitions
87
+ begin
88
+ require File.join(RAILS_ROOT, "config", "context_roles.rb")
89
+ rescue MissingSourceFile
90
+ puts "CBAC warning: Could not load config/context_roles.rb (Did you run ./script/generate cbac)"
91
+ end
92
+
93
+ # ### Database autoload code
94
+ else
95
+ # This is the code that is executed if CBAc is not properly installed/
96
+ # configured. It includes a different authorize method, aimes at refusing
97
+ # all authorizations
98
+ def authorize
99
+ render :text => "Authorization error", :status => 401
100
+ false
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,10 @@
1
+ module Cbac
2
+ # Class containing configuration options for the Cbac system. The following
3
+ # configuration options are supported: verbose. Determines whether or not to
4
+ # output results to the console. All outputs are processed as puts commands.
5
+ class Config
6
+ class << self
7
+ attr_accessor :verbose
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # ContextRole is the class containing the context role definitions
2
+ #
3
+ # Usage: ContextRole.add :logged_in_user, "!session[:currentuser].nil?"
4
+ class ContextRole
5
+ class << self
6
+ # Hash containing all the context roles. Keys are the role names Values are
7
+ # the Ruby eval strings Eval strings must result in true or false
8
+ attr_reader :roles
9
+
10
+ # Adds a context role to the list of context roles. @symbol defines the name
11
+ # of the context role @context_rule defines the ruby code to be evaluated
12
+ # when determining role membership
13
+ #
14
+ # If the context role already exists, an exception is thrown.
15
+ def add(symbol, context_rule = "", &block)
16
+ symbol = symbol.to_sym
17
+ @roles = Hash.new if @roles.nil?
18
+ raise ArgumentError, "CBAC: ContextRole was already defined" if @roles.keys.include?(symbol)
19
+ # TODO following code
20
+ #raise ArgumentError, "CBAC: cannot specify both string rule and block rule" unless context_rule.nil? and block.nil?
21
+ # TODO context parameter in block statement is not explicitly tested
22
+ block = eval("Proc.new {|context| " + context_rule + "}") if block.nil?
23
+ @roles[symbol] = block
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,6 @@
1
+ class Cbac::GenericRole < ActiveRecord::Base
2
+ set_table_name "cbac_generic_roles"
3
+
4
+ has_many :generic_role_members, :class_name => "Cbac::Membership", :foreign_key => "generic_role_id"
5
+ has_many :permissions, :class_name => "Cbac::Permission", :foreign_key => "generic_role_id"
6
+ end
@@ -0,0 +1,4 @@
1
+ class Cbac::Membership < ActiveRecord::Base
2
+ set_table_name "cbac_memberships"
3
+ belongs_to :generic_role, :class_name => "Cbac::GenericRole", :foreign_key => "generic_role_id"
4
+ end
@@ -0,0 +1,6 @@
1
+ class Cbac::Permission < ActiveRecord::Base
2
+ set_table_name "cbac_permissions"
3
+
4
+ belongs_to :generic_role, :class_name => "Cbac::GenericRole", :foreign_key => "generic_role_id"
5
+ belongs_to :privilegeset, :class_name => "Cbac::PrivilegeSetRecord", :foreign_key => "privilege_set_id"
6
+ end
@@ -0,0 +1,72 @@
1
+ # Class containing all the privileges
2
+ #
3
+ # To define a new controller method resource: Privilege.resource :privilegeset,
4
+ # "controller/method"
5
+ #
6
+ class Privilege
7
+ class << self
8
+ attr_reader :get_resources, :post_resources, :model_attributes, :models
9
+
10
+ # Links a resource with a PrivilegeSet
11
+ #
12
+ # An ArgumentError exception is thrown if the PrivilegeSet does not exist.
13
+ # To create PrivilegeSets, use the PrivilegeSet.add method
14
+ def resource(privilege_set, method, action="GET")
15
+ privilege_set = privilege_set.to_sym
16
+ @get_resources = Hash.new if @get_resources.nil?
17
+ @post_resources = Hash.new if @post_resources.nil?
18
+ action_aliases = {"GET" => ["GET", "get", "g","idempotent"], "POST" => ["POST", "post", "p"]}
19
+ raise ArgumentError, "CBAC: PrivilegeSet does not exist: #{privilege_set}" unless PrivilegeSet.sets.include?(privilege_set)
20
+ action_option = action_aliases.find { |name, aliases| aliases.include?(action.to_s) }
21
+ raise ArgumentError, "CBAC: Wrong value for argument 'action' in Privilege.resource: #{action}" if action_option.nil?
22
+ case action_option[0]
23
+ when "GET"
24
+ (@get_resources[method] ||= Array.new) << PrivilegeSet.sets[privilege_set]
25
+ when "POST"
26
+ (@post_resources[method] ||= Array.new) << PrivilegeSet.sets[privilege_set]
27
+ else
28
+ end
29
+ end
30
+
31
+ def model_attribute
32
+
33
+ end
34
+ def model
35
+
36
+ end
37
+
38
+ # Finds the privilege sets associated with the given controller_method and
39
+ # action_type Valid values for action_type are "get", "post" and "put".
40
+ # "put" is converted into "post".
41
+ #
42
+ # If incorrect values are given for action_type the method will raise an
43
+ # ArgumentError. If the controller and action name are not found, an
44
+ # exception is being raised.
45
+ def select(controller_method, action_type)
46
+ action_type = action_type.to_s
47
+ post_methods = ["post", "put", "delete"]
48
+ if action_type == "get"
49
+ privilege_sets = Privilege.get_resources[controller_method]
50
+ else if post_methods.include?(action_type)
51
+ privilege_sets = Privilege.post_resources[controller_method]
52
+ else
53
+ raise ArgumentError, "CBAC: Incorrect action_type: #{action_type}"
54
+ end
55
+ end
56
+ # Error handling if no privilege_sets were found
57
+ if privilege_sets.nil?
58
+ if action_type == "get"
59
+ if !Privilege.post_resources[controller_method].nil?
60
+ raise "CBAC: PrivilegeSets only exist for other action: post on method: #{controller_method}"
61
+ end
62
+ else
63
+ if !Privilege.get_resources[controller_method].nil?
64
+ raise "CBAC: PrivilegeSets only exist for other action: get on method: #{controller_method}"
65
+ end
66
+ end
67
+ raise "CBAC: Could not find any privilege sets associated with: #{controller_method} and action: #{action_type}"
68
+ end
69
+ privilege_sets
70
+ end
71
+ end
72
+ end