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 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,2 @@
1
+ require 'authorization/allow_access'
2
+ require 'authorization/block_access'
@@ -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
@@ -0,0 +1,4 @@
1
+ require 'authorization'
2
+
3
+ ActionController::Base.send(:include, Authorization::BlockAccess)
4
+ ActionController::Base.send(:extend, Authorization::AllowAccess)
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
+