cantango 0.8.5.1 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/README.textile +49 -28
- data/VERSION +1 -1
- data/cantango.gemspec +19 -15
- data/lib/cantango.rb +16 -0
- data/lib/cantango/ability/cache/key.rb +22 -6
- data/lib/cantango/configuration.rb +2 -2
- data/lib/cantango/configuration/adapters.rb +2 -3
- data/lib/cantango/configuration/debug.rb +25 -0
- data/lib/cantango/configuration/permits.rb +45 -2
- data/lib/cantango/configuration/registry.rb +1 -1
- data/lib/cantango/engine.rb +1 -1
- data/lib/cantango/permission_engine.rb +0 -1
- data/lib/cantango/permit_engine.rb +3 -1
- data/lib/cantango/permits/permit.rb +12 -5
- data/lib/cantango/rules.rb +1 -16
- data/spec/cantango/configuration/debug_spec.rb +68 -0
- data/spec/cantango/configuration/permits_spec.rb +60 -0
- metadata +54 -31
- data/spec/cantango/README.textile +0 -3
data/Gemfile
CHANGED
@@ -49,8 +49,8 @@ group :test do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
group :development, :test do
|
52
|
-
|
53
|
-
|
52
|
+
gem "rspec-rails", '>= 2.6.1' # needed in development to expose the rails generators
|
53
|
+
gem 'forgery', '>= 0.3' # needed in development when using rake db:seed
|
54
54
|
gem 'factory_girl'
|
55
55
|
|
56
56
|
# Adapters
|
data/README.textile
CHANGED
@@ -2,10 +2,10 @@ h1. CanTango
|
|
2
2
|
|
3
3
|
CanTango is an advanced Access Control (permissions) system for Rails 3. It:
|
4
4
|
|
5
|
-
* extends "CanCan":http://github.com/ryanb/cancan and offers a role oriented design
|
5
|
+
* extends "CanCan":http://github.com/ryanb/cancan and offers a more role oriented design
|
6
6
|
* integrates with _role_ and _authentication_ systems in a non-intrusive manner
|
7
|
-
* can _cache_ rules between requests for increased performance
|
8
|
-
* can _store_
|
7
|
+
* can _cache_ ability rules between requests for increased performance
|
8
|
+
* can _store_ abilites in a permission store, including a YAML file, for easy administration
|
9
9
|
* works well with multiple user accounts and sub applications
|
10
10
|
* supports multiple "Devise":https://github.com/plataformatec/devise users
|
11
11
|
|
@@ -37,15 +37,15 @@ Run bundler in a terminal/console from the folder of your Gemfile (root folder o
|
|
37
37
|
|
38
38
|
h2. Update Sept 1, 2011
|
39
39
|
|
40
|
-
Version *0.8.5* has been released.
|
40
|
+
Version *0.8.5.1* has been released.
|
41
41
|
|
42
|
-
CanTango now
|
42
|
+
CanTango now:
|
43
43
|
|
44
|
-
*
|
45
|
-
*
|
46
|
-
*
|
47
|
-
*
|
48
|
-
*
|
44
|
+
* supports "sugar-high 0.6":https://github.com/kristianmandrup/sugar-high.
|
45
|
+
* The ability cache has been refactored
|
46
|
+
* Activated engines are now run in specified order
|
47
|
+
* The ability cache rules compiler (for dynamic rules caching) and Moneta cache/store are now optional (enabled via adapters)
|
48
|
+
* Permits are found and loaded using pre-registration via inheritance. You can also use the _tango_permit_ macro for more control.
|
49
49
|
|
50
50
|
The wiki will soon be updated to reflect these improvements and changes.
|
51
51
|
|
@@ -73,14 +73,16 @@ h3. Rails 3 configuration
|
|
73
73
|
|
74
74
|
The CanTango "Configuration":https://github.com/kristianmandrup/cantango/wiki/Configuration consists of a nice DSL that let's you configure most of the things we imagine you would want to customize. Feel free to suggest more configuration options!
|
75
75
|
|
76
|
-
h3.
|
76
|
+
h3. Abilities via Permits and Permissions
|
77
77
|
|
78
|
-
|
78
|
+
Abilities are Access Control rules. With CanTango, these can be defined in both:
|
79
79
|
|
80
80
|
* "Permissions":https://github.com/kristianmandrup/cantango/wiki/Permissions (fx a yaml file)
|
81
81
|
* "Permits":https://github.com/kristianmandrup/cantango/wiki/Permits (special classes)
|
82
82
|
|
83
|
-
|
83
|
+
Note: For the simplest cases, you can define a @#permit_rules@ instance method directly in _CanTango::Ability_
|
84
|
+
|
85
|
+
Abilities can be defined for the following conceptual entities:
|
84
86
|
|
85
87
|
* User models
|
86
88
|
* User Account models
|
@@ -88,15 +90,44 @@ AC rules can be defined for the following conceptual entities:
|
|
88
90
|
* Role groups
|
89
91
|
* Users
|
90
92
|
|
93
|
+
h3. Debugging Abilities and Permits
|
94
|
+
|
95
|
+
Each Permit is in effect an Ability on its own. This lets you easily investigate which Permits allowed or denied a certain action for a specific ability candidate (typically a user or user account).
|
96
|
+
|
97
|
+
Debugging Example:
|
98
|
+
|
99
|
+
<pre>
|
100
|
+
# First you must enable debug mode
|
101
|
+
CanTango.debug!
|
102
|
+
|
103
|
+
# And have the permit engine execute at least once
|
104
|
+
user_can? :read, Article
|
105
|
+
|
106
|
+
# Then you can debug the permits execution
|
107
|
+
CanTango.permits_allowed current_user, :read, Article
|
108
|
+
|
109
|
+
admin_can? :read, Article
|
110
|
+
CanTango.permits_denied admin_user, :publish, [Article, Post]
|
111
|
+
CanTango.permits_allowed admin_user, :write, Article
|
112
|
+
|
113
|
+
CanTango.clear_executed_permits! # reset as if no permits have been executed
|
114
|
+
|
115
|
+
user_can? :publish, Article
|
116
|
+
CanTango.permits_denied current_user, [:write, publish], [Article, Post]
|
117
|
+
|
118
|
+
guest_account_can? :publish, Article
|
119
|
+
CanTango.permits_denied guest_account, :publish, [Article, Post], options
|
120
|
+
</pre>
|
121
|
+
|
91
122
|
h3. Design overview
|
92
123
|
|
93
|
-
The default CanTango
|
124
|
+
The default CanTango Ability pattern is simple.
|
94
125
|
|
95
|
-
1. Return cached rules for
|
126
|
+
1. Return cached ability rules for candidate if available
|
96
127
|
2. Generate rules for candidate
|
97
128
|
3. Cache rules for candidate
|
98
129
|
|
99
|
-
|
130
|
+
A candidate is typically either a user or an account instance.
|
100
131
|
|
101
132
|
Caching can be enabled or disabled. To generate the rules, one or more engines are executed.
|
102
133
|
|
@@ -141,18 +172,8 @@ If you encounter bugs, raise an issue or:
|
|
141
172
|
|
142
173
|
h2. Contributors
|
143
174
|
|
144
|
-
*Kristian Mandrup
|
145
|
-
|
146
|
-
- Designer of structure
|
147
|
-
- Feature ideas
|
148
|
-
- Initiator of project
|
149
|
-
- Devise app integration specs
|
150
|
-
|
151
|
-
"Stanislaw Pankevich":https://github.com/stanislaw
|
152
|
-
- Main contributor of permissions engine
|
153
|
-
- Caching of Procs for caching engine
|
154
|
-
- Lots of bug fixes and specs
|
155
|
-
- Tireless "worker" ;)
|
175
|
+
* Kristian Mandrup
|
176
|
+
* "Stanislaw Pankevich":https://github.com/stanislaw
|
156
177
|
|
157
178
|
h3. Copyright
|
158
179
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.6
|
data/cantango.gemspec
CHANGED
@@ -4,17 +4,14 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.8.
|
7
|
+
s.name = "cantango"
|
8
|
+
s.version = "0.8.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
|
15
|
-
Includes rules caching.
|
16
|
-
Store permissions in yaml file or key-value store}
|
17
|
-
s.email = %q{kmandrup@gmail.com, s.pankevich@gmail.com}
|
11
|
+
s.authors = ["Kristian Mandrup", "Stanislaw Pankevich"]
|
12
|
+
s.date = "2011-09-16"
|
13
|
+
s.description = "Define your permission rules as role- or role group specific permits.\nIntegrates well with multiple Devise user acounts.\nIncludes rules caching.\nStore permissions in yaml file or key-value store"
|
14
|
+
s.email = "kmandrup@gmail.com, s.pankevich@gmail.com"
|
18
15
|
s.extra_rdoc_files = [
|
19
16
|
"LICENSE.txt",
|
20
17
|
"README.textile"
|
@@ -71,6 +68,7 @@ Store permissions in yaml file or key-value store}
|
|
71
68
|
"lib/cantango/configuration/adapters.rb",
|
72
69
|
"lib/cantango/configuration/autoload.rb",
|
73
70
|
"lib/cantango/configuration/categories.rb",
|
71
|
+
"lib/cantango/configuration/debug.rb",
|
74
72
|
"lib/cantango/configuration/engines.rb",
|
75
73
|
"lib/cantango/configuration/engines/cache.rb",
|
76
74
|
"lib/cantango/configuration/engines/engine.rb",
|
@@ -274,7 +272,6 @@ Store permissions in yaml file or key-value store}
|
|
274
272
|
"spec/active_record/scenarios/user_accounts/permits/user_account_permit.rb",
|
275
273
|
"spec/active_record/scenarios/user_accounts/user_account_spec.rb",
|
276
274
|
"spec/active_record/spec_helper.rb",
|
277
|
-
"spec/cantango/README.textile",
|
278
275
|
"spec/cantango/ability/cache/key_spec.rb",
|
279
276
|
"spec/cantango/ability/cache/kompiler_spec.rb",
|
280
277
|
"spec/cantango/ability/cache/reader_compile_spec.rb",
|
@@ -300,6 +297,7 @@ Store permissions in yaml file or key-value store}
|
|
300
297
|
"spec/cantango/configuration/adapter_spec.rb",
|
301
298
|
"spec/cantango/configuration/autoload_spec.rb",
|
302
299
|
"spec/cantango/configuration/categories_spec.rb",
|
300
|
+
"spec/cantango/configuration/debug_spec.rb",
|
303
301
|
"spec/cantango/configuration/engines/cache_spec.rb",
|
304
302
|
"spec/cantango/configuration/engines/engine_shared.rb",
|
305
303
|
"spec/cantango/configuration/engines/permission_spec.rb",
|
@@ -634,11 +632,11 @@ Store permissions in yaml file or key-value store}
|
|
634
632
|
"wiki/when_to_use.markdown",
|
635
633
|
"wiki/why_to_use.markdown"
|
636
634
|
]
|
637
|
-
s.homepage =
|
638
|
-
s.licenses = [
|
639
|
-
s.require_paths = [
|
640
|
-
s.rubygems_version =
|
641
|
-
s.summary =
|
635
|
+
s.homepage = "http://github.com/kristianmandrup/cantango"
|
636
|
+
s.licenses = ["MIT"]
|
637
|
+
s.require_paths = ["lib"]
|
638
|
+
s.rubygems_version = "1.8.10"
|
639
|
+
s.summary = "CanCan extension with role oriented permission management and more"
|
642
640
|
|
643
641
|
if s.respond_to? :specification_version then
|
644
642
|
s.specification_version = 3
|
@@ -650,6 +648,8 @@ Store permissions in yaml file or key-value store}
|
|
650
648
|
s.add_runtime_dependency(%q<sweetloader>, ["~> 0.1.0"])
|
651
649
|
s.add_runtime_dependency(%q<sqlite3>, [">= 0"])
|
652
650
|
s.add_runtime_dependency(%q<hashie>, [">= 0.4"])
|
651
|
+
s.add_development_dependency(%q<rspec-rails>, [">= 2.6.1"])
|
652
|
+
s.add_development_dependency(%q<forgery>, [">= 0.3"])
|
653
653
|
s.add_development_dependency(%q<factory_girl>, [">= 0"])
|
654
654
|
s.add_development_dependency(%q<sourcify>, [">= 0"])
|
655
655
|
s.add_development_dependency(%q<dkastner-moneta>, [">= 1.0"])
|
@@ -664,6 +664,8 @@ Store permissions in yaml file or key-value store}
|
|
664
664
|
s.add_dependency(%q<sweetloader>, ["~> 0.1.0"])
|
665
665
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
666
666
|
s.add_dependency(%q<hashie>, [">= 0.4"])
|
667
|
+
s.add_dependency(%q<rspec-rails>, [">= 2.6.1"])
|
668
|
+
s.add_dependency(%q<forgery>, [">= 0.3"])
|
667
669
|
s.add_dependency(%q<factory_girl>, [">= 0"])
|
668
670
|
s.add_dependency(%q<sourcify>, [">= 0"])
|
669
671
|
s.add_dependency(%q<dkastner-moneta>, [">= 1.0"])
|
@@ -679,6 +681,8 @@ Store permissions in yaml file or key-value store}
|
|
679
681
|
s.add_dependency(%q<sweetloader>, ["~> 0.1.0"])
|
680
682
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
681
683
|
s.add_dependency(%q<hashie>, [">= 0.4"])
|
684
|
+
s.add_dependency(%q<rspec-rails>, [">= 2.6.1"])
|
685
|
+
s.add_dependency(%q<forgery>, [">= 0.3"])
|
682
686
|
s.add_dependency(%q<factory_girl>, [">= 0"])
|
683
687
|
s.add_dependency(%q<sourcify>, [">= 0"])
|
684
688
|
s.add_dependency(%q<dkastner-moneta>, [">= 1.0"])
|
data/lib/cantango.rb
CHANGED
@@ -22,6 +22,22 @@ module CanTango
|
|
22
22
|
end
|
23
23
|
|
24
24
|
alias_method :config, :configure
|
25
|
+
|
26
|
+
def permits_allowed candidate, actions, subjects, *extra_args
|
27
|
+
config.permits.allowed candidate, actions, subjects, *extra_args
|
28
|
+
end
|
29
|
+
|
30
|
+
def permits_denied candidate, actions, subjects, *extra_args
|
31
|
+
config.permits.denied candidate, actions, subjects, *extra_args
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear_permits_executed!
|
35
|
+
config.permits.clear_executed!
|
36
|
+
end
|
37
|
+
|
38
|
+
def debug!
|
39
|
+
config.debug.set :on
|
40
|
+
end
|
25
41
|
end
|
26
42
|
end
|
27
43
|
|
@@ -4,14 +4,18 @@ module CanTango
|
|
4
4
|
class Key
|
5
5
|
attr_reader :user, :subject
|
6
6
|
|
7
|
-
def initialize user, subject
|
7
|
+
def initialize user, subject = nil
|
8
8
|
@user = user
|
9
|
-
@subject = subject
|
9
|
+
@subject = subject || user
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create_for ability
|
13
|
+
self.new ability.user, ability.subject
|
10
14
|
end
|
11
15
|
|
12
16
|
def value
|
13
|
-
raise "
|
14
|
-
@value ||=
|
17
|
+
raise "No key could be generated for #{user} and #{subject}" if hash_values.empty?
|
18
|
+
@value ||= hash_values.hash
|
15
19
|
end
|
16
20
|
|
17
21
|
def same? session
|
@@ -21,8 +25,13 @@ module CanTango
|
|
21
25
|
|
22
26
|
protected
|
23
27
|
|
28
|
+
def hash_values
|
29
|
+
@hash_values ||= [user_key, subject_roles_hash].compact
|
30
|
+
end
|
31
|
+
|
24
32
|
def user_key
|
25
|
-
user.
|
33
|
+
# raise "#{user.class} must have a method ##{user_key_field}. You can configure this with CanTango.config#user.unique_key_field" if !user.respond_to?(user_key_field)
|
34
|
+
user.send(user_key_field) if user.respond_to? user_key_field
|
26
35
|
end
|
27
36
|
|
28
37
|
def user_key_field
|
@@ -30,7 +39,14 @@ module CanTango
|
|
30
39
|
end
|
31
40
|
|
32
41
|
def subject_roles_hash
|
33
|
-
|
42
|
+
role_hash_values.empty? ? nil : role_hash_values.hash
|
43
|
+
end
|
44
|
+
|
45
|
+
def role_hash_values
|
46
|
+
@role_hash_values ||= [:roles_list, :role_groups_list].inject([]) do |result, meth|
|
47
|
+
result << subject.send(meth) if subject.respond_to? meth
|
48
|
+
result
|
49
|
+
end
|
34
50
|
end
|
35
51
|
end
|
36
52
|
end
|
@@ -7,7 +7,7 @@ module CanTango
|
|
7
7
|
autoload_modules :Models, :Engines, :Ability
|
8
8
|
autoload_modules :User, :Guest, :UserAccount
|
9
9
|
autoload_modules :Roles, :RoleGroups, :Registry, :RoleRegistry, :HashRegistry, :PermitRegistry, :Factory
|
10
|
-
autoload_modules :SpecialPermits, :Autoload, :Adapters, :Permits
|
10
|
+
autoload_modules :SpecialPermits, :Autoload, :Adapters, :Permits, :Debug
|
11
11
|
autoload_modules :Users, :UserAccounts
|
12
12
|
|
13
13
|
include Singleton
|
@@ -21,7 +21,7 @@ module CanTango
|
|
21
21
|
def self.components
|
22
22
|
[
|
23
23
|
:guest, :autoload, :user, :user_account, :models, :roles, :role_groups,
|
24
|
-
:engines, :users, :user_accounts, :categories, :adapters, :permits
|
24
|
+
:engines, :users, :user_accounts, :categories, :adapters, :permits, :debug
|
25
25
|
]
|
26
26
|
end
|
27
27
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module CanTango
|
2
2
|
class Configuration
|
3
3
|
class Adapters < Registry
|
4
|
-
|
4
|
+
|
5
5
|
include Singleton
|
6
|
-
|
6
|
+
|
7
7
|
def adapter name
|
8
8
|
raise "Unknown adapter #{name}" if !available_adapters.include? name.to_sym
|
9
9
|
require "cantango/adapter/#{name}"
|
@@ -16,7 +16,6 @@ module CanTango
|
|
16
16
|
def available_adapters
|
17
17
|
[:moneta, :compiler]
|
18
18
|
end
|
19
|
-
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CanTango
|
2
|
+
class Configuration
|
3
|
+
# Note: This config feature is currently not used, but could potentially be of use in the future
|
4
|
+
class Debug
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def set state = :on
|
8
|
+
raise ArgumentError, "Must be :on or :off" unless !state || [:on, :off].include?(state)
|
9
|
+
@state = state || :on
|
10
|
+
end
|
11
|
+
|
12
|
+
def on?
|
13
|
+
@state == :on
|
14
|
+
end
|
15
|
+
|
16
|
+
def off?
|
17
|
+
!on?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -1,10 +1,9 @@
|
|
1
1
|
module CanTango
|
2
|
-
class Configuration
|
2
|
+
class Configuration
|
3
3
|
class Permits < PermitRegistry
|
4
4
|
include Singleton
|
5
5
|
|
6
6
|
attr_reader :accounts
|
7
|
-
# CanTango.config.permits.accounts[:admin].role => {}
|
8
7
|
|
9
8
|
def accounts
|
10
9
|
@accounts ||= Hash.new
|
@@ -22,6 +21,50 @@ module CanTango
|
|
22
21
|
registry = account_name ? self.send(account_name.to_sym) : self
|
23
22
|
registry.send(permit_type)[permit_name] = permit_clazz
|
24
23
|
end
|
24
|
+
|
25
|
+
def allowed candidate, actions, subjects, *extra_args
|
26
|
+
executed_for(candidate).inject([]) do |result, permit|
|
27
|
+
result << permit.class if permit.can? actions, subjects, *extra_args
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def denied candidate, actions, subjects, *extra_args
|
33
|
+
executed_for(candidate).inject([]) do |result, permit|
|
34
|
+
result << permit.class if permit.cannot? actions, subjects, *extra_args
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def was_executed permit, ability
|
40
|
+
executed_for(ability) << permit
|
41
|
+
end
|
42
|
+
|
43
|
+
def executed_for ability
|
44
|
+
executed[hash_key_for(ability)] ||= []
|
45
|
+
end
|
46
|
+
|
47
|
+
def executed
|
48
|
+
@executed ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def clear_executed!
|
52
|
+
@executed = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def hash_key_for subject
|
58
|
+
key_for(subject).value
|
59
|
+
end
|
60
|
+
|
61
|
+
def key_for subject
|
62
|
+
subject.kind_of?(CanTango::Ability) ? key_maker.create_for(subject) : key_maker.new(subject)
|
63
|
+
end
|
64
|
+
|
65
|
+
def key_maker
|
66
|
+
CanTango::Ability::Cache::Key
|
67
|
+
end
|
25
68
|
end
|
26
69
|
end
|
27
70
|
end
|
data/lib/cantango/engine.rb
CHANGED
@@ -8,7 +8,9 @@ module CanTango
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute!
|
11
|
+
# CanTango.config.permits.clear_executed! # should there be an option clear before each execution?
|
11
12
|
permits.each do |permit|
|
13
|
+
CanTango.config.permits.was_executed(permit, ability) if CanTango.config.debug.on?
|
12
14
|
break if permit.execute == :break
|
13
15
|
end
|
14
16
|
end
|
@@ -17,7 +19,7 @@ module CanTango
|
|
17
19
|
# has a role or a role group
|
18
20
|
# also execute any permit marked as special
|
19
21
|
def permits
|
20
|
-
permit_factory.build!
|
22
|
+
@permits ||= permit_factory.build!
|
21
23
|
end
|
22
24
|
|
23
25
|
def permit_class_names
|
@@ -30,12 +30,14 @@ module CanTango
|
|
30
30
|
# executes the permit
|
31
31
|
def execute
|
32
32
|
executor.execute!
|
33
|
+
ability_sync!
|
33
34
|
end
|
34
35
|
|
35
36
|
def category label
|
36
37
|
config.models.by_category label
|
37
38
|
end
|
38
39
|
|
40
|
+
|
39
41
|
def any reg_exp
|
40
42
|
config.models.by_reg_exp reg_exp
|
41
43
|
end
|
@@ -72,11 +74,16 @@ module CanTango
|
|
72
74
|
ability.user_account
|
73
75
|
end
|
74
76
|
|
75
|
-
def
|
76
|
-
ability.send
|
77
|
+
def ability_rules
|
78
|
+
ability.send(:rules)
|
79
|
+
end
|
80
|
+
|
81
|
+
def ability_sync!
|
82
|
+
ability_rules << (rules - ability_rules)
|
83
|
+
ability_rules.flatten!
|
77
84
|
end
|
78
85
|
|
79
|
-
# In a specific Role based Permit you can use
|
86
|
+
# In a specific Role based Permit you can use
|
80
87
|
# def permit? user, options = {}
|
81
88
|
# return if !super(user, :in_role)
|
82
89
|
# ... permission logic follows
|
@@ -103,7 +110,7 @@ module CanTango
|
|
103
110
|
end
|
104
111
|
end
|
105
112
|
|
106
|
-
include CanTango::Rules
|
113
|
+
include CanTango::Rules # also makes a Permit a subclass of CanCan::Ability
|
107
114
|
|
108
115
|
protected
|
109
116
|
|
@@ -117,7 +124,7 @@ module CanTango
|
|
117
124
|
raise "License #{clazz} could not be enforced using #{self.inspect}"
|
118
125
|
end
|
119
126
|
|
120
|
-
# This method will contain the actual rules
|
127
|
+
# This method will contain the actual rules
|
121
128
|
# can be implemented in the subclass
|
122
129
|
|
123
130
|
def permit_rules
|
data/lib/cantango/rules.rb
CHANGED
@@ -3,21 +3,6 @@ module CanTango
|
|
3
3
|
autoload_modules :Adaptor, :UserRelation, :Dsl, :Scope, :RuleClass
|
4
4
|
|
5
5
|
include Dsl
|
6
|
-
include
|
7
|
-
# Examples:
|
8
|
-
# can :read, Project
|
9
|
-
# can [:read, :create], [Project, Post]
|
10
|
-
# can :read, Project, :active => true, :user_id => user.id
|
11
|
-
def can(action, subject, conditions = nil, &block)
|
12
|
-
rules << rule_class.new(true, action, subject, conditions, block)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Examples:
|
16
|
-
# cannot :read, Project
|
17
|
-
# cannot [:read, :create], [Project, Post]
|
18
|
-
# cannot :read, Project, :active => true, :user_id => user.id
|
19
|
-
def cannot(action, subject, conditions = nil, &block)
|
20
|
-
rules << rule_class.new(false, action, subject, conditions, block)
|
21
|
-
end
|
6
|
+
include CanCan::Ability
|
22
7
|
end
|
23
8
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Menu
|
4
|
+
end
|
5
|
+
|
6
|
+
class WaiterRolePermit < CanTango::RolePermit
|
7
|
+
def initialize ability
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def permit_rules
|
14
|
+
can :read, Menu
|
15
|
+
cannot :write, Menu
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ChefRolePermit < CanTango::RolePermit
|
20
|
+
def initialize ability
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def permit_rules
|
27
|
+
can :publish, Menu
|
28
|
+
can :write, Menu
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Context
|
33
|
+
include CanTango::Api::User::Ability
|
34
|
+
end
|
35
|
+
|
36
|
+
# Note: This config feature is currently not used, but could potentially be of use in the future
|
37
|
+
describe CanTango::Configuration::Debug do
|
38
|
+
let(:context) { Context.new }
|
39
|
+
subject { CanTango.config.debug }
|
40
|
+
|
41
|
+
describe 'should set debug mode :on' do
|
42
|
+
before do
|
43
|
+
subject.set :on
|
44
|
+
end
|
45
|
+
|
46
|
+
its(:on?) { should be_true }
|
47
|
+
its(:off?) { should be_false }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'should set debug mode :off' do
|
51
|
+
before do
|
52
|
+
subject.set :on
|
53
|
+
end
|
54
|
+
|
55
|
+
its(:on?) { should be_true }
|
56
|
+
its(:off?) { should be_false }
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'debug! should set debug mode :on' do
|
60
|
+
before do
|
61
|
+
CanTango.debug!
|
62
|
+
end
|
63
|
+
|
64
|
+
its(:on?) { should be_true }
|
65
|
+
its(:off?) { should be_false }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -1,5 +1,38 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
class Menu
|
4
|
+
end
|
5
|
+
|
6
|
+
class WaiterRolePermit < CanTango::RolePermit
|
7
|
+
def initialize ability
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def permit_rules
|
14
|
+
can :read, Menu
|
15
|
+
cannot :write, Menu
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ChefRolePermit < CanTango::RolePermit
|
20
|
+
def initialize ability
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def permit_rules
|
27
|
+
can :publish, Menu
|
28
|
+
can :write, Menu
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Context
|
33
|
+
include CanTango::Api::User::Ability
|
34
|
+
end
|
35
|
+
|
3
36
|
describe CanTango::Configuration::Permits do
|
4
37
|
before do
|
5
38
|
@permit_registry = CanTango::Configuration::Permits.instance
|
@@ -22,4 +55,31 @@ describe CanTango::Configuration::Permits do
|
|
22
55
|
end
|
23
56
|
end
|
24
57
|
end
|
58
|
+
|
59
|
+
describe 'debugging permits' do
|
60
|
+
let(:context) { Context.new }
|
61
|
+
let (:user) do
|
62
|
+
User.new 'kris', 'kris@gmail.com', :role => :waiter
|
63
|
+
end
|
64
|
+
|
65
|
+
before do
|
66
|
+
CanTango.config.debug.set :on
|
67
|
+
context.user_ability(user).can? :read, Menu
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'should tell which permits allowe :read' do
|
71
|
+
it 'should show WaiterRolePermit as the permit that allowed :read of Menu' do
|
72
|
+
CanTango.permits_allowed(user, :read, Menu).should include(WaiterRolePermit)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'should tell which permits denied :write' do
|
77
|
+
it 'should show WaiterRolePermit as the permit that denied :write of Menu' do
|
78
|
+
CanTango.permits_denied(user, :write, Menu).should include(WaiterRolePermit)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
25
82
|
end
|
83
|
+
|
84
|
+
|
85
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cantango
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-09-
|
13
|
+
date: 2011-09-16 00:00:00.000000000Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &2158759980 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.0.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2158759980
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: cancan
|
28
|
-
requirement: &
|
28
|
+
requirement: &2158759180 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '1.4'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2158759180
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: sugar-high
|
39
|
-
requirement: &
|
39
|
+
requirement: &2158752840 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 0.6.0
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2158752840
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: sweetloader
|
50
|
-
requirement: &
|
50
|
+
requirement: &2158751900 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ~>
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: 0.1.0
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *2158751900
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: sqlite3
|
61
|
-
requirement: &
|
61
|
+
requirement: &2158749860 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *2158749860
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: hashie
|
72
|
-
requirement: &
|
72
|
+
requirement: &2158748240 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,10 +77,32 @@ dependencies:
|
|
77
77
|
version: '0.4'
|
78
78
|
type: :runtime
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *2158748240
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec-rails
|
83
|
+
requirement: &2158734040 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 2.6.1
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *2158734040
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: forgery
|
94
|
+
requirement: &2158732460 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0.3'
|
100
|
+
type: :development
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: *2158732460
|
81
103
|
- !ruby/object:Gem::Dependency
|
82
104
|
name: factory_girl
|
83
|
-
requirement: &
|
105
|
+
requirement: &2158729700 !ruby/object:Gem::Requirement
|
84
106
|
none: false
|
85
107
|
requirements:
|
86
108
|
- - ! '>='
|
@@ -88,10 +110,10 @@ dependencies:
|
|
88
110
|
version: '0'
|
89
111
|
type: :development
|
90
112
|
prerelease: false
|
91
|
-
version_requirements: *
|
113
|
+
version_requirements: *2158729700
|
92
114
|
- !ruby/object:Gem::Dependency
|
93
115
|
name: sourcify
|
94
|
-
requirement: &
|
116
|
+
requirement: &2158728640 !ruby/object:Gem::Requirement
|
95
117
|
none: false
|
96
118
|
requirements:
|
97
119
|
- - ! '>='
|
@@ -99,10 +121,10 @@ dependencies:
|
|
99
121
|
version: '0'
|
100
122
|
type: :development
|
101
123
|
prerelease: false
|
102
|
-
version_requirements: *
|
124
|
+
version_requirements: *2158728640
|
103
125
|
- !ruby/object:Gem::Dependency
|
104
126
|
name: dkastner-moneta
|
105
|
-
requirement: &
|
127
|
+
requirement: &2158727540 !ruby/object:Gem::Requirement
|
106
128
|
none: false
|
107
129
|
requirements:
|
108
130
|
- - ! '>='
|
@@ -110,10 +132,10 @@ dependencies:
|
|
110
132
|
version: '1.0'
|
111
133
|
type: :development
|
112
134
|
prerelease: false
|
113
|
-
version_requirements: *
|
135
|
+
version_requirements: *2158727540
|
114
136
|
- !ruby/object:Gem::Dependency
|
115
137
|
name: rspec
|
116
|
-
requirement: &
|
138
|
+
requirement: &2158726640 !ruby/object:Gem::Requirement
|
117
139
|
none: false
|
118
140
|
requirements:
|
119
141
|
- - ! '>='
|
@@ -121,10 +143,10 @@ dependencies:
|
|
121
143
|
version: 2.4.0
|
122
144
|
type: :development
|
123
145
|
prerelease: false
|
124
|
-
version_requirements: *
|
146
|
+
version_requirements: *2158726640
|
125
147
|
- !ruby/object:Gem::Dependency
|
126
148
|
name: jeweler
|
127
|
-
requirement: &
|
149
|
+
requirement: &2158725840 !ruby/object:Gem::Requirement
|
128
150
|
none: false
|
129
151
|
requirements:
|
130
152
|
- - ! '>='
|
@@ -132,10 +154,10 @@ dependencies:
|
|
132
154
|
version: 1.6.4
|
133
155
|
type: :development
|
134
156
|
prerelease: false
|
135
|
-
version_requirements: *
|
157
|
+
version_requirements: *2158725840
|
136
158
|
- !ruby/object:Gem::Dependency
|
137
159
|
name: bundler
|
138
|
-
requirement: &
|
160
|
+
requirement: &2158724960 !ruby/object:Gem::Requirement
|
139
161
|
none: false
|
140
162
|
requirements:
|
141
163
|
- - ! '>='
|
@@ -143,10 +165,10 @@ dependencies:
|
|
143
165
|
version: 1.0.1
|
144
166
|
type: :development
|
145
167
|
prerelease: false
|
146
|
-
version_requirements: *
|
168
|
+
version_requirements: *2158724960
|
147
169
|
- !ruby/object:Gem::Dependency
|
148
170
|
name: rdoc
|
149
|
-
requirement: &
|
171
|
+
requirement: &2158724140 !ruby/object:Gem::Requirement
|
150
172
|
none: false
|
151
173
|
requirements:
|
152
174
|
- - ! '>='
|
@@ -154,7 +176,7 @@ dependencies:
|
|
154
176
|
version: '0'
|
155
177
|
type: :development
|
156
178
|
prerelease: false
|
157
|
-
version_requirements: *
|
179
|
+
version_requirements: *2158724140
|
158
180
|
description: ! 'Define your permission rules as role- or role group specific permits.
|
159
181
|
|
160
182
|
Integrates well with multiple Devise user acounts.
|
@@ -220,6 +242,7 @@ files:
|
|
220
242
|
- lib/cantango/configuration/adapters.rb
|
221
243
|
- lib/cantango/configuration/autoload.rb
|
222
244
|
- lib/cantango/configuration/categories.rb
|
245
|
+
- lib/cantango/configuration/debug.rb
|
223
246
|
- lib/cantango/configuration/engines.rb
|
224
247
|
- lib/cantango/configuration/engines/cache.rb
|
225
248
|
- lib/cantango/configuration/engines/engine.rb
|
@@ -423,7 +446,6 @@ files:
|
|
423
446
|
- spec/active_record/scenarios/user_accounts/permits/user_account_permit.rb
|
424
447
|
- spec/active_record/scenarios/user_accounts/user_account_spec.rb
|
425
448
|
- spec/active_record/spec_helper.rb
|
426
|
-
- spec/cantango/README.textile
|
427
449
|
- spec/cantango/ability/cache/key_spec.rb
|
428
450
|
- spec/cantango/ability/cache/kompiler_spec.rb
|
429
451
|
- spec/cantango/ability/cache/reader_compile_spec.rb
|
@@ -449,6 +471,7 @@ files:
|
|
449
471
|
- spec/cantango/configuration/adapter_spec.rb
|
450
472
|
- spec/cantango/configuration/autoload_spec.rb
|
451
473
|
- spec/cantango/configuration/categories_spec.rb
|
474
|
+
- spec/cantango/configuration/debug_spec.rb
|
452
475
|
- spec/cantango/configuration/engines/cache_spec.rb
|
453
476
|
- spec/cantango/configuration/engines/engine_shared.rb
|
454
477
|
- spec/cantango/configuration/engines/permission_spec.rb
|
@@ -797,7 +820,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
797
820
|
version: '0'
|
798
821
|
segments:
|
799
822
|
- 0
|
800
|
-
hash: -
|
823
|
+
hash: -2544503821884776922
|
801
824
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
802
825
|
none: false
|
803
826
|
requirements:
|
@@ -806,7 +829,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
806
829
|
version: '0'
|
807
830
|
requirements: []
|
808
831
|
rubyforge_project:
|
809
|
-
rubygems_version: 1.8.
|
832
|
+
rubygems_version: 1.8.10
|
810
833
|
signing_key:
|
811
834
|
specification_version: 3
|
812
835
|
summary: CanCan extension with role oriented permission management and more
|