credentials 2.2.3 → 2.3.0
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/HISTORY +4 -0
- data/VERSION +1 -1
- data/credentials.gemspec +2 -2
- data/lib/credentials/extensions/action_controller.rb +10 -3
- data/lib/credentials/rule.rb +33 -2
- data/lib/credentials/rulebook.rb +17 -0
- data/lib/credentials.rb +4 -0
- data/spec/controllers/test_controller_spec.rb +29 -1
- data/spec/credentials_spec.rb +9 -1
- data/spec/domain.rb +3 -0
- metadata +2 -2
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.3.0
|
data/credentials.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{credentials}
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matt Powell"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-16}
|
13
13
|
s.description = %q{A generic actor/resource permission framework based on rules, not objects.}
|
14
14
|
s.email = %q{fauxparse@gmail.com.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -47,8 +47,8 @@ module Credentials
|
|
47
47
|
# otherwise Credentials would also try to evaluate the
|
48
48
|
# +edit+ method as an argument.
|
49
49
|
def requires_permission_to(*args)
|
50
|
-
options = (args.last.is_a?(Hash) ? args.pop : {})
|
51
|
-
|
50
|
+
options = (args.last.is_a?(Hash) ? args.pop : {})
|
51
|
+
[ :only, :except ].each do |key|
|
52
52
|
options[key] = Array(options[key]).map(&:to_sym) if options[key]
|
53
53
|
end
|
54
54
|
self.required_credentials = self.required_credentials + [ [ options, args ] ]
|
@@ -80,12 +80,19 @@ module Credentials
|
|
80
80
|
self.class.required_credentials.each do |options, args|
|
81
81
|
next if options[:only] && !options[:only].include?(current_action)
|
82
82
|
next if options[:except] && options[:except].include?(current_action)
|
83
|
-
|
83
|
+
|
84
84
|
raise Credentials::Errors::NotLoggedInError unless current_user
|
85
85
|
evaluated = args.map do |arg|
|
86
86
|
(arg.is_a?(Symbol) && respond_to?(arg) && !public_methods.include?(arg.to_s)) ? send(arg) : arg
|
87
87
|
end
|
88
88
|
|
89
|
+
opts = returning({}) do |hash|
|
90
|
+
(Credentials::Prepositions & options.keys).each do |prep|
|
91
|
+
hash[prep] = send(options[prep])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
evaluated << opts
|
95
|
+
|
89
96
|
unless current_user.can?(*evaluated)
|
90
97
|
raise Credentials::Errors::AccessDeniedError
|
91
98
|
end
|
data/lib/credentials/rule.rb
CHANGED
@@ -33,7 +33,7 @@ module Credentials
|
|
33
33
|
# match any element of that array:
|
34
34
|
# class User
|
35
35
|
# credentials do |user|
|
36
|
-
# user.can :fight, [ :shatner, :gandhi ]
|
36
|
+
# user.can [ :punch, :fight ], [ :shatner, :gandhi ]
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
#
|
@@ -47,8 +47,10 @@ module Credentials
|
|
47
47
|
# end
|
48
48
|
# end
|
49
49
|
def match?(*args)
|
50
|
-
|
50
|
+
values = args.last.is_a?(Hash) ? args.pop : {}
|
51
51
|
|
52
|
+
return false unless arity == args.length
|
53
|
+
|
52
54
|
parameters.zip(args).each do |expected, actual|
|
53
55
|
case expected
|
54
56
|
when :self then return false unless actual == args.first
|
@@ -56,7 +58,9 @@ module Credentials
|
|
56
58
|
else return false unless expected === actual
|
57
59
|
end
|
58
60
|
end
|
61
|
+
|
59
62
|
result = true
|
63
|
+
result = result && (options.keys & Credentials::Prepositions).inject(true) { |memo, key| memo && evaluate_preposition(args.first, options[key], values[key]) }
|
60
64
|
result = result && evaluate_condition(options[:if], :|, *args) unless options[:if].nil?
|
61
65
|
result = result && !evaluate_condition(options[:unless], :&, *args) unless options[:unless].nil?
|
62
66
|
result
|
@@ -84,5 +88,32 @@ module Credentials
|
|
84
88
|
end
|
85
89
|
end
|
86
90
|
end
|
91
|
+
|
92
|
+
def evaluate_preposition(object, expected, actual)
|
93
|
+
return true if expected.nil?
|
94
|
+
return false if actual.nil?
|
95
|
+
return true if expected === actual
|
96
|
+
|
97
|
+
single = expected.to_s
|
98
|
+
plural = single.respond_to?(:pluralize) ? single.pluralize : single + "s"
|
99
|
+
|
100
|
+
lclass, rclass = [ object.class.name, actual.class.name ].map do |s|
|
101
|
+
s.gsub(/^.*::/, '').
|
102
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
103
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
104
|
+
tr("-", "_").
|
105
|
+
downcase
|
106
|
+
end
|
107
|
+
|
108
|
+
if object.respond_to?(:id) && actual.respond_to?(:"#{lclass}_id")
|
109
|
+
return true if actual.send(:"#{lclass}_id") == object.id
|
110
|
+
end
|
111
|
+
|
112
|
+
if actual.respond_to?(:id) && object.respond_to?(:"#{rclass}_id")
|
113
|
+
return true if object.send(:"#{rclass}_id") == actual.id
|
114
|
+
end
|
115
|
+
|
116
|
+
(object.respond_to?(single) && (object.send(single) == actual)) || (object.respond_to?(plural) && (object.send(plural).include?(actual)))
|
117
|
+
end
|
87
118
|
end
|
88
119
|
end
|
data/lib/credentials/rulebook.rb
CHANGED
@@ -123,6 +123,23 @@ module Credentials
|
|
123
123
|
# user.can :edit, :self
|
124
124
|
# end
|
125
125
|
# end
|
126
|
+
#
|
127
|
+
# == Prepositions (+:for+, +:on+, etc)
|
128
|
+
# You can do the following:
|
129
|
+
# class User
|
130
|
+
# credentials do |user|
|
131
|
+
# user.can :delete, Comment, :on => :post
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# user.can? :delete, post.comments.first, :on => post
|
136
|
+
# ...means that Credentials will check if:
|
137
|
+
# * +post+ has a +user_id+ method matching +user.id+
|
138
|
+
# * +user+ has a +post_id+ method matching +post.id+
|
139
|
+
# * +user+ has a +post+ method matching +post+
|
140
|
+
# * +user+ has a +posts+ method that returns an array including +post+
|
141
|
+
#
|
142
|
+
# See Credentials::Prepositions for the list of available prepositions.
|
126
143
|
def can(*args)
|
127
144
|
self.rules << AllowRule.new(klass, *args)
|
128
145
|
end
|
data/lib/credentials.rb
CHANGED
@@ -2,6 +2,10 @@ require "credentials/rulebook"
|
|
2
2
|
require "credentials/extensions/object"
|
3
3
|
require "credentials/extensions/magic_methods"
|
4
4
|
|
5
|
+
module Credentials
|
6
|
+
Prepositions = [ :on, :for, :with, :at, :in, :from ].freeze
|
7
|
+
end
|
8
|
+
|
5
9
|
Object.send :include, Credentials::Extensions::Object
|
6
10
|
|
7
11
|
if defined?(ActionController)
|
@@ -5,10 +5,12 @@ if defined?(ActionController)
|
|
5
5
|
self.current_user_method = :logged_in_user
|
6
6
|
requires_permission_to :view, :stuff, :except => [ :public ]
|
7
7
|
requires_permission_to :break, :stuff, :only => [ :dangerous ]
|
8
|
+
requires_permission_to :create, :stuff, :for => :account, :only => [ :create ]
|
8
9
|
|
9
10
|
def index; end
|
10
11
|
def public; end
|
11
12
|
def dangerous; end
|
13
|
+
def create; end
|
12
14
|
|
13
15
|
def rescue_action(e)
|
14
16
|
raise e
|
@@ -19,9 +21,14 @@ if defined?(ActionController)
|
|
19
21
|
credentials do |user|
|
20
22
|
user.can :view, :stuff
|
21
23
|
user.can :break, :stuff, :if => :special?
|
24
|
+
user.can :create, :stuff, :for => :account
|
25
|
+
|
26
|
+
def account; end
|
22
27
|
end
|
23
28
|
end
|
24
|
-
|
29
|
+
|
30
|
+
class TestAccount; end
|
31
|
+
|
25
32
|
describe TestController do
|
26
33
|
it "should know how to specify access credentials" do
|
27
34
|
controller.class.should respond_to(:requires_permission_to)
|
@@ -77,6 +84,27 @@ if defined?(ActionController)
|
|
77
84
|
}.should raise_error(Credentials::Errors::AccessDeniedError)
|
78
85
|
end
|
79
86
|
end
|
87
|
+
|
88
|
+
it "should be able to do stuff on its own account" do
|
89
|
+
@my_account = TestAccount.new
|
90
|
+
@user.stub!(:account).and_return(@my_account)
|
91
|
+
controller.stub!(:account).and_return(@my_account)
|
92
|
+
lambda {
|
93
|
+
get :create
|
94
|
+
response.should be_success
|
95
|
+
}.should_not raise_error(Credentials::Errors::AccessDeniedError)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not be able to do stuff on someone else's account" do
|
99
|
+
@my_account = TestAccount.new
|
100
|
+
@your_account = TestAccount.new
|
101
|
+
@user.stub!(:account).and_return(@my_account)
|
102
|
+
controller.stub!(:account).and_return(@your_account)
|
103
|
+
lambda {
|
104
|
+
get :create
|
105
|
+
response.should_not be_success
|
106
|
+
}.should raise_error(Credentials::Errors::AccessDeniedError)
|
107
|
+
end
|
80
108
|
end
|
81
109
|
|
82
110
|
describe "when not logged in" do
|
data/spec/credentials_spec.rb
CHANGED
@@ -22,6 +22,14 @@ describe Animal do
|
|
22
22
|
it "should not be able to clean another animal" do
|
23
23
|
@sheep.should_not be_able_to :clean, @cow
|
24
24
|
end
|
25
|
+
|
26
|
+
it "should be able to laugh at its friends" do
|
27
|
+
@dog = Animal.new("Dog")
|
28
|
+
@dog.friends = [ @cow ]
|
29
|
+
|
30
|
+
@dog.should be_able_to :laugh, :at => @cow
|
31
|
+
@dog.should_not be_able_to :laugh, :at => @sheep
|
32
|
+
end
|
25
33
|
|
26
34
|
it "should have magic methods for permissions" do
|
27
35
|
lambda {
|
@@ -112,7 +120,7 @@ end
|
|
112
120
|
|
113
121
|
describe Man do
|
114
122
|
before :each do
|
115
|
-
@man = Man.new
|
123
|
+
@man = Man.new("Andrew")
|
116
124
|
end
|
117
125
|
|
118
126
|
it "should be able to do anything it wants" do
|
data/spec/domain.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
class Animal
|
2
2
|
credentials do |animal|
|
3
3
|
animal.can :clean, :self
|
4
|
+
animal.can :laugh, :at => :friend
|
4
5
|
end
|
5
6
|
|
6
7
|
attr_accessor :species, :hungry, :fast
|
8
|
+
attr_accessor :friends
|
9
|
+
def friends; @friends ||= []; end
|
7
10
|
|
8
11
|
def initialize(species = nil, hungry = false, fast = false)
|
9
12
|
@species = species
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credentials
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Powell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-16 00:00:00 +13:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|