Fingertips-authorization-san 1.0.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/LICENSE +18 -0
- data/README.rdoc +21 -0
- data/lib/authorization.rb +2 -0
- data/lib/authorization/allow_access.rb +78 -0
- data/lib/authorization/block_access.rb +133 -0
- data/rails/init.rb +4 -0
- metadata +60 -0
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
(c) 2009 Fingertips, Manfred Stienstra <m.stienstra@fngtps.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= Authorization-San
|
2
|
+
|
3
|
+
Authorization-san allows you to specify access policies in your controllers. The plugin assumes a number of things about the application.
|
4
|
+
|
5
|
+
* If a user has authenticated with the application, it's stored in <tt>@authenticated</tt>. The method of authentication doesn't matter.
|
6
|
+
* <tt>@authenticated</tt> has either a <tt>role</tt> attribute or a number of methods to query for the role: <tt>admin?</tt>, <tt>editor?</tt>, <tt>guest?</tt>. When the <tt>@authenticated</tt> object doesn't have role methods it's
|
7
|
+
|
8
|
+
== What does it look like?
|
9
|
+
|
10
|
+
class BooksController < ActionController::Base
|
11
|
+
# Visitors can see list of books and book pages
|
12
|
+
allow_access :all, :only => [:index, :show]
|
13
|
+
# An editor can create new books, but…
|
14
|
+
allow_access :editor, :only => [:new, :create]
|
15
|
+
# …she can only update her own books.
|
16
|
+
allow_access(:editor, :only => [:edit, :update]) { @book = @authenticated.books.find(params[:id]) }
|
17
|
+
# Admin users can do it all.
|
18
|
+
allow_access :admin
|
19
|
+
end
|
20
|
+
|
21
|
+
The best place to start learning more is the <tt>examples</tt> directory in the source.
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Authorization
|
2
|
+
module AllowAccess
|
3
|
+
# By default you block all access to the controller with <tt>block_access</tt>, with <tt>allow_access</tt> you
|
4
|
+
# specify who can access the actions on the controller under certain conditions. <tt>allow_access</tt> can deal
|
5
|
+
# with accounts with and without roles.
|
6
|
+
#
|
7
|
+
# *Examples*
|
8
|
+
#
|
9
|
+
# Everyone can access all actions on the controller.
|
10
|
+
# allow_access
|
11
|
+
# allow_access :all
|
12
|
+
# Everyone with the admin role can access the controller.
|
13
|
+
# allow_access :admin
|
14
|
+
# Everyone with the admin and editor role can access the controller.
|
15
|
+
# allow_access :admin, :editor
|
16
|
+
# Everyone with the editor role can access the index. show, edit and update actions.
|
17
|
+
# allow_access :editor, :only => [:index, :show, :edit, :update]
|
18
|
+
# A coordinator can do anything the admin can, except for delete
|
19
|
+
# allow_access :coordinator, :except => :destroy
|
20
|
+
# Everyone with the admin and editor role can access the show action.
|
21
|
+
# allow_access :admin, :editor, :action => :show
|
22
|
+
# A guest can view all resources if he has view permissions. The block is evaltuated in the controller's instance.
|
23
|
+
# Note that rules are evaluated when <tt>block_access</tt> is run.
|
24
|
+
# allow_access(:guest, :only => [:index, :show]) { @authenticated.view_permission? }
|
25
|
+
# Specifying a role is optional, if you don't specify a role the rule is added for the default role <tt>:all</tt>.
|
26
|
+
# allow_access(:only => :unsubscribe) { @authenticated.subscribed? }
|
27
|
+
# Only allow authenticated users, :authenticated is a special role meaning all authenticated users.
|
28
|
+
# allow_access :authenticated
|
29
|
+
# You need to be authenticated for the secret action
|
30
|
+
# allow_access :all, :except => :secret
|
31
|
+
# allow_access :authenticated, :only => :secret
|
32
|
+
#
|
33
|
+
# The following special directives might be a little hard to explain, I will give the equivalent rule with the
|
34
|
+
# block access.
|
35
|
+
#
|
36
|
+
# Imagine we have a user controller, every user has an organization association. The users resource is nested
|
37
|
+
# in the organization resource like this.
|
38
|
+
# map.resources :organizations { |org| org.resources :users }
|
39
|
+
# Now we want the user to edit his own resource (for instance to update the password).
|
40
|
+
# allow_access :only => [:index, :show, :edit, :update], :user_resource => true
|
41
|
+
# allow_access(:only => [:index, :show, :edit, :update]) do
|
42
|
+
# @authenticated.id == params[:id].to_i
|
43
|
+
# end
|
44
|
+
# We could also specify that a user can edit everything in his own organization.
|
45
|
+
# allow_access :only => [:index, :show, :edit, :update], :scope => :organization
|
46
|
+
# allow_access(:only => [:index, :show, :edit, :update]) do
|
47
|
+
# @authenticated.organization.id == params[:organization_id].to_i
|
48
|
+
# end
|
49
|
+
def allow_access(*args, &block)
|
50
|
+
unless self.respond_to?(:access_allowed_for)
|
51
|
+
self.class_inheritable_accessor(:access_allowed_for)
|
52
|
+
send(:protected, :access_allowed_for, :access_allowed_for=)
|
53
|
+
end
|
54
|
+
self.access_allowed_for ||= HashWithIndifferentAccess.new
|
55
|
+
if args.first.kind_of?(Hash) || args.empty?
|
56
|
+
self.access_allowed_for[:all] ||= []
|
57
|
+
self.access_allowed_for[:all] << {
|
58
|
+
:directives => args.first || {},
|
59
|
+
:block => block
|
60
|
+
}
|
61
|
+
else
|
62
|
+
directives = args.last.kind_of?(Hash) ? args.pop : {}
|
63
|
+
roles = args.flatten
|
64
|
+
if roles.delete(:authenticated) or roles.delete('authenticated')
|
65
|
+
roles = [:all] if roles.empty?
|
66
|
+
directives[:authenticated] = true
|
67
|
+
end
|
68
|
+
roles.each do |role|
|
69
|
+
self.access_allowed_for[role.to_s] ||= []
|
70
|
+
self.access_allowed_for[role.to_s] << {
|
71
|
+
:directives => directives,
|
72
|
+
:block => block
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Authorization
|
2
|
+
module BlockAccess
|
3
|
+
protected
|
4
|
+
|
5
|
+
# Block access to all actions in the controller, designed to be used as a <tt>before_filter</tt>.
|
6
|
+
# class ApplicationController < ActionController::Base
|
7
|
+
# before_filter :block_access
|
8
|
+
# end
|
9
|
+
def block_access
|
10
|
+
die_if_undefined
|
11
|
+
unless @authenticated.nil?
|
12
|
+
# Find the user's roles
|
13
|
+
roles = []
|
14
|
+
roles << @authenticated.role if @authenticated.respond_to?(:role)
|
15
|
+
access_allowed_for.keys.each do |role|
|
16
|
+
roles << role.to_s if @authenticated.respond_to?("#{role}?") and @authenticated.__send__("#{role}?")
|
17
|
+
end
|
18
|
+
# Check if any of the roles give her access
|
19
|
+
roles.each do |role|
|
20
|
+
return true if access_allowed?(params, role, @authenticated)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
return true if access_allowed?(params, :all, @authenticated)
|
24
|
+
access_forbidden
|
25
|
+
end
|
26
|
+
|
27
|
+
# Checks if access is allowed for the params, role and authenticated user.
|
28
|
+
# access_allowed?({:action => :show, :id => 1}, :admin, @authenticated)
|
29
|
+
def access_allowed?(params, role, authenticated=nil)
|
30
|
+
die_if_undefined
|
31
|
+
if (rules = access_allowed_for[role]).nil?
|
32
|
+
logger.debug(" \e[31mCan't find rules for `#{role}'\e[0m")
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
!rules.detect do |rule|
|
36
|
+
if !action_allowed_by_rule?(rule, params, role) or !resource_allowed_by_rule?(rule, params, role, authenticated) or !block_allowed_by_rule?(rule)
|
37
|
+
logger.debug(" \e[31mAccess DENIED by RULE #{rule.inspect} FOR `#{role}'\e[0m")
|
38
|
+
false
|
39
|
+
else
|
40
|
+
logger.debug(" \e[32mAccess GRANTED by RULE #{rule.inspect} FOR `#{role}'\e[0m")
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# <tt>access_forbidden</tt> is called by <tt>block_access</tt> when access is forbidden. This method does
|
47
|
+
# nothing by default. Make sure you return <tt>false</tt> from the method if you want to halt the filter
|
48
|
+
# chain.
|
49
|
+
def access_forbidden
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Checks if a certain action can be accessed by the role.
|
54
|
+
# If you want to check for <tt>action_allowed?</tt>, <tt>resource_allowed?</tt> and <tt>block_allowed?</tt>
|
55
|
+
# use <tt>access_allowed?</tt>.
|
56
|
+
# action_allowed?({:action => :show, :id => 1}, :editor)
|
57
|
+
def action_allowed?(params, role=:all)
|
58
|
+
die_if_undefined
|
59
|
+
return false if (rules = access_allowed_for[role]).nil?
|
60
|
+
!rules.detect { |rule| action_allowed_by_rule?(rule, params, role) }.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def action_allowed_by_rule?(rule, params, role) #:nodoc:
|
64
|
+
return false if (action = params[:action]).nil?
|
65
|
+
directives = rule[:directives]
|
66
|
+
return false if directives[:only].kind_of?(Array) and !directives[:only].include?(action.to_sym)
|
67
|
+
return false if directives[:only].kind_of?(Symbol) and directives[:only] != action.to_sym
|
68
|
+
return false if directives[:except].kind_of?(Array) and directives[:except].include?(action.to_sym)
|
69
|
+
return false if directives[:except].kind_of?(Symbol) and directives[:except] == action.to_sym
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Checks if the resource indicated by the params can be accessed by user.
|
74
|
+
# If you want to check for <tt>action_allowed?</tt>, <tt>resource_allowed?</tt> and <tt>block_allowed?</tt>
|
75
|
+
# use <tt>access_allowed?</tt>.
|
76
|
+
# resource_allowed?({:id => 1, :organization_id => 12}, :guest, @authenticated)
|
77
|
+
def resource_allowed?(params, role=:all, user=nil)
|
78
|
+
user ||= @authenticated
|
79
|
+
die_if_undefined
|
80
|
+
return false if (rules = access_allowed_for[role]).nil?
|
81
|
+
!rules.detect { |rule| resource_allowed_by_rule?(rule, params, role, user) }.nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
def resource_allowed_by_rule?(rule, params, role, user) #:nodoc:
|
85
|
+
directives = rule[:directives]
|
86
|
+
if directives[:authenticated]
|
87
|
+
return false unless user
|
88
|
+
end
|
89
|
+
begin
|
90
|
+
if directives[:user_resource]
|
91
|
+
return false if params[:id].nil? or user.id.nil?
|
92
|
+
return false if params[:id].to_i != user.id.to_i
|
93
|
+
end
|
94
|
+
rescue NoMethodError
|
95
|
+
end
|
96
|
+
begin
|
97
|
+
if scope = directives[:scope]
|
98
|
+
assoc_id = params["#{scope}_id"].to_i
|
99
|
+
begin
|
100
|
+
object_id = user.__send__(scope).id.to_i
|
101
|
+
rescue NoMethodError
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
return false if assoc_id.nil? or object_id.nil?
|
105
|
+
return false if assoc_id != object_id
|
106
|
+
end
|
107
|
+
rescue NoMethodError
|
108
|
+
end
|
109
|
+
true
|
110
|
+
end
|
111
|
+
|
112
|
+
# Checks if the blocks associated with the rules doesn't stop the user from acessing the resource.
|
113
|
+
# If you want to check for <tt>action_allowed?</tt>, <tt>resource_allowed?</tt> and <tt>block_allowed?</tt>
|
114
|
+
# use <tt>access_allowed?</tt>.
|
115
|
+
# block_allowed?(:guest)
|
116
|
+
def block_allowed?(role)
|
117
|
+
die_if_undefined
|
118
|
+
return false if (rules = access_allowed_for[role]).nil?
|
119
|
+
!rules.detect { |rule| block_allowed_by_rule?(rule) }.nil?
|
120
|
+
end
|
121
|
+
|
122
|
+
def block_allowed_by_rule?(rule) #:nodoc:
|
123
|
+
return false if !rule[:block].nil? and !rule[:block].bind(self).call
|
124
|
+
true
|
125
|
+
end
|
126
|
+
|
127
|
+
def die_if_undefined #:nodoc:
|
128
|
+
if !self.respond_to?(:access_allowed_for) or access_allowed_for.nil?
|
129
|
+
raise ArgumentError, "Please specify access control using `allow_access' in the controller"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/rails/init.rb
ADDED
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Fingertips-authorization-san
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manfred Stienstra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-09 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A plugin for authorization in a ReSTful application.
|
17
|
+
email: manfred@fngtps.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- lib/authorization.rb
|
27
|
+
- lib/authorization/allow_access.rb
|
28
|
+
- lib/authorization/block_access.rb
|
29
|
+
- rails/init.rb
|
30
|
+
- README.rdoc
|
31
|
+
- LICENSE
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://fingertips.github.com
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options:
|
36
|
+
- --inline-source
|
37
|
+
- --charset=UTF-8
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.2.0
|
56
|
+
signing_key:
|
57
|
+
specification_version: 2
|
58
|
+
summary: A plugin for authorization in a ReSTful application.
|
59
|
+
test_files: []
|
60
|
+
|