Fingertips-authorization-san 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|