AccessControl 0.2.6
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/.gitignore +4 -0
- data/README.markdown +105 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/generators/access_control/USAGE +8 -0
- data/generators/access_control/access_control_generator.rb +49 -0
- data/generators/access_control/templates/migrate/create_access_control_models.rb +29 -0
- data/init.rb +9 -0
- data/install.rb +1 -0
- data/lib/access_control.rb +33 -0
- data/lib/access_control/common_methods.rb +41 -0
- data/lib/access_control/controller_helper.rb +10 -0
- data/lib/access_control/language.rb +15 -0
- data/lib/access_control/role_extension.rb +24 -0
- data/lib/access_control/user_extension.rb +84 -0
- data/lib/app/models/permission.rb +20 -0
- data/lib/app/models/role.rb +14 -0
- data/spec/access_controlled_user_spec.rb +91 -0
- data/spec/models/permission_spec.rb +40 -0
- data/spec/models/role_spec.rb +61 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/access_control_user.rb +5 -0
- data/spec/support/authorizable.rb +61 -0
- data/spec/support/schema.rb +39 -0
- data/tasks/access_control_tasks.rake +6 -0
- metadata +85 -0
data/.gitignore
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
AccessControl
|
2
|
+
=============
|
3
|
+
|
4
|
+
AccessControl is a user authorization plugin. It gives you a role based permission system without having to do any work. There are users and roles, each have permission.
|
5
|
+
A user can play any role and inherit permissions through that role. A user may also have individual permissions. For example, you can create a role to update
|
6
|
+
the news section on your site and give a user that role. You may also give him permission to update contact information. Combining these two functionalities gives you
|
7
|
+
a rich permission system inside your application.
|
8
|
+
|
9
|
+
Features
|
10
|
+
---------
|
11
|
+
* Role Based
|
12
|
+
* Easy to query permission (example: @current_user.can_manage_news?)
|
13
|
+
* God permission
|
14
|
+
* Easy to use
|
15
|
+
|
16
|
+
Up and Running
|
17
|
+
================
|
18
|
+
|
19
|
+
Install
|
20
|
+
-------
|
21
|
+
|
22
|
+
First, prepare your application. AccessControl does not create user logins, it soley is a permission system. Your user model must be named User. AccessControl
|
23
|
+
also uses two other models: Permission & Role. Once your users can login and log out, you are ready to use AccessControl.
|
24
|
+
|
25
|
+
1. Install
|
26
|
+
sudo gem install AccessControl
|
27
|
+
config.gem 'AccessControl'
|
28
|
+
|
29
|
+
2. Prepare the database
|
30
|
+
./script/generate access_control models
|
31
|
+
rake db:migrate
|
32
|
+
|
33
|
+
Step 2 creates a migration that creates one join table, role, and permission table. Migrate your database and you are ready to start working with permissions.
|
34
|
+
|
35
|
+
|
36
|
+
Working with Permissions
|
37
|
+
-------
|
38
|
+
|
39
|
+
Each permission you need in your application is a column in the permission model. Once again, we use a migration to create our permission.
|
40
|
+
./script/generate access_control permission NameOfYourPermission
|
41
|
+
./script/generate access_control permission YourFirstPermission YourSecondPermission YourThirdPermission
|
42
|
+
|
43
|
+
The first creates a named migration. As you can see from the second example you can also create multiple permissions at once. Now, install your permissions:
|
44
|
+
rake db:migrate
|
45
|
+
|
46
|
+
You're permissions are now ready. They can be attached to a user or a role. Now, you need to tell your user model that is has access controls:
|
47
|
+
class User < ActiveRecord::Base
|
48
|
+
has_access_controls
|
49
|
+
# some more code
|
50
|
+
end
|
51
|
+
|
52
|
+
And that's it! You are now ready to start granting and creating your authorization structure. First, lets focus on our users.
|
53
|
+
Let us assume that there is a permission named PostNews. In your application, permissions are passed in underscore notation so post_news is correct.
|
54
|
+
Let's give a user this permission:
|
55
|
+
user = User.find_by_name "Adam", "Hawkins"
|
56
|
+
user.can_post_news?
|
57
|
+
user.grant :post_news
|
58
|
+
user.can_post_news?
|
59
|
+
|
60
|
+
Voilla, Adam can now post_news. But that's no good by itself. So now check aganist for the permission in the controller:
|
61
|
+
class NewsController < ActionController::Base
|
62
|
+
before_filter permission_required(@current_user, :post_news)
|
63
|
+
end
|
64
|
+
|
65
|
+
Your controllers are protected from people who can't post news. Now lets expand our permissions by adding a role:
|
66
|
+
editors = Role.create :name => "Editors", :description => "Manage content around the site." # Description is optional
|
67
|
+
# assuming we have these permissions in the system
|
68
|
+
editors.grant :manage_news
|
69
|
+
editors.grant :manage_categories
|
70
|
+
editors.grant :manage_comments
|
71
|
+
editors.grant :ban_users
|
72
|
+
# now we need adam to be an editor
|
73
|
+
user.plays :editor
|
74
|
+
user.can_manage_news? (true)
|
75
|
+
user.can_manage_categories? (true)
|
76
|
+
user.can_manage_comments (true)
|
77
|
+
user.can_ban_users? (true)
|
78
|
+
|
79
|
+
Man, Adam sure got a lot of responsibilities, hopefully you trust him :)
|
80
|
+
|
81
|
+
|
82
|
+
Using the language
|
83
|
+
==============
|
84
|
+
|
85
|
+
Here are the methods available on User & Role objects:
|
86
|
+
Authorizable#authorize(permission)
|
87
|
+
Authorizable#grant(permission)
|
88
|
+
Authorizable#deauthorize(permission)
|
89
|
+
Authorizable#cannot?(permission)
|
90
|
+
Authorizable#god?
|
91
|
+
Authorizable#can_permission_name?
|
92
|
+
Authorizable#can_not_permission_name?
|
93
|
+
Authorizable#permissions
|
94
|
+
Authorizable#has_permission?(permission)
|
95
|
+
Authorizable#can?(permission)
|
96
|
+
|
97
|
+
User Methods:
|
98
|
+
User#plays?(role)
|
99
|
+
User#plays(role)
|
100
|
+
User#does_not_play?(role)
|
101
|
+
User#does_not_play(role)
|
102
|
+
User#roles (and all other has_and_belongs_to_many methods)
|
103
|
+
User#has_any_permissions? (useful to see if you should allow someone into an admin area)
|
104
|
+
|
105
|
+
Copyright (c) 2009 Adam Hawkins, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the access_control plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the access_control plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'AccessControl'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'jeweler'
|
27
|
+
|
28
|
+
Jeweler::Tasks.new do |s|
|
29
|
+
s.name = "AccessControl"
|
30
|
+
s.summary = "Simple role based authorization for rails"
|
31
|
+
s.email = "Adman1965@gmail.com"
|
32
|
+
s.homepage = "http://github.com/Adman65/AccessControl"
|
33
|
+
s.description = "Simple role based authorization for rails"
|
34
|
+
s.authors = ["Adam Hawkins"]
|
35
|
+
Jeweler::GemcutterTasks.new
|
36
|
+
end
|
37
|
+
rescue LoadError
|
38
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.6
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class AccessControlGenerator < Rails::Generator::NamedBase
|
2
|
+
attr_reader :mode, :args
|
3
|
+
|
4
|
+
def initialize(args,runtime_options = {})
|
5
|
+
super
|
6
|
+
|
7
|
+
mode = args.first.downcase if args.is_a? Array
|
8
|
+
case mode
|
9
|
+
when 'models'
|
10
|
+
@mode = :models
|
11
|
+
when 'permission'
|
12
|
+
@mode = :permission
|
13
|
+
else
|
14
|
+
raise 'You must specify what to generate: models or permission'
|
15
|
+
end
|
16
|
+
|
17
|
+
@permission_names = args[1..args.size].map { |name| name.underscore.downcase} if args.is_a? Array
|
18
|
+
@permission_name = args.second.underscore.downcase if args.is_a? Array and args.size.eql?(2)
|
19
|
+
|
20
|
+
@args = args
|
21
|
+
end
|
22
|
+
|
23
|
+
def manifest
|
24
|
+
record do |m|
|
25
|
+
case mode
|
26
|
+
when :models
|
27
|
+
# m.directory "lib"
|
28
|
+
# m.template 'README', "README"
|
29
|
+
|
30
|
+
m.migration_template File.join("migrate","create_access_control_models.rb"), File.join("db","migrate"), :migration_file_name => "GenerateAccessControlModels".underscore
|
31
|
+
when :permission
|
32
|
+
file_name = "create_multiple_permissions_#{@permission_names.join('_').underscore}" if args.size > 2
|
33
|
+
file_name = "create_permission_#{@permission_name}" if args.size.eql? 2
|
34
|
+
m.migration_template "migration:migration.rb", File.join("db","migrate"), :assigns => migration_options, :migration_file_name => file_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def migration_options
|
41
|
+
assigns = {}
|
42
|
+
assigns[:migration_action] = "add"
|
43
|
+
assigns[:class_name] = "create_multiple_permissions_#{@permission_names.join('_').underscore}".camelize if @permission_names
|
44
|
+
assigns[:class_name] = "create_permission_#{@permission_name}" if @permission_name
|
45
|
+
assigns[:table_name] = "permissions"
|
46
|
+
assigns[:attributes] = @permission_names.map {|name| Rails::Generator::GeneratedAttribute.new(name, "boolean")}
|
47
|
+
assigns
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class GenerateAccessControlModels < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table "permissions" do |t|
|
4
|
+
t.integer "authorizable_id"
|
5
|
+
t.string "authorizable_type"
|
6
|
+
t.datetime "created_at"
|
7
|
+
t.datetime "updated_at"
|
8
|
+
t.boolean "god", :default => false
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table "roles" do |t|
|
12
|
+
t.string "name"
|
13
|
+
t.string "description"
|
14
|
+
t.datetime "created_at"
|
15
|
+
t.datetime "updated_at"
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table "user_roles", :id => false do |t|
|
19
|
+
t.integer "user_id"
|
20
|
+
t.integer "role_id"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table :permisisons
|
26
|
+
drop_table :roles
|
27
|
+
drop_table :user_roles
|
28
|
+
end
|
29
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Include hook code here
|
2
|
+
%w{ models controllers helpers }.each do |dir|
|
3
|
+
path = File.join(directory, 'lib', dir)
|
4
|
+
$: << path
|
5
|
+
ActiveSupport::Dependencies.load_paths << path
|
6
|
+
ActiveSupport::Dependencies.load_once_paths.delete(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'access_control.rb'
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# AccessControl
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), 'access_control', 'user_extension')
|
4
|
+
require File.join(File.dirname(__FILE__), 'access_control', 'controller_helper')
|
5
|
+
require File.join(File.dirname(__FILE__), 'access_control', 'common_methods')
|
6
|
+
require File.join(File.dirname(__FILE__), 'access_control', 'language')
|
7
|
+
require File.join(File.dirname(__FILE__), 'access_control', 'role_extension')
|
8
|
+
|
9
|
+
%w{ models }.each do |dir|
|
10
|
+
path = File.join(File.dirname(__FILE__), 'app', dir)
|
11
|
+
$LOAD_PATH << path
|
12
|
+
ActiveSupport::Dependencies.load_paths << path
|
13
|
+
ActiveSupport::Dependencies.load_once_paths.delete(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
module AccessControl
|
17
|
+
module MacroMethods
|
18
|
+
def self.included base
|
19
|
+
base.extend ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def has_access_controls
|
25
|
+
include AccessControl::UserExtension
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
ActiveRecord::Base.send :include, AccessControl::MacroMethods
|
33
|
+
ActionController::Base.send :include, AccessControl::ControllerHelper
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module AccessControl
|
2
|
+
module CommonMethods
|
3
|
+
|
4
|
+
def self.included(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
alias_method :authorize, :grant
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def grant(perm)
|
11
|
+
self.permission = Permission.create if self.permission.nil?
|
12
|
+
perm = perm.to_s if perm.is_a? Symbol
|
13
|
+
raise "Permission (#{perm}) does not exist" unless self.permission.respond_to? perm.to_sym
|
14
|
+
self.permission.update_attribute(perm,true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def deauthorize perm
|
18
|
+
self.permission = Permission.create if self.permission.nil?
|
19
|
+
perm = perm.to_s if perm.is_a? Symbol
|
20
|
+
raise "Permission (#{perm}) does not exist" unless self.permission.respond_to? perm.to_sym
|
21
|
+
self.permission.update_attribute(perm,false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def cannot? perm
|
25
|
+
!has_permission? perm
|
26
|
+
end
|
27
|
+
|
28
|
+
def god?
|
29
|
+
has_permission? :god
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_local_permission? perm
|
33
|
+
perm = perm.to_s if perm.is_a? Symbol
|
34
|
+
raise "Permission (#{perm}) does not exist" unless Permission.new.respond_to? perm.to_sym
|
35
|
+
return false if self.permission.nil?
|
36
|
+
return true if self.permission.god
|
37
|
+
self.permission.send(perm)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AccessControl
|
2
|
+
module Language
|
3
|
+
|
4
|
+
def method_missing(method_id, *attrs)
|
5
|
+
if /can_not_(.+)\?/.match(method_id.to_s)
|
6
|
+
return !has_permission?($~[1])
|
7
|
+
elsif /can_(.+)\?/.match(method_id.to_s)
|
8
|
+
return has_permission?($~[1])
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AccessControl
|
2
|
+
module RoleExtension
|
3
|
+
|
4
|
+
def self.included(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
include AccessControl::CommonMethods
|
7
|
+
include AccessControl::Language
|
8
|
+
|
9
|
+
has_and_belongs_to_many :users, :join_table => :user_roles
|
10
|
+
has_one :permission, :as => :authorizable, :dependent => :destroy
|
11
|
+
|
12
|
+
alias :has_permission? :has_local_permission?
|
13
|
+
alias :can? :has_local_permission?
|
14
|
+
|
15
|
+
accepts_nested_attributes_for :permission
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def permissions
|
20
|
+
self.permission.set_permissions
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module AccessControl
|
2
|
+
module UserExtension
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
include AccessControl::CommonMethods
|
6
|
+
include AccessControl::Language
|
7
|
+
|
8
|
+
has_one :permission, :as => :authorizable, :dependent => :destroy
|
9
|
+
has_and_belongs_to_many :roles, :join_table => :user_roles
|
10
|
+
|
11
|
+
alias_method :can?, :has_permission?
|
12
|
+
|
13
|
+
accepts_nested_attributes_for :permission
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def plays role
|
18
|
+
role = role.to_s if role.is_a? Symbol
|
19
|
+
r = Role.find_by_name role.downcase
|
20
|
+
raise "#{role} does not exist." if r.nil?
|
21
|
+
roles << r
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def plays? role
|
26
|
+
role = role.to_s if role.is_a? Symbol
|
27
|
+
actual_role = Role.find_by_name(role.downcase)
|
28
|
+
raise "#{role} does not exist" if actual_role.nil?
|
29
|
+
roles.include? actual_role
|
30
|
+
end
|
31
|
+
|
32
|
+
def does_not_play? role
|
33
|
+
!plays? role
|
34
|
+
end
|
35
|
+
|
36
|
+
def does_not_play role
|
37
|
+
role = role.to_s if role.is_a? Symbol
|
38
|
+
actual_role = Role.find_by_name(role.downcase)
|
39
|
+
raise "#{role} does not exist" if actual_role.nil?
|
40
|
+
roles.delete actual_role
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_permission? perm
|
44
|
+
return true if has_local_permission? perm
|
45
|
+
roles.each do |role|
|
46
|
+
return true if role.has_local_permission? perm
|
47
|
+
end
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def permissions
|
52
|
+
set = self.permission.set_permissions unless self.permission.nil?
|
53
|
+
set = [] if set.nil?
|
54
|
+
set = [set] if set.is_a? String
|
55
|
+
|
56
|
+
role_permissions = []
|
57
|
+
roles.each do |role|
|
58
|
+
role_perms = role.permission.set_permissions
|
59
|
+
role_permissions << role_perms if role_perms.is_a? String
|
60
|
+
role_permissions = role_permissions + role_perms if role_perms.is_a? Array
|
61
|
+
end
|
62
|
+
|
63
|
+
total = set + role_permissions
|
64
|
+
total.uniq
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_any_permissions?
|
68
|
+
!self.permissions.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
def roles_attributes=(attributes)
|
72
|
+
if attributes.size == 1
|
73
|
+
self.roles.clear
|
74
|
+
else
|
75
|
+
keys = []
|
76
|
+
attributes.each_key do |id|
|
77
|
+
keys << id unless id.to_i.eql? 0
|
78
|
+
end
|
79
|
+
self.role_ids = keys
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Permission < ActiveRecord::Base
|
2
|
+
belongs_to :authorizable, :polymorphic => true
|
3
|
+
|
4
|
+
def self.names
|
5
|
+
boolean_columns = columns.select { |column| column.type == :boolean}
|
6
|
+
boolean_columns.map { |column| column.name }
|
7
|
+
end
|
8
|
+
|
9
|
+
def empty?
|
10
|
+
set_permissions.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_permissions
|
14
|
+
Permission.names.select {|name| self.send(name.to_sym).eql?(true)}
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
Permission.names.select {|name| self.update_attribute(name.to_sym,false)}
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#require '../access_control'
|
2
|
+
|
3
|
+
class Role < ActiveRecord::Base
|
4
|
+
include AccessControl::RoleExtension
|
5
|
+
|
6
|
+
validates_presence_of :name
|
7
|
+
validates_uniqueness_of :name
|
8
|
+
|
9
|
+
validates_length_of :description, :maximum => 100, :allow_nil => true
|
10
|
+
|
11
|
+
def before_validation
|
12
|
+
self.name = self.name.downcase unless self.name.nil?
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/access_control_user'
|
3
|
+
|
4
|
+
describe "User with access controls" do
|
5
|
+
before(:each) do
|
6
|
+
@authorizable = User.new
|
7
|
+
@user = @authorizable
|
8
|
+
@admin_role = Role.create!(:name => "admin")
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
@admin_role.destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
it_should_behave_like "Authorizable"
|
16
|
+
|
17
|
+
describe "Working with Roles" do
|
18
|
+
it "should be a role after granting a role" do
|
19
|
+
lambda {@user.plays?(:rspec)}.should raise_error
|
20
|
+
r = Role.create! :name => "Rspec", :description => "runs rspec tests"
|
21
|
+
@user.plays("Rspec").should be_true
|
22
|
+
@user.plays?(:rspec).should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should raise an error when setting a role that doesn't exsist" do
|
26
|
+
lambda {@user.plays(:fake_role)}.should raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an error when asking if a user plays a role that doesn't exist" do
|
30
|
+
lambda {@user.plays?(:fake_role)}.should raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "Checking Authorization" do
|
35
|
+
it "should authorize god users on any permission" do
|
36
|
+
@user.can?(:manage_news).should be_false
|
37
|
+
@user.grant(:god).should be_true
|
38
|
+
Permission.names.each {|name| @user.can?(name).should be_true}
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should authorize if the user the permission through a role" do
|
42
|
+
@user.can_manage_news?.should be_false
|
43
|
+
@admin_role.can_manage_news?.should be_false
|
44
|
+
@user.plays(:admin).should be_true
|
45
|
+
@admin_role.grant(:manage_news).should be_true
|
46
|
+
@user.can_manage_news?.should be_true
|
47
|
+
|
48
|
+
@user.roles.clear
|
49
|
+
@user.can_manage_news?.should be_false
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should authorize if the user has permission through his permissions" do
|
53
|
+
@user.can_manage_schedule?.should be_false
|
54
|
+
@user.grant(:manage_schedule).should be_true
|
55
|
+
@user.can_manage_schedule?.should be_true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be able to check access denied" do
|
59
|
+
@user.permission = nil
|
60
|
+
@user.roles.clear
|
61
|
+
@user.can_not_manage_schedule?.should be_true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "Counting total permissions" do
|
66
|
+
it "should have permissions if they belong to the user" do
|
67
|
+
@user.has_any_permissions?.should be_false
|
68
|
+
@user.permissions.empty?.should be_true
|
69
|
+
@user.grant :manage_news
|
70
|
+
@user.permissions.should_not be_nil
|
71
|
+
@user.permissions.should eql(['manage_news'])
|
72
|
+
@user.has_any_permissions?.should be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should have permissions through roles" do
|
76
|
+
@user.has_any_permissions?.should be_false
|
77
|
+
@user.grant :manage_news
|
78
|
+
@admin_role.grant :manage_schedule
|
79
|
+
@user.plays :admin
|
80
|
+
@user.permissions.should be_a(Array)
|
81
|
+
@user.permissions.size.should eql(2)
|
82
|
+
@user.permissions.include?('manage_schedule').should be_true
|
83
|
+
@user.permissions.include?('manage_news').should be_true
|
84
|
+
@user.has_any_permissions?.should be_true
|
85
|
+
|
86
|
+
@user.permission.clear
|
87
|
+
@user.permissions.should be_a(Array)
|
88
|
+
@user.permissions.should eql(['manage_schedule'])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Permission" do
|
4
|
+
it "should be able to clear permissions" do
|
5
|
+
permission = Permission.new
|
6
|
+
permission.run_tests = true
|
7
|
+
permission.god = true
|
8
|
+
permission.post_news = true
|
9
|
+
permission.clear
|
10
|
+
permission.run_tests.should be_false
|
11
|
+
permission.god.should be_false
|
12
|
+
permission.post_news.should be_false
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Counting Permissions" do
|
17
|
+
it "should be empty if no permissions are set" do
|
18
|
+
permission = Permission.new
|
19
|
+
permission.empty?.should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "Set Permissions" do
|
23
|
+
it "should return an empty array if none are set" do
|
24
|
+
permission = Permission.new
|
25
|
+
permission.set_permissions.should be_a(Array)
|
26
|
+
permission.set_permissions.empty?.should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return an array of set permissions" do
|
30
|
+
permission = Permission.new
|
31
|
+
permission.run_tests = true
|
32
|
+
permission.god = true
|
33
|
+
permission.set_permissions.should be_a(Array)
|
34
|
+
permission.set_permissions.size.should eql(2)
|
35
|
+
permission.set_permissions.include?('run_tests').should be_true
|
36
|
+
permission.set_permissions.include?('god').should be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "Role" do
|
4
|
+
before(:each) do
|
5
|
+
@valid_attributes = {
|
6
|
+
:name => "Role name",
|
7
|
+
:description => "Role Description",
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should require a name" do
|
12
|
+
role = Role.create(@valid_attributes.except(:name))
|
13
|
+
role.should_not be_valid
|
14
|
+
role.errors.size.should eql(1)
|
15
|
+
role.errors.on(:name).should_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should require a unique name" do
|
19
|
+
Role.create(@valid_attributes)
|
20
|
+
|
21
|
+
r = Role.create(@valid_attributes)
|
22
|
+
r.should_not be_valid
|
23
|
+
r.errors.size.should eql(1)
|
24
|
+
r.errors.on(:name).should_not be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "should only allow descriptions up to 100 characters" do
|
29
|
+
@valid_attributes[:description] = "2" * 101
|
30
|
+
r = Role.create @valid_attributes
|
31
|
+
r.should_not be_valid
|
32
|
+
r.errors.on(:description).should match(/is too long/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should create a new instance given valid attributes" do
|
36
|
+
Role.destroy_all
|
37
|
+
Role.create!(@valid_attributes)
|
38
|
+
Role.destroy_all
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should always downcase named" do
|
42
|
+
r = Role.create(@valid_attributes)
|
43
|
+
r.name.should eql(@valid_attributes[:name].downcase)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
describe "Permission System" do
|
48
|
+
before(:each) do
|
49
|
+
@role = Role.create! @valid_attributes
|
50
|
+
@authorizable = @role
|
51
|
+
end
|
52
|
+
|
53
|
+
after(:each) do
|
54
|
+
@role.destroy
|
55
|
+
end
|
56
|
+
|
57
|
+
it_should_behave_like "Authorizable"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
|
3
|
+
require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'access_control')
|
6
|
+
|
7
|
+
require File.join(File.dirname(__FILE__), 'support', 'authorizable')
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => "access_control.sqlite3")
|
10
|
+
|
11
|
+
load File.join(File.dirname(__FILE__), 'support', 'schema.rb')
|
@@ -0,0 +1,61 @@
|
|
1
|
+
shared_examples_for "Authorizable" do
|
2
|
+
describe "DSL" do
|
3
|
+
it "should have method in the format of can_permission_name? to ask permission" do
|
4
|
+
Permission.names.each do |permission|
|
5
|
+
method_name = ("can_" + permission.downcase + "?").to_sym
|
6
|
+
@authorizable.send(method_name)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a method formatted like can_not_permission? to see if denied" do
|
11
|
+
Permission.names.each do |permission|
|
12
|
+
method_name = ("can_not_" + permission.downcase + "?").to_sym
|
13
|
+
@authorizable.send(method_name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should raise an error when asking can_permission_that_deoesnt_exist" do
|
18
|
+
lambda{ @authorizable.can_permission_that_has_no_chance_of_existing?}.should raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should also raise an error when asking can_not?" do
|
22
|
+
lambda{ @authorizable.can_not_permission_that_has_no_chance_of_existing?}.should raise_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "Granting a permission" do
|
27
|
+
it "should have a method to grant a permission" do
|
28
|
+
@authorizable.respond_to?(:grant).should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should take a symbol as a permission name" do
|
32
|
+
lambda {@authorizable.grant(:manage_users)}.should_not raise_error
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should take a string as a permission name" do
|
36
|
+
lambda { @authorizable.grant("manage_users")}.should_not raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error if the permission is not a string or symbol" do
|
40
|
+
lambda { @authorizable.grant([:permission, :permission])}.should raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should only grant permissions that exist" do
|
44
|
+
@authorizable.grant(:manage_news).should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should raise an error when permissions don't exist" do
|
48
|
+
lambda { @authorizable.grant(:adsfjk238748723478)}.should raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be able to authorize after granting" do
|
52
|
+
@authorizable.can?(:manage_news).should be_false
|
53
|
+
@authorizable.grant(:manage_news).should be_true
|
54
|
+
@authorizable.can?(:manage_news).should be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have a method to check to see if it is god" do
|
58
|
+
@authorizable.respond_to?(:god?).should be_true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table "permissions", :force => true do |t|
|
3
|
+
t.integer "authorizable_id"
|
4
|
+
t.string "authorizable_type"
|
5
|
+
t.datetime "created_at"
|
6
|
+
t.datetime "updated_at"
|
7
|
+
t.boolean "run_tests", :default => false
|
8
|
+
t.boolean "post_news", :default => false
|
9
|
+
t.boolean "manage_news", :default => false
|
10
|
+
t.boolean "manage_users", :default => false
|
11
|
+
t.boolean "god", :default => false
|
12
|
+
t.boolean "manage_events", :default => false
|
13
|
+
t.boolean "manage_schedule", :default => false
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table "role_permissions", :id => false, :force => true do |t|
|
17
|
+
t.integer "role_id"
|
18
|
+
t.integer "permission_id"
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table "roles", :force => true do |t|
|
22
|
+
t.string "name"
|
23
|
+
t.string "description"
|
24
|
+
t.datetime "created_at"
|
25
|
+
t.datetime "updated_at"
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table "user_roles", :id => false, :force => true do |t|
|
29
|
+
t.integer "user_id"
|
30
|
+
t.integer "role_id"
|
31
|
+
end
|
32
|
+
|
33
|
+
create_table "users", :force => true do |t|
|
34
|
+
t.string "name"
|
35
|
+
t.datetime "created_at"
|
36
|
+
t.datetime "updated_at"
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: AccessControl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Hawkins
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-20 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Simple role based authorization for rails
|
17
|
+
email: Adman1965@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- README.markdown
|
27
|
+
- Rakefile
|
28
|
+
- VERSION
|
29
|
+
- generators/access_control/USAGE
|
30
|
+
- generators/access_control/access_control_generator.rb
|
31
|
+
- generators/access_control/templates/migrate/create_access_control_models.rb
|
32
|
+
- init.rb
|
33
|
+
- install.rb
|
34
|
+
- lib/access_control.rb
|
35
|
+
- lib/access_control/common_methods.rb
|
36
|
+
- lib/access_control/controller_helper.rb
|
37
|
+
- lib/access_control/language.rb
|
38
|
+
- lib/access_control/role_extension.rb
|
39
|
+
- lib/access_control/user_extension.rb
|
40
|
+
- lib/app/models/permission.rb
|
41
|
+
- lib/app/models/role.rb
|
42
|
+
- spec/access_controlled_user_spec.rb
|
43
|
+
- spec/models/permission_spec.rb
|
44
|
+
- spec/models/role_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
- spec/support/access_control_user.rb
|
47
|
+
- spec/support/authorizable.rb
|
48
|
+
- spec/support/schema.rb
|
49
|
+
- tasks/access_control_tasks.rake
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/Adman65/AccessControl
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options:
|
56
|
+
- --charset=UTF-8
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.5
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Simple role based authorization for rails
|
78
|
+
test_files:
|
79
|
+
- spec/access_controlled_user_spec.rb
|
80
|
+
- spec/models/permission_spec.rb
|
81
|
+
- spec/models/role_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
- spec/support/access_control_user.rb
|
84
|
+
- spec/support/authorizable.rb
|
85
|
+
- spec/support/schema.rb
|