makandra-aegis 1.1.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.
- data/.gitignore +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +66 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/aegis.gemspec +93 -0
- data/lib/aegis/constants.rb +6 -0
- data/lib/aegis/has_role.rb +77 -0
- data/lib/aegis/normalization.rb +26 -0
- data/lib/aegis/permission_error.rb +5 -0
- data/lib/aegis/permission_evaluator.rb +34 -0
- data/lib/aegis/permissions.rb +111 -0
- data/lib/aegis/role.rb +55 -0
- data/lib/aegis.rb +9 -0
- data/lib/rails/active_record.rb +5 -0
- data/test/app_root/app/controllers/application_controller.rb +2 -0
- data/test/app_root/app/models/permissions.rb +49 -0
- data/test/app_root/app/models/soldier.rb +5 -0
- data/test/app_root/app/models/user.rb +6 -0
- data/test/app_root/config/boot.rb +114 -0
- data/test/app_root/config/database.yml +21 -0
- data/test/app_root/config/environment.rb +14 -0
- data/test/app_root/config/environments/in_memory.rb +0 -0
- data/test/app_root/config/environments/mysql.rb +0 -0
- data/test/app_root/config/environments/postgresql.rb +0 -0
- data/test/app_root/config/environments/sqlite.rb +0 -0
- data/test/app_root/config/environments/sqlite3.rb +0 -0
- data/test/app_root/config/routes.rb +4 -0
- data/test/app_root/db/migrate/20090408115228_create_users.rb +14 -0
- data/test/app_root/db/migrate/20090429075648_create_soldiers.rb +16 -0
- data/test/app_root/lib/console_with_fixtures.rb +4 -0
- data/test/app_root/log/.gitignore +1 -0
- data/test/app_root/script/console +7 -0
- data/test/has_role_options_test.rb +28 -0
- data/test/has_role_test.rb +39 -0
- data/test/permissions_test.rb +92 -0
- data/test/test_helper.rb +23 -0
- data/test/validation_test.rb +49 -0
- metadata +109 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Henning Koch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
= Aegis - role-based permissions for your user models
|
2
|
+
|
3
|
+
Aegis allows you to managed fine-grained and complex permission for user accounts in a central place.
|
4
|
+
|
5
|
+
=== Example
|
6
|
+
|
7
|
+
First, let's define some roles:
|
8
|
+
|
9
|
+
# app/models/permissions.rb
|
10
|
+
class Permissions < Aegis::Permissions
|
11
|
+
|
12
|
+
role :guest
|
13
|
+
role :registered_user
|
14
|
+
role :moderator
|
15
|
+
role :administrator, :default_permission => :allow
|
16
|
+
|
17
|
+
permission :edit_post do |user, post|
|
18
|
+
allow :registered_user do
|
19
|
+
post.creator == user # a registered_user can only edit his own posts
|
20
|
+
end
|
21
|
+
allow :moderator
|
22
|
+
end
|
23
|
+
|
24
|
+
permission :read_post do |post|
|
25
|
+
allow :everyone
|
26
|
+
deny :guest do
|
27
|
+
post.private? # guests may not read private posts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
Now we assign roles to users. For this, the users table needs to have a string
|
35
|
+
column +role_name+.
|
36
|
+
|
37
|
+
# app/models/user.rb
|
38
|
+
class User
|
39
|
+
has_role
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
These permissions may be used in views and controllers:
|
44
|
+
|
45
|
+
# app/views/posts/index.html.erb
|
46
|
+
@posts.each do |post|
|
47
|
+
<% if current_user.may_read_post? post %>
|
48
|
+
<%= render post %>
|
49
|
+
<% if current_user.may_edit_post? post %>
|
50
|
+
<%= link_to 'Edit', edit_post_path(post) %>
|
51
|
+
<% end %>
|
52
|
+
<% end %>
|
53
|
+
<% end %>
|
54
|
+
|
55
|
+
|
56
|
+
# app/controllers/posts_controller.rb
|
57
|
+
class PostsController
|
58
|
+
# ...
|
59
|
+
|
60
|
+
def update
|
61
|
+
@post = Post.find(params[:id])
|
62
|
+
current_user.may_edit_post! @post # raises an Aegis::PermissionError for unauthorized access
|
63
|
+
# ...
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
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 aegis gem.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the aegis plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Aegis'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'jeweler'
|
26
|
+
Jeweler::Tasks.new do |gemspec|
|
27
|
+
gemspec.name = "aegis"
|
28
|
+
gemspec.summary = "Role-based permissions for your user models."
|
29
|
+
gemspec.email = "github@makandra.de"
|
30
|
+
gemspec.homepage = "http://github.com/makandra/aegis"
|
31
|
+
gemspec.description = "Aegis is a role-based permission system, where all users are given a role. It is possible to define detailed and complex permissions for each role very easily."
|
32
|
+
gemspec.authors = ["Henning Koch"]
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
36
|
+
end
|
37
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.1.1
|
data/aegis.gemspec
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{aegis}
|
5
|
+
s.version = "1.1.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Henning Koch"]
|
9
|
+
s.date = %q{2009-05-29}
|
10
|
+
s.description = %q{Aegis is a role-based permission system, where all users are given a role. It is possible to define detailed and complex permissions for each role very easily.}
|
11
|
+
s.email = %q{github@makandra.de}
|
12
|
+
s.extra_rdoc_files = [
|
13
|
+
"README.rdoc"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
".gitignore",
|
17
|
+
"MIT-LICENSE",
|
18
|
+
"README.rdoc",
|
19
|
+
"Rakefile",
|
20
|
+
"VERSION",
|
21
|
+
"aegis.gemspec",
|
22
|
+
"lib/aegis.rb",
|
23
|
+
"lib/aegis/constants.rb",
|
24
|
+
"lib/aegis/has_role.rb",
|
25
|
+
"lib/aegis/normalization.rb",
|
26
|
+
"lib/aegis/permission_error.rb",
|
27
|
+
"lib/aegis/permission_evaluator.rb",
|
28
|
+
"lib/aegis/permissions.rb",
|
29
|
+
"lib/aegis/role.rb",
|
30
|
+
"lib/rails/active_record.rb",
|
31
|
+
"test/app_root/app/controllers/application_controller.rb",
|
32
|
+
"test/app_root/app/models/permissions.rb",
|
33
|
+
"test/app_root/app/models/soldier.rb",
|
34
|
+
"test/app_root/app/models/user.rb",
|
35
|
+
"test/app_root/config/boot.rb",
|
36
|
+
"test/app_root/config/database.yml",
|
37
|
+
"test/app_root/config/environment.rb",
|
38
|
+
"test/app_root/config/environments/in_memory.rb",
|
39
|
+
"test/app_root/config/environments/mysql.rb",
|
40
|
+
"test/app_root/config/environments/postgresql.rb",
|
41
|
+
"test/app_root/config/environments/sqlite.rb",
|
42
|
+
"test/app_root/config/environments/sqlite3.rb",
|
43
|
+
"test/app_root/config/routes.rb",
|
44
|
+
"test/app_root/db/migrate/20090408115228_create_users.rb",
|
45
|
+
"test/app_root/db/migrate/20090429075648_create_soldiers.rb",
|
46
|
+
"test/app_root/lib/console_with_fixtures.rb",
|
47
|
+
"test/app_root/log/.gitignore",
|
48
|
+
"test/app_root/script/console",
|
49
|
+
"test/has_role_options_test.rb",
|
50
|
+
"test/has_role_test.rb",
|
51
|
+
"test/permissions_test.rb",
|
52
|
+
"test/test_helper.rb",
|
53
|
+
"test/validation_test.rb"
|
54
|
+
]
|
55
|
+
s.has_rdoc = true
|
56
|
+
s.homepage = %q{http://github.com/makandra/aegis}
|
57
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
58
|
+
s.require_paths = ["lib"]
|
59
|
+
s.rubygems_version = %q{1.3.1}
|
60
|
+
s.summary = %q{Role-based permissions for your user models.}
|
61
|
+
s.test_files = [
|
62
|
+
"test/app_root/app/models/permissions.rb",
|
63
|
+
"test/app_root/app/models/soldier.rb",
|
64
|
+
"test/app_root/app/models/user.rb",
|
65
|
+
"test/app_root/app/controllers/application_controller.rb",
|
66
|
+
"test/app_root/config/environment.rb",
|
67
|
+
"test/app_root/config/environments/mysql.rb",
|
68
|
+
"test/app_root/config/environments/postgresql.rb",
|
69
|
+
"test/app_root/config/environments/sqlite3.rb",
|
70
|
+
"test/app_root/config/environments/in_memory.rb",
|
71
|
+
"test/app_root/config/environments/sqlite.rb",
|
72
|
+
"test/app_root/config/boot.rb",
|
73
|
+
"test/app_root/config/routes.rb",
|
74
|
+
"test/app_root/db/migrate/20090429075648_create_soldiers.rb",
|
75
|
+
"test/app_root/db/migrate/20090408115228_create_users.rb",
|
76
|
+
"test/app_root/lib/console_with_fixtures.rb",
|
77
|
+
"test/validation_test.rb",
|
78
|
+
"test/test_helper.rb",
|
79
|
+
"test/has_role_options_test.rb",
|
80
|
+
"test/has_role_test.rb",
|
81
|
+
"test/permissions_test.rb"
|
82
|
+
]
|
83
|
+
|
84
|
+
if s.respond_to? :specification_version then
|
85
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
86
|
+
s.specification_version = 2
|
87
|
+
|
88
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
89
|
+
else
|
90
|
+
end
|
91
|
+
else
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Aegis
|
2
|
+
module HasRole
|
3
|
+
|
4
|
+
def validates_role_name(options = {})
|
5
|
+
validates_each :role_name do |record, attr, value|
|
6
|
+
options[:message] ||= ActiveRecord::Errors.default_error_messages[:inclusion]
|
7
|
+
role = ::Permissions.find_role_by_name(value)
|
8
|
+
record.errors.add attr, options[:message] if role.nil?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :validates_role, :validates_role_name
|
13
|
+
|
14
|
+
def has_role(options = {})
|
15
|
+
|
16
|
+
if options[:name_accessor]
|
17
|
+
options[:name_reader] = "#{options[:name_accessor]}"
|
18
|
+
options[:name_writer] = "#{options[:name_accessor]}="
|
19
|
+
options.delete(:name_accessor)
|
20
|
+
end
|
21
|
+
|
22
|
+
self.class_eval do
|
23
|
+
|
24
|
+
@aegis_role_name_reader = (options[:name_reader] || "role_name").to_sym
|
25
|
+
@aegis_role_name_writer = (options[:name_writer] || "role_name=").to_sym
|
26
|
+
|
27
|
+
def aegis_role_name_reader
|
28
|
+
self.class.class_eval{ @aegis_role_name_reader }
|
29
|
+
end
|
30
|
+
|
31
|
+
def aegis_role_name_writer
|
32
|
+
self.class.class_eval{ @aegis_role_name_writer }
|
33
|
+
end
|
34
|
+
|
35
|
+
def aegis_role_name
|
36
|
+
send(aegis_role_name_reader)
|
37
|
+
end
|
38
|
+
|
39
|
+
def aegis_role_name=(value)
|
40
|
+
send(aegis_role_name_writer, value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def role
|
44
|
+
::Permissions.find_role_by_name!(aegis_role_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def role=(role_or_name)
|
48
|
+
self.aegis_role_name = if role_or_name.is_a?(Aegis::Role)
|
49
|
+
role_or_name.name
|
50
|
+
else
|
51
|
+
role_or_name.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Delegate may_...? and may_...! methods to the user's role.
|
58
|
+
def method_missing_with_aegis_permissions(symb, *args)
|
59
|
+
method_name = symb.to_s
|
60
|
+
if method_name =~ /^may_(.+?)[\!\?]$/
|
61
|
+
role.send(symb, self, *args)
|
62
|
+
elsif method_name =~ /^(.*?)\?$/ && queried_role = ::Permissions.find_role_by_name($1)
|
63
|
+
role == queried_role
|
64
|
+
else
|
65
|
+
method_missing_without_aegis_permissions(symb, *args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
alias_method_chain :method_missing, :aegis_permissions
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Aegis
|
2
|
+
class Normalization
|
3
|
+
|
4
|
+
VERB_NORMALIZATIONS = {
|
5
|
+
"edit" => "update",
|
6
|
+
"show" => "read",
|
7
|
+
"list" => "read",
|
8
|
+
"view" => "read",
|
9
|
+
"delete" => "destroy",
|
10
|
+
"remove" => "destroy"
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.normalize_verb(verb)
|
14
|
+
VERB_NORMALIZATIONS[verb] || verb
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.normalize_permission(permission)
|
18
|
+
if permission =~ /^([^_]+?)_(.+?)$/
|
19
|
+
verb, target = $1, $2
|
20
|
+
permission = normalize_verb(verb) + "_" + target
|
21
|
+
end
|
22
|
+
permission
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Aegis
|
2
|
+
class PermissionEvaluator
|
3
|
+
|
4
|
+
def initialize(role)
|
5
|
+
@role = role
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(permissions, rule_args)
|
9
|
+
@result = @role.allow_by_default?
|
10
|
+
permissions.each do |permission|
|
11
|
+
instance_exec(*rule_args, &permission)
|
12
|
+
end
|
13
|
+
@result
|
14
|
+
end
|
15
|
+
|
16
|
+
def allow(*role_name_or_names, &block)
|
17
|
+
rule_encountered(role_name_or_names, true, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def deny(*role_name_or_names, &block)
|
21
|
+
rule_encountered(role_name_or_names, false, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def rule_encountered(role_name_or_names, is_allow, &block)
|
25
|
+
role_names = Array(role_name_or_names)
|
26
|
+
if role_names.include?(@role.name) || role_names.include?(Aegis::Constants::EVERYONE_ROLE_NAME)
|
27
|
+
@result = (block ? block.call : true)
|
28
|
+
@result = !@result unless is_allow
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Aegis
|
2
|
+
class Permissions
|
3
|
+
|
4
|
+
def self.inherited(base)
|
5
|
+
base.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
@@roles_by_name = {}
|
13
|
+
|
14
|
+
# Example: @@permission_blocks[:update_users] =
|
15
|
+
# [proc { allow :admin; deny :guest }, proc { deny :student }]
|
16
|
+
@@permission_blocks = Hash.new { |hash, key| hash[key] = [] }
|
17
|
+
|
18
|
+
def role(role_name, options = {})
|
19
|
+
role_name = role_name.to_sym
|
20
|
+
role_name != Aegis::Constants::EVERYONE_ROLE_NAME or raise "Cannot define a role named: #{Aegis::Constants::EVERYONE_ROLE_NAME}"
|
21
|
+
@@roles_by_name[role_name] = Aegis::Role.new(role_name, self, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_all_role_names
|
25
|
+
@@roles_by_name.keys
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_all_roles
|
29
|
+
@@roles_by_name.values.sort
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_role_by_name(name)
|
33
|
+
# cannot call :to_sym on nil or an empty string
|
34
|
+
if name.blank?
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
@@roles_by_name[name.to_sym]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_role_by_name!(name)
|
42
|
+
find_role_by_name(name) or raise "Undefined role: #{name}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def permission(*permission_name_or_names, &block)
|
46
|
+
permission_names = Array(permission_name_or_names).map(&:to_s)
|
47
|
+
permission_names.each do |permission_name|
|
48
|
+
add_split_crud_permission(permission_name, &block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def may?(role_or_role_name, permission, *args)
|
53
|
+
role = role_or_role_name.is_a?(Aegis::Role) ? role_or_role_name : find_role_by_name(role_or_role_name)
|
54
|
+
blocks = @@permission_blocks[permission.to_sym]
|
55
|
+
evaluate_permission_blocks(role, blocks, *args)
|
56
|
+
end
|
57
|
+
|
58
|
+
def evaluate_permission_blocks(role, blocks, *args)
|
59
|
+
evaluator = Aegis::PermissionEvaluator.new(role)
|
60
|
+
evaluator.evaluate(blocks, args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def denied?(*args)
|
64
|
+
!allowed?(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def add_split_crud_permission(permission_name, &block)
|
70
|
+
if permission_name =~ /^crud_(.+?)$/
|
71
|
+
target = $1
|
72
|
+
Aegis::Constants::CRUD_VERBS.each do |verb|
|
73
|
+
add_normalized_permission("#{verb}_#{target}", &block)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
add_normalized_permission(permission_name, &block)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_normalized_permission(permission_name, &block)
|
81
|
+
normalized_permission_name = Aegis::Normalization.normalize_permission(permission_name)
|
82
|
+
add_singularized_permission(normalized_permission_name, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_singularized_permission(permission_name, &block)
|
86
|
+
if permission_name =~ /^([^_]+?)_(.+?)$/
|
87
|
+
verb = $1
|
88
|
+
target = $2
|
89
|
+
singular_target = target.singularize
|
90
|
+
if singular_target.length < target.length
|
91
|
+
singular_block = lambda do |*args|
|
92
|
+
args.delete_at 1
|
93
|
+
instance_exec(*args, &block)
|
94
|
+
end
|
95
|
+
singular_permission_name = "#{verb}_#{singular_target}"
|
96
|
+
add_permission(singular_permission_name, &singular_block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
add_permission(permission_name, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_permission(permission_name, &block)
|
103
|
+
permission_name = permission_name.to_sym
|
104
|
+
@@permission_blocks[permission_name] << block
|
105
|
+
end
|
106
|
+
|
107
|
+
end # module ClassMethods
|
108
|
+
|
109
|
+
end # class Permissions
|
110
|
+
end # module Aegis
|
111
|
+
|
data/lib/aegis/role.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Aegis
|
2
|
+
class Role
|
3
|
+
|
4
|
+
attr_reader :name, :default_permission
|
5
|
+
|
6
|
+
# permissions is a hash like: permissions[:edit_user] = lambda { |user| ... }
|
7
|
+
def initialize(name, permissions, options)
|
8
|
+
@name = name
|
9
|
+
@permissions = permissions
|
10
|
+
@default_permission = options[:default_permission] == :allow ? :allow : :deny
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
def allow_by_default?
|
15
|
+
@default_permission == :allow
|
16
|
+
end
|
17
|
+
|
18
|
+
def may?(permission, *args)
|
19
|
+
# puts "may? #{permission}, #{args}"
|
20
|
+
@permissions.may?(self, permission, *args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
name.to_s <=> other.name.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
name.to_s.humanize
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
name.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def method_missing(symb, *args)
|
38
|
+
method_name = symb.to_s
|
39
|
+
if method_name =~ /^may_(.+)(\?|\!)$/
|
40
|
+
permission, severity = $1, $2
|
41
|
+
permission = Aegis::Normalization.normalize_permission(permission)
|
42
|
+
may = may?(permission, *args)
|
43
|
+
if severity == '!' && !may
|
44
|
+
raise PermissionError, "Access denied: #{permission}"
|
45
|
+
else
|
46
|
+
may
|
47
|
+
end
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/aegis.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class Permissions < Aegis::Permissions
|
3
|
+
|
4
|
+
role :guest
|
5
|
+
role :student
|
6
|
+
role :admin, :default_permission => :allow
|
7
|
+
|
8
|
+
permission :use_empty do
|
9
|
+
end
|
10
|
+
|
11
|
+
permission :use_simple do
|
12
|
+
allow :student
|
13
|
+
deny :admin
|
14
|
+
end
|
15
|
+
|
16
|
+
permission :update_users do
|
17
|
+
allow :student
|
18
|
+
deny :admin
|
19
|
+
end
|
20
|
+
|
21
|
+
permission :crud_projects do
|
22
|
+
allow :student
|
23
|
+
end
|
24
|
+
|
25
|
+
permission :edit_drinks do
|
26
|
+
allow :student
|
27
|
+
deny :admin
|
28
|
+
end
|
29
|
+
|
30
|
+
permission :hug do
|
31
|
+
allow :everyone
|
32
|
+
end
|
33
|
+
|
34
|
+
permission :divide do |user, left, right|
|
35
|
+
allow :student do
|
36
|
+
right != 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
permission :draw do
|
41
|
+
allow :everyone
|
42
|
+
end
|
43
|
+
|
44
|
+
permission :draw do
|
45
|
+
deny :student
|
46
|
+
deny :admin
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Allow customization of the rails framework path
|
2
|
+
RAILS_FRAMEWORK_ROOT = (ENV['RAILS_FRAMEWORK_ROOT'] || "#{File.dirname(__FILE__)}/../../../../../../vendor/rails") unless defined?(RAILS_FRAMEWORK_ROOT)
|
3
|
+
|
4
|
+
# Don't change this file!
|
5
|
+
# Configure your app in config/environment.rb and config/environments/*.rb
|
6
|
+
|
7
|
+
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
8
|
+
|
9
|
+
module Rails
|
10
|
+
class << self
|
11
|
+
def boot!
|
12
|
+
unless booted?
|
13
|
+
preinitialize
|
14
|
+
pick_boot.run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def booted?
|
19
|
+
defined? Rails::Initializer
|
20
|
+
end
|
21
|
+
|
22
|
+
def pick_boot
|
23
|
+
(vendor_rails? ? VendorBoot : GemBoot).new
|
24
|
+
end
|
25
|
+
|
26
|
+
def vendor_rails?
|
27
|
+
File.exist?(RAILS_FRAMEWORK_ROOT)
|
28
|
+
end
|
29
|
+
|
30
|
+
def preinitialize
|
31
|
+
load(preinitializer_path) if File.exist?(preinitializer_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def preinitializer_path
|
35
|
+
"#{RAILS_ROOT}/config/preinitializer.rb"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Boot
|
40
|
+
def run
|
41
|
+
load_initializer
|
42
|
+
Rails::Initializer.run(:set_load_path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class VendorBoot < Boot
|
47
|
+
def load_initializer
|
48
|
+
require "#{RAILS_FRAMEWORK_ROOT}/railties/lib/initializer"
|
49
|
+
Rails::Initializer.run(:install_gem_spec_stubs)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class GemBoot < Boot
|
54
|
+
def load_initializer
|
55
|
+
self.class.load_rubygems
|
56
|
+
load_rails_gem
|
57
|
+
require 'initializer'
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_rails_gem
|
61
|
+
if version = self.class.gem_version
|
62
|
+
gem 'rails', version
|
63
|
+
else
|
64
|
+
gem 'rails'
|
65
|
+
end
|
66
|
+
rescue Gem::LoadError => load_error
|
67
|
+
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
|
71
|
+
class << self
|
72
|
+
def rubygems_version
|
73
|
+
Gem::RubyGemsVersion rescue nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def gem_version
|
77
|
+
if defined? RAILS_GEM_VERSION
|
78
|
+
RAILS_GEM_VERSION
|
79
|
+
elsif ENV.include?('RAILS_GEM_VERSION')
|
80
|
+
ENV['RAILS_GEM_VERSION']
|
81
|
+
else
|
82
|
+
parse_gem_version(read_environment_rb)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def load_rubygems
|
87
|
+
require 'rubygems'
|
88
|
+
min_version = '1.1.1'
|
89
|
+
unless rubygems_version >= min_version
|
90
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
|
94
|
+
rescue LoadError
|
95
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
|
99
|
+
def parse_gem_version(text)
|
100
|
+
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def read_environment_rb
|
105
|
+
environment_rb = "#{RAILS_ROOT}/config/environment.rb"
|
106
|
+
environment_rb = "#{HELPER_RAILS_ROOT}/config/environment.rb" unless File.exists?(environment_rb)
|
107
|
+
File.read(environment_rb)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# All that for this:
|
114
|
+
Rails.boot!
|
@@ -0,0 +1,21 @@
|
|
1
|
+
in_memory:
|
2
|
+
adapter: sqlite3
|
3
|
+
database: ":memory:"
|
4
|
+
verbosity: quiet
|
5
|
+
sqlite:
|
6
|
+
adapter: sqlite
|
7
|
+
dbfile: plugin_test.sqlite.db
|
8
|
+
sqlite3:
|
9
|
+
adapter: sqlite3
|
10
|
+
dbfile: plugin_test.sqlite3.db
|
11
|
+
postgresql:
|
12
|
+
adapter: postgresql
|
13
|
+
username: postgres
|
14
|
+
password: postgres
|
15
|
+
database: plugin_test
|
16
|
+
mysql:
|
17
|
+
adapter: mysql
|
18
|
+
host: localhost
|
19
|
+
username: root
|
20
|
+
password:
|
21
|
+
database: plugin_test
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
2
|
+
|
3
|
+
Rails::Initializer.run do |config|
|
4
|
+
config.cache_classes = false
|
5
|
+
config.whiny_nils = true
|
6
|
+
config.action_controller.session = { :key => "_myapp_session", :secret => "gwirofjweroijger8924rt2zfwehfuiwehb1378rifowenfoqwphf23" }
|
7
|
+
config.plugin_locators.unshift(
|
8
|
+
Class.new(Rails::Plugin::Locator) do
|
9
|
+
def plugins
|
10
|
+
[Rails::Plugin.new(File.expand_path('.'))]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
) unless defined?(PluginTestHelper::PluginLocator)
|
14
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,4 @@
|
|
1
|
+
# Loads fixtures into the database when running the test app via the console
|
2
|
+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(Rails.root, '../fixtures/*.{yml,csv}'))).each do |fixture_file|
|
3
|
+
Fixtures.create_fixtures(File.join(Rails.root, '../fixtures'), File.basename(fixture_file, '.*'))
|
4
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "test/test_helper"
|
2
|
+
|
3
|
+
class HasRoleOptionsTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "A record with a custom role field" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@soldier = Soldier.new
|
9
|
+
end
|
10
|
+
|
11
|
+
should "allow its role to be written and read" do
|
12
|
+
@soldier.role = "guest"
|
13
|
+
assert "guest", @soldier.role.name
|
14
|
+
end
|
15
|
+
|
16
|
+
should "store the role name in the custom field" do
|
17
|
+
assert "guest", @soldier.rank
|
18
|
+
end
|
19
|
+
|
20
|
+
should "still work with permissions" do
|
21
|
+
@soldier.role = "guest"
|
22
|
+
assert @soldier.may_hug?
|
23
|
+
assert !@soldier.may_update_users?
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "test/test_helper"
|
2
|
+
|
3
|
+
class HasRoleTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "Objects that have an aegis role" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@guest = User.new(:role_name => "guest")
|
9
|
+
@student = User.new(:role_name => "student")
|
10
|
+
@admin = User.new(:role_name => "admin")
|
11
|
+
end
|
12
|
+
|
13
|
+
should "know their role" do
|
14
|
+
assert :guest, @guest.role.name
|
15
|
+
assert :student, @student.role.name
|
16
|
+
assert :admin, @admin.role.name
|
17
|
+
end
|
18
|
+
|
19
|
+
should "know if they belong to a role" do
|
20
|
+
assert @guest.guest?
|
21
|
+
assert !@guest.student?
|
22
|
+
assert !@guest.admin?
|
23
|
+
assert !@student.guest?
|
24
|
+
assert @student.student?
|
25
|
+
assert !@student.admin?
|
26
|
+
assert !@admin.guest?
|
27
|
+
assert !@admin.student?
|
28
|
+
assert @admin.admin?
|
29
|
+
end
|
30
|
+
|
31
|
+
should "still behave as usual when a method ending in a '?' does not map to a role query" do
|
32
|
+
assert_raise NoMethodError do
|
33
|
+
@guest.nonexisting_method?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "test/test_helper"
|
2
|
+
|
3
|
+
class PermissionsTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "Aegis permissions" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@guest = User.new(:role_name => "guest")
|
9
|
+
@student = User.new(:role_name => "student")
|
10
|
+
@admin = User.new(:role_name => "admin")
|
11
|
+
end
|
12
|
+
|
13
|
+
should "use the default permission for actions without any allow or grant directives" do
|
14
|
+
assert !@guest.may_use_empty?
|
15
|
+
assert !@student.may_use_empty?
|
16
|
+
assert @admin.may_use_empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
should "understand simple allow and deny directives" do
|
20
|
+
assert !@guest.may_use_simple?
|
21
|
+
assert @student.may_use_simple?
|
22
|
+
assert !@admin.may_use_simple?
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'raise exceptions when a denied action is queried with an exclamation mark' do
|
26
|
+
assert_raise Aegis::PermissionError do
|
27
|
+
@guest.may_use_simple!
|
28
|
+
end
|
29
|
+
assert_raise Aegis::PermissionError do
|
30
|
+
@admin.may_use_simple!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'do nothing if an allowed action is queried with an exclamation mark' do
|
35
|
+
assert_nothing_raised do
|
36
|
+
@student.may_use_simple!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
should "implicate the singular form of an action described in plural form" do
|
41
|
+
assert !@guest.may_update_users?
|
42
|
+
assert !@guest.may_update_user?("foo")
|
43
|
+
assert @student.may_update_users?
|
44
|
+
assert @student.may_update_user?("foo")
|
45
|
+
assert !@admin.may_update_users?
|
46
|
+
assert !@admin.may_update_user?("foo")
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'implicate create, read, update and destroy forms for actions named "crud_..."' do
|
50
|
+
assert @student.may_create_projects?
|
51
|
+
assert @student.may_read_projects?
|
52
|
+
assert @student.may_update_projects?
|
53
|
+
assert @student.may_destroy_projects?
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'perform normalization of CRUD verbs (e.g. "edit" and "update")' do
|
57
|
+
assert !@guest.may_edit_drinks?
|
58
|
+
assert @student.may_edit_drinks?
|
59
|
+
assert !@admin.may_edit_drinks?
|
60
|
+
assert !@guest.may_update_drinks?
|
61
|
+
assert @student.may_update_drinks?
|
62
|
+
assert !@admin.may_update_drinks?
|
63
|
+
end
|
64
|
+
|
65
|
+
should "be able to grant or deny actions to all roles using :everyone" do
|
66
|
+
assert @guest.may_hug?
|
67
|
+
assert @student.may_hug?
|
68
|
+
assert @admin.may_hug?
|
69
|
+
end
|
70
|
+
|
71
|
+
should "allow the definition of parametrized actions" do
|
72
|
+
assert !@guest.may_divide?(10, 2)
|
73
|
+
assert @student.may_divide?(10, 2)
|
74
|
+
assert !@student.may_divide?(10, 0)
|
75
|
+
assert @admin.may_divide?(10, 2)
|
76
|
+
assert @admin.may_divide?(10, 0)
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'use default permissions for undefined actions' do
|
80
|
+
!@student.may_do_undefined_stuff?("foo")
|
81
|
+
@admin.may_do_undefined_stuff?("foo")
|
82
|
+
end
|
83
|
+
|
84
|
+
should 'overshadow previous action definitions with the same name' do
|
85
|
+
assert @guest.may_draw?
|
86
|
+
assert !@student.may_draw?
|
87
|
+
assert !@admin.may_draw?
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Set the default environment to sqlite3's in_memory database
|
2
|
+
ENV['RAILS_ENV'] ||= 'in_memory'
|
3
|
+
|
4
|
+
# Load the Rails environment and testing framework
|
5
|
+
require "#{File.dirname(__FILE__)}/app_root/config/environment"
|
6
|
+
require "#{File.dirname(__FILE__)}/../lib/aegis"
|
7
|
+
require 'test_help'
|
8
|
+
require 'action_view/test_case' # Load additional test classes not done automatically by < Rails 2.2.2
|
9
|
+
|
10
|
+
require "shoulda"
|
11
|
+
|
12
|
+
# Undo changes to RAILS_ENV
|
13
|
+
silence_warnings {RAILS_ENV = ENV['RAILS_ENV']}
|
14
|
+
|
15
|
+
# Run the migrations
|
16
|
+
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
17
|
+
|
18
|
+
# Set default fixture loading properties
|
19
|
+
ActiveSupport::TestCase.class_eval do
|
20
|
+
self.use_transactional_fixtures = true
|
21
|
+
self.use_instantiated_fixtures = false
|
22
|
+
self.fixture_path = "#{File.dirname(__FILE__)}/fixtures"
|
23
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "test/test_helper"
|
2
|
+
|
3
|
+
class ValidationTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "A model that has and validates its role" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@user = User.new()
|
9
|
+
end
|
10
|
+
|
11
|
+
context "that has a role_name mapping to a role" do
|
12
|
+
|
13
|
+
setup do
|
14
|
+
@user.role_name = "admin"
|
15
|
+
end
|
16
|
+
|
17
|
+
should "be valid" do
|
18
|
+
assert @user.valid?
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
context "that has a blank role_name" do
|
24
|
+
|
25
|
+
setup do
|
26
|
+
@user.role_name = ""
|
27
|
+
end
|
28
|
+
|
29
|
+
should "not be valid" do
|
30
|
+
assert !@user.valid?
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
context "that has a role_name not mapping to a role" do
|
36
|
+
|
37
|
+
setup do
|
38
|
+
@user.role_name = "nonexisting_role_name"
|
39
|
+
end
|
40
|
+
|
41
|
+
should "not be valid" do
|
42
|
+
assert !@user.valid?
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: makandra-aegis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Henning Koch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-29 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Aegis is a role-based permission system, where all users are given a role. It is possible to define detailed and complex permissions for each role very easily.
|
17
|
+
email: github@makandra.de
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- aegis.gemspec
|
31
|
+
- lib/aegis.rb
|
32
|
+
- lib/aegis/constants.rb
|
33
|
+
- lib/aegis/has_role.rb
|
34
|
+
- lib/aegis/normalization.rb
|
35
|
+
- lib/aegis/permission_error.rb
|
36
|
+
- lib/aegis/permission_evaluator.rb
|
37
|
+
- lib/aegis/permissions.rb
|
38
|
+
- lib/aegis/role.rb
|
39
|
+
- lib/rails/active_record.rb
|
40
|
+
- test/app_root/app/controllers/application_controller.rb
|
41
|
+
- test/app_root/app/models/permissions.rb
|
42
|
+
- test/app_root/app/models/soldier.rb
|
43
|
+
- test/app_root/app/models/user.rb
|
44
|
+
- test/app_root/config/boot.rb
|
45
|
+
- test/app_root/config/database.yml
|
46
|
+
- test/app_root/config/environment.rb
|
47
|
+
- test/app_root/config/environments/in_memory.rb
|
48
|
+
- test/app_root/config/environments/mysql.rb
|
49
|
+
- test/app_root/config/environments/postgresql.rb
|
50
|
+
- test/app_root/config/environments/sqlite.rb
|
51
|
+
- test/app_root/config/environments/sqlite3.rb
|
52
|
+
- test/app_root/config/routes.rb
|
53
|
+
- test/app_root/db/migrate/20090408115228_create_users.rb
|
54
|
+
- test/app_root/db/migrate/20090429075648_create_soldiers.rb
|
55
|
+
- test/app_root/lib/console_with_fixtures.rb
|
56
|
+
- test/app_root/log/.gitignore
|
57
|
+
- test/app_root/script/console
|
58
|
+
- test/has_role_options_test.rb
|
59
|
+
- test/has_role_test.rb
|
60
|
+
- test/permissions_test.rb
|
61
|
+
- test/test_helper.rb
|
62
|
+
- test/validation_test.rb
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/makandra/aegis
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options:
|
67
|
+
- --charset=UTF-8
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.2.0
|
86
|
+
signing_key:
|
87
|
+
specification_version: 2
|
88
|
+
summary: Role-based permissions for your user models.
|
89
|
+
test_files:
|
90
|
+
- test/app_root/app/models/permissions.rb
|
91
|
+
- test/app_root/app/models/soldier.rb
|
92
|
+
- test/app_root/app/models/user.rb
|
93
|
+
- test/app_root/app/controllers/application_controller.rb
|
94
|
+
- test/app_root/config/environment.rb
|
95
|
+
- test/app_root/config/environments/mysql.rb
|
96
|
+
- test/app_root/config/environments/postgresql.rb
|
97
|
+
- test/app_root/config/environments/sqlite3.rb
|
98
|
+
- test/app_root/config/environments/in_memory.rb
|
99
|
+
- test/app_root/config/environments/sqlite.rb
|
100
|
+
- test/app_root/config/boot.rb
|
101
|
+
- test/app_root/config/routes.rb
|
102
|
+
- test/app_root/db/migrate/20090429075648_create_soldiers.rb
|
103
|
+
- test/app_root/db/migrate/20090408115228_create_users.rb
|
104
|
+
- test/app_root/lib/console_with_fixtures.rb
|
105
|
+
- test/validation_test.rb
|
106
|
+
- test/test_helper.rb
|
107
|
+
- test/has_role_options_test.rb
|
108
|
+
- test/has_role_test.rb
|
109
|
+
- test/permissions_test.rb
|