thelinuxlich-aegis 1.1.7

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 (46) hide show
  1. data/.gitignore +3 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +195 -0
  4. data/Rakefile +37 -0
  5. data/VERSION +1 -0
  6. data/aegis.gemspec +107 -0
  7. data/lib/aegis.rb +10 -0
  8. data/lib/aegis/constants.rb +7 -0
  9. data/lib/aegis/has_role.rb +110 -0
  10. data/lib/aegis/normalization.rb +26 -0
  11. data/lib/aegis/permission_error.rb +5 -0
  12. data/lib/aegis/permission_evaluator.rb +34 -0
  13. data/lib/aegis/permissions.rb +107 -0
  14. data/lib/aegis/role.rb +55 -0
  15. data/lib/rails/active_record.rb +5 -0
  16. data/test/app_root/app/controllers/application_controller.rb +2 -0
  17. data/test/app_root/app/models/old_soldier.rb +6 -0
  18. data/test/app_root/app/models/permissions.rb +49 -0
  19. data/test/app_root/app/models/soldier.rb +5 -0
  20. data/test/app_root/app/models/trust_fund_kid.rb +5 -0
  21. data/test/app_root/app/models/user.rb +6 -0
  22. data/test/app_root/app/models/user_subclass.rb +2 -0
  23. data/test/app_root/app/models/veteran_soldier.rb +6 -0
  24. data/test/app_root/config/boot.rb +114 -0
  25. data/test/app_root/config/database.yml +21 -0
  26. data/test/app_root/config/environment.rb +14 -0
  27. data/test/app_root/config/environments/in_memory.rb +0 -0
  28. data/test/app_root/config/environments/mysql.rb +0 -0
  29. data/test/app_root/config/environments/postgresql.rb +0 -0
  30. data/test/app_root/config/environments/sqlite.rb +0 -0
  31. data/test/app_root/config/environments/sqlite3.rb +0 -0
  32. data/test/app_root/config/routes.rb +4 -0
  33. data/test/app_root/db/migrate/20090408115228_create_users.rb +14 -0
  34. data/test/app_root/db/migrate/20090429075648_create_soldiers.rb +14 -0
  35. data/test/app_root/db/migrate/20091110075648_create_veteran_soldiers.rb +14 -0
  36. data/test/app_root/db/migrate/20091110075649_create_trust_fund_kids.rb +15 -0
  37. data/test/app_root/lib/console_with_fixtures.rb +4 -0
  38. data/test/app_root/log/.gitignore +1 -0
  39. data/test/app_root/script/console +7 -0
  40. data/test/has_role_options_test.rb +64 -0
  41. data/test/has_role_test.rb +54 -0
  42. data/test/permissions_test.rb +109 -0
  43. data/test/test_helper.rb +23 -0
  44. data/test/validation_test.rb +55 -0
  45. data/thelinuxlich-aegis.gemspec +109 -0
  46. metadata +131 -0
@@ -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,5 @@
1
+ module Aegis
2
+ class PermissionError < StandardError
3
+
4
+ end
5
+ 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,107 @@
1
+ module Aegis
2
+ class Permissions
3
+
4
+ def self.inherited(base)
5
+ base.class_eval do
6
+ @roles_by_name = {}
7
+ @permission_blocks = Hash.new { |hash, key| hash[key] = [] }
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def role(role_name, options = {})
15
+ role_name = role_name.to_sym
16
+ role_name != Aegis::Constants::EVERYONE_ROLE_NAME or raise "Cannot define a role named: #{Aegis::Constants::EVERYONE_ROLE_NAME}"
17
+ @roles_by_name[role_name] = Aegis::Role.new(role_name, self, options)
18
+ end
19
+
20
+ def find_all_role_names
21
+ @roles_by_name.keys
22
+ end
23
+
24
+ def find_all_roles
25
+ @roles_by_name.values.sort
26
+ end
27
+
28
+ def find_role_by_name(name)
29
+ # cannot call :to_sym on nil or an empty string
30
+ if name.blank?
31
+ nil
32
+ else
33
+ @roles_by_name[name.to_sym]
34
+ end
35
+ end
36
+
37
+ def find_role_by_name!(name)
38
+ find_role_by_name(name) or raise "Undefined role: #{name}"
39
+ end
40
+
41
+ def permission(*permission_name_or_names, &block)
42
+ permission_names = Array(permission_name_or_names).map(&:to_s)
43
+ permission_names.each do |permission_name|
44
+ add_split_crud_permission(permission_name, &block)
45
+ end
46
+ end
47
+
48
+ define_method "#{Aegis::Constants::PERMISSION_PREFIX}?" do |role_or_role_name, permission, *args|
49
+ role = role_or_role_name.is_a?(Aegis::Role) ? role_or_role_name : find_role_by_name(role_or_role_name)
50
+ blocks = @permission_blocks[permission.to_sym]
51
+ evaluate_permission_blocks(role, blocks, *args)
52
+ end
53
+
54
+ def evaluate_permission_blocks(role, blocks, *args)
55
+ evaluator = Aegis::PermissionEvaluator.new(role)
56
+ evaluator.evaluate(blocks, args)
57
+ end
58
+
59
+ def denied?(*args)
60
+ !allowed?(*args)
61
+ end
62
+
63
+ private
64
+
65
+ def add_split_crud_permission(permission_name, &block)
66
+ if permission_name =~ /^crud_(.+?)$/
67
+ target = $1
68
+ Aegis::Constants::CRUD_VERBS.each do |verb|
69
+ add_normalized_permission("#{verb}_#{target}", &block)
70
+ end
71
+ else
72
+ add_normalized_permission(permission_name, &block)
73
+ end
74
+ end
75
+
76
+ def add_normalized_permission(permission_name, &block)
77
+ normalized_permission_name = Aegis::Normalization.normalize_permission(permission_name)
78
+ add_singularized_permission(normalized_permission_name, &block)
79
+ end
80
+
81
+ def add_singularized_permission(permission_name, &block)
82
+ if permission_name =~ /^([^_]+?)_(.+?)$/
83
+ verb = $1
84
+ target = $2
85
+ singular_target = target.singularize
86
+ if singular_target.length < target.length
87
+ singular_block = lambda do |*args|
88
+ args.delete_at 1
89
+ instance_exec(*args, &block)
90
+ end
91
+ singular_permission_name = "#{verb}_#{singular_target}"
92
+ add_permission(singular_permission_name, &singular_block)
93
+ end
94
+ end
95
+ add_permission(permission_name, &block)
96
+ end
97
+
98
+ def add_permission(permission_name, &block)
99
+ permission_name = permission_name.to_sym
100
+ @permission_blocks[permission_name] << block
101
+ end
102
+
103
+ end # module ClassMethods
104
+
105
+ end # class Permissions
106
+ end # module Aegis
107
+
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
+ define_method "#{Aegis::Constants::PERMISSION_PREFIX}?" do |permission,*args|
19
+ # puts "may? #{permission}, #{args}"
20
+ @permissions.send "#{Aegis::Constants::PERMISSION_PREFIX}?",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 =~ /^#{Aegis::Constants::PERMISSION_PREFIX}_(.+)(\?|\!)$/
40
+ permission, severity = $1, $2
41
+ permission = Aegis::Normalization.normalize_permission(permission)
42
+ may = send "#{Aegis::Constants::PERMISSION_PREFIX}?", 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
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Base.class_eval do
2
+
3
+ extend Aegis::HasRole
4
+
5
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,6 @@
1
+ class VeteranSoldier < ActiveRecord::Base
2
+
3
+ # Use legacy parameter :name_accessor instead of :accessor
4
+ has_role :name_accessor => "rank"
5
+
6
+ end
@@ -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,5 @@
1
+ class Soldier < ActiveRecord::Base
2
+
3
+ has_role :accessor => "rank"
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ class TrustFundKid < ActiveRecord::Base
2
+
3
+ has_role :default => :admin
4
+
5
+ end
@@ -0,0 +1,6 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ has_role
4
+ validates_role_name
5
+
6
+ end
@@ -0,0 +1,2 @@
1
+ class UserSubclass < User
2
+ end
@@ -0,0 +1,6 @@
1
+ class VeteranSoldier < ActiveRecord::Base
2
+
3
+ # Using legacy parameter names
4
+ has_role :name_accessor => "rank"
5
+
6
+ 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!