adva_rbac 0.0.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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/NOTES +98 -0
  6. data/README.md +29 -0
  7. data/Rakefile +2 -0
  8. data/adva_rbac.gemspec +17 -0
  9. data/app/controllers/roles_controller.rb +28 -0
  10. data/app/helpers/roles_helper.rb +64 -0
  11. data/app/views/admin/sections/settings/_permissions.html.erb +16 -0
  12. data/app/views/roles/index.js.erb +3 -0
  13. data/config/initializers/base_controller.rb +4 -0
  14. data/config/initializers/rbac.rb +60 -0
  15. data/config/initializers/user.rb +80 -0
  16. data/db/migrate/20080402000006_create_role_tables.rb +13 -0
  17. data/db/migrate/20090720132900_migrate_roles_table_to_new_rbac.rb +15 -0
  18. data/lib/action_controller/guards_permissions.rb +77 -0
  19. data/lib/adva_rbac.rb +18 -0
  20. data/lib/adva_rbac/version.rb +3 -0
  21. data/lib/permission_map.rb +70 -0
  22. data/lib/rbac.rb +26 -0
  23. data/lib/rbac/acts_as_role_context.rb +44 -0
  24. data/lib/rbac/acts_as_role_subject.rb +65 -0
  25. data/lib/rbac/context.rb +85 -0
  26. data/lib/rbac/role.rb +10 -0
  27. data/lib/rbac/role_type.rb +73 -0
  28. data/lib/rbac/role_type/active_record.rb +47 -0
  29. data/lib/rbac/role_type/static.rb +144 -0
  30. data/lib/rbac/subject.rb +52 -0
  31. data/test/functional/roles_controller_test.rb +21 -0
  32. data/test/integration/user_rbac_test.rb +34 -0
  33. data/test/rbac/all.rb +3 -0
  34. data/test/rbac/database.rb +155 -0
  35. data/test/rbac/database.yml +3 -0
  36. data/test/rbac/implementation/active_record_test.rb +17 -0
  37. data/test/rbac/implementation/static_test.rb +14 -0
  38. data/test/rbac/static.rb +25 -0
  39. data/test/rbac/test_helper.rb +62 -0
  40. data/test/rbac/tests/acts_as_role_context.rb +37 -0
  41. data/test/rbac/tests/context.rb +35 -0
  42. data/test/rbac/tests/group.rb +40 -0
  43. data/test/rbac/tests/has_role.rb +126 -0
  44. data/test/rbac/tests/role_type.rb +110 -0
  45. data/test/test_helper.rb +1 -0
  46. data/test/unit/helpers/roles_helper_test.rb +69 -0
  47. data/test/unit/models/rbac_context_test.rb +37 -0
  48. data/test/unit/models/rbac_user_test.rb +100 -0
  49. data/test/unit/models/role_test.rb +185 -0
  50. metadata +110 -0
@@ -0,0 +1,47 @@
1
+ require 'active_record'
2
+
3
+ module Rbac
4
+ module RoleType
5
+ module ActiveRecord
6
+ class RoleTypeRelationship < ::ActiveRecord::Base
7
+ belongs_to :master, :class_name => "RoleType"
8
+ belongs_to :minion, :class_name => "RoleType"
9
+ end
10
+
11
+
12
+ class RoleType < ::ActiveRecord::Base
13
+ include Rbac::RoleType
14
+
15
+ has_many :master_relationships, :foreign_key => 'master_id', :class_name => 'RoleTypeRelationship', :dependent => :destroy
16
+ has_many :minion_relationships, :foreign_key => 'minion_id', :class_name => 'RoleTypeRelationship', :dependent => :destroy
17
+
18
+ has_many :masters, :through => :minion_relationships
19
+ has_many :minions, :through => :master_relationships
20
+
21
+ class << self
22
+ def build(name)
23
+ find_by_name(name.to_s) || raise(Rbac::UndefinedRoleType.new(name))
24
+ end
25
+ end
26
+
27
+ def requires_context?
28
+ !!attributes['requires_context']
29
+ end
30
+
31
+ def granted_to?(user, context = nil, options = {})
32
+ return super unless ['anonymous', 'user', 'author'].include?(name)
33
+ return false if options[:explicit]
34
+
35
+ case name
36
+ when 'anonymous'
37
+ true
38
+ when 'user'
39
+ user.try(:registered?)
40
+ when 'author'
41
+ context.respond_to?(:author) && context.author == user || super
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,144 @@
1
+ module Rbac
2
+ module RoleType
3
+ module Author
4
+ extend Rbac::RoleType
5
+
6
+ class << self
7
+ def minions
8
+ [User]
9
+ end
10
+
11
+ def masters
12
+ [Moderator]
13
+ end
14
+
15
+ def granted_to?(user, context = nil, options = {})
16
+ options[:explicit] ? false : context.respond_to?(:author) && context.author == user || super
17
+ end
18
+ end
19
+ end
20
+
21
+ module Static
22
+ mattr_accessor :role_types
23
+ self.role_types = [:editor, :superuser, :moderator, :author, :user, :anonymous]
24
+
25
+ class << self
26
+ def build(name)
27
+ const_get(name.to_s.camelize)
28
+ end
29
+
30
+ def all
31
+ @role_types ||= role_types.map { |type| build(type) }
32
+ end
33
+ end
34
+
35
+ module Anonymous
36
+ extend Rbac::RoleType
37
+
38
+ class << self
39
+ def requires_context?
40
+ false
41
+ end
42
+
43
+ def masters
44
+ [User]
45
+ end
46
+
47
+ def minions
48
+ []
49
+ end
50
+
51
+ def granted_to?(user, context = nil, options = {})
52
+ options[:explicit] ? false : true
53
+ end
54
+ end
55
+ end
56
+
57
+ module User
58
+ extend Rbac::RoleType
59
+
60
+ class << self
61
+ def requires_context?
62
+ false
63
+ end
64
+
65
+ def minions
66
+ [Anonymous]
67
+ end
68
+
69
+ def masters
70
+ [Editor, Author]
71
+ end
72
+
73
+ def granted_to?(user, context = nil, options = {})
74
+ options[:explicit] ? false : user.try(:registered?)
75
+ end
76
+ end
77
+ end
78
+
79
+ module Author
80
+ extend Rbac::RoleType
81
+
82
+ class << self
83
+ def minions
84
+ [User]
85
+ end
86
+
87
+ def masters
88
+ [Moderator]
89
+ end
90
+
91
+ def granted_to?(user, context = nil, options = {})
92
+ options[:explicit] ? false : context.respond_to?(:author) && context.author == user || super
93
+ end
94
+ end
95
+ end
96
+
97
+ module Moderator
98
+ extend Rbac::RoleType
99
+
100
+ class << self
101
+ def minions
102
+ [Author]
103
+ end
104
+
105
+ def masters
106
+ [Superuser]
107
+ end
108
+ end
109
+ end
110
+
111
+ module Superuser
112
+ extend Rbac::RoleType
113
+
114
+ class << self
115
+ def requires_context?
116
+ false
117
+ end
118
+
119
+ def minions
120
+ [Moderator, Editor]
121
+ end
122
+
123
+ def masters
124
+ []
125
+ end
126
+ end
127
+ end
128
+
129
+ module Editor
130
+ extend Rbac::RoleType
131
+
132
+ class << self
133
+ def minions
134
+ [User]
135
+ end
136
+
137
+ def masters
138
+ [Superuser]
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,52 @@
1
+ module Rbac
2
+ class Subject
3
+ class << self
4
+ def define_class(model, options)
5
+ Class.new(Base).tap do |klass|
6
+ model.const_set('RoleSubject', klass)
7
+ end
8
+ end
9
+ end
10
+
11
+ class Base
12
+ attr_accessor :object
13
+
14
+ def initialize(object = nil)
15
+ self.object = object
16
+ end
17
+
18
+ def has_permission?(action, context)
19
+ # puts "============== action = #{action}"
20
+ # puts "============== context = #{context}"
21
+ types = context.authorizing_role_types_for(action)
22
+ # puts "============== authorizing_role_types_for #{types}"
23
+ has_role?(types, context)
24
+ end
25
+
26
+ def has_role?(types, context = nil)
27
+ Array(types).any? do |type|
28
+ type = Rbac::RoleType.build(type) unless type.respond_to?(:granted_to?)
29
+ type.granted_to?(self, context)
30
+ end
31
+ end
32
+
33
+ def has_explicit_role?(type, context = nil)
34
+ type = Rbac::RoleType.build(type) unless type.respond_to?(:granted_to?)
35
+ type.granted_to?(self, context, :explicit => true)
36
+ end
37
+
38
+ def ==(other)
39
+ super || object == other # hmmmm ...
40
+ end
41
+
42
+ def respond_to?(method)
43
+ object.respond_to?(method) || super
44
+ end
45
+
46
+ def method_missing(method, *args, &block)
47
+ return object.send(method, *args, &block) if object.respond_to?(method)
48
+ super
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+ class RolesControllerTest < ActionController::TestCase
4
+ with_common :a_site, :a_user
5
+
6
+ test "is an BaseController" do
7
+ @controller.should be_kind_of(BaseController)
8
+ end
9
+
10
+ describe "GET to :index" do
11
+ action { get :index, { :user_id => @user.id } }
12
+
13
+ it_assigns :site, :user, :roles
14
+ it_renders_template :index, :format => :js
15
+ it_caches_the_page # FIXME should track user references, eh?
16
+
17
+ it "always includes the user role" do
18
+ assigns(:roles).map(&:name).should include('user')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper' ))
2
+
3
+ module IntegrationTests
4
+ class UserRbacTest < ActionController::IntegrationTest
5
+ def setup
6
+ super
7
+ @site = use_site! 'site with pages'
8
+ @superuser = User.find_by_email('a-superuser@example.com')
9
+ end
10
+
11
+ test "Updating the user account does not remove users roles" do
12
+ login_as_superuser
13
+ visit_user_edit_form
14
+ fill_and_submit_user_edit_form
15
+ end
16
+
17
+ def visit_user_edit_form
18
+ visit "admin/sites/#{@site.id}/users/#{@superuser.id}/edit"
19
+ assert 'admin/users/edit'
20
+ end
21
+
22
+ def fill_and_submit_user_edit_form
23
+ assert @superuser.has_role?(:superuser)
24
+
25
+ fill_in 'user_first_name', :with => "the awesome"
26
+ fill_in 'user_last_name', :with => "superuser"
27
+ click_button 'Save'
28
+
29
+ @superuser.reload
30
+ assert @superuser.name == "the awesome superuser"
31
+ assert @superuser.has_role?(:superuser)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.dirname(__FILE__) + '/**/*_test.rb'].each do |filename|
2
+ require filename
3
+ end
@@ -0,0 +1,155 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
+
3
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
4
+ ActiveRecord::Base.establish_connection(config['test'])
5
+
6
+ ActiveRecord::Base.connection.create_table :users do |t|
7
+ t.string :name
8
+ t.boolean :anonymous
9
+ end
10
+
11
+ ActiveRecord::Base.connection.create_table :sites do |t|
12
+ t.string :name
13
+ end
14
+
15
+ ActiveRecord::Base.connection.create_table :sections do |t|
16
+ t.string :title
17
+ t.text :permissions
18
+ t.references :site
19
+ end
20
+
21
+ ActiveRecord::Base.connection.create_table :contents do |t|
22
+ t.references :section
23
+ t.references :author
24
+ t.string :title
25
+ t.text :permissions
26
+ end
27
+
28
+ ActiveRecord::Base.connection.create_table :roles do |t|
29
+ t.references :subject, :polymorphic => true
30
+ t.references :context, :polymorphic => true
31
+ t.string :name
32
+ end
33
+
34
+ ActiveRecord::Base.connection.create_table :groups do |t|
35
+ t.string :name
36
+ end
37
+
38
+ ActiveRecord::Base.connection.create_table :group_memberships do |t|
39
+ t.references :user
40
+ t.references :group
41
+ end
42
+
43
+ ActiveRecord::Base.connection.create_table :role_types do |t|
44
+ t.string :name
45
+ t.boolean :requires_context, :default => true
46
+ end
47
+
48
+ ActiveRecord::Base.connection.create_table :role_type_relationships do |t|
49
+ t.references :master
50
+ t.references :minion
51
+ end
52
+
53
+ class User < ActiveRecord::Base
54
+ class RoleSubject < Rbac::Subject::Base
55
+ def roles
56
+ (object.roles + object.groups.map(&:roles).flatten).uniq # should obviously happen in a single query
57
+ end
58
+ end
59
+
60
+ acts_as_role_subject
61
+ has_many :roles, :as => :subject, :class_name => 'Rbac::Role'
62
+ has_many :group_memberships
63
+ has_many :groups, :through => :group_memberships
64
+
65
+ def registered?
66
+ !new_record? && !anonymous?
67
+ end
68
+ end
69
+
70
+ class GroupMembership < ActiveRecord::Base
71
+ belongs_to :user
72
+ belongs_to :group
73
+ end
74
+
75
+ class Group < ActiveRecord::Base
76
+ acts_as_role_subject
77
+
78
+ has_many :group_memberships
79
+ has_many :members, :through => :group_memberships, :source => :user, :class_name => 'User'
80
+ has_many :roles, :as => :subject, :class_name => 'Rbac::Role'
81
+ end
82
+
83
+ class Site < ActiveRecord::Base
84
+ acts_as_role_context
85
+ end
86
+
87
+ class Section < ActiveRecord::Base
88
+ acts_as_role_context
89
+
90
+ belongs_to :site
91
+
92
+ def include?(other)
93
+ !!other
94
+ end
95
+ end
96
+
97
+ class Content < ActiveRecord::Base
98
+ acts_as_role_context :parent => :owner
99
+
100
+ belongs_to :section
101
+ belongs_to :author, :class_name => 'User'
102
+
103
+ def owner
104
+ section
105
+ end
106
+
107
+ def include?(other)
108
+ false
109
+ end
110
+ end
111
+
112
+
113
+ RoleType = Rbac::RoleType::ActiveRecord::RoleType
114
+
115
+ site = Site.create!(:name => 'a site')
116
+ another_site = Site.create!(:name => 'another site')
117
+
118
+ anonymous_type = RoleType.create!(:name => 'anonymous', :requires_context => false)
119
+ user_type = RoleType.create!(:name => 'user', :requires_context => false, :minions => [anonymous_type])
120
+ author_type = RoleType.create!(:name => 'author', :requires_context => true , :minions => [user_type])
121
+ moderator_type = RoleType.create!(:name => 'moderator', :requires_context => true , :minions => [author_type])
122
+ editor_type = RoleType.create!(:name => 'editor', :requires_context => true , :minions => [user_type])
123
+ superuser_type = RoleType.create!(:name => 'superuser', :requires_context => false, :minions => [moderator_type, editor_type])
124
+ pizzaboy_type = RoleType.create!(:name => 'pizzaboy', :requires_context => true)
125
+
126
+ superuser = User.create!(:name => 'superuser')
127
+ admin = User.create!(:name => 'site admin')
128
+ editor = User.create!(:name => 'editor')
129
+ moderator = User.create!(:name => 'moderator')
130
+ site_moderator = User.create!(:name => 'site moderator')
131
+ author = User.create!(:name => 'author')
132
+ user = User.create!(:name => 'user')
133
+ anonymous = User.create!(:name => 'anonymous', :anonymous => true)
134
+ site_designer = User.create!(:name => 'designer')
135
+
136
+ blog = Section.create!(:title => 'blog', :site => site)
137
+ content = Content.create!(:title => 'content', :section => blog, :author => author)
138
+
139
+ john = User.create!(:name => 'john')
140
+ paul = User.create!(:name => 'paul')
141
+ mick = User.create!(:name => 'mick')
142
+ keith = User.create!(:name => 'keith')
143
+
144
+ beatles = Group.create!(:name => 'beatles', :members => [john, paul])
145
+ stones = Group.create!(:name => 'stones', :members => [mick, keith])
146
+
147
+ beatles.roles.create!(:name => 'superuser')
148
+ stones.roles.create!(:name => 'pizzaboy')
149
+ editor.roles.create!(:name => 'editor')
150
+ superuser.roles.create!(:name => 'superuser')
151
+ admin.roles.create!(:name => 'admin', :context => site)
152
+ moderator.roles.create!(:name => 'moderator', :context => blog)
153
+ author.roles.create!(:name => 'author', :context => site)
154
+ site_moderator.roles.create!(:name => 'moderator', :context => site)
155
+ site_designer.roles.create!(:name => 'designer', :context => site)