fat_model_auth 2.0.1

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/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [Brent Greeff]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,172 @@
1
+ = Fat Model Auth
2
+
3
+ Wikipedia defines Authorization as 'the function of specifying access rights to resources'.
4
+ Fat Model Auth allows the resources themselves to define these rights.
5
+
6
+ == Fat Model Auth is a simple, clean authorization system for Rails
7
+
8
+ * How simple?
9
+
10
+ == Controller
11
+
12
+ * Imagine you have a controller for Articles:
13
+
14
+ before_filter :load_article
15
+
16
+ def edit
17
+ end
18
+
19
+ def update
20
+ # Update shazam
21
+ end
22
+
23
+ private
24
+
25
+ def load_article
26
+ Article.find(params[:id])
27
+ end
28
+
29
+ * We want to ensure only the Articles Author can view the edit page or update
30
+ * an Article.
31
+
32
+ * Just Add a before filter:
33
+
34
+ before_filter :auth_required, :only => [:edit, :update]
35
+
36
+ * Add it AFTER you load the article
37
+
38
+ Go ahead and try and view the article
39
+
40
+ * We are missing something:
41
+
42
+ undefined method 'allows' for #<Article:0x204a8d8>
43
+
44
+ == Model
45
+
46
+ * Just add the following to your Article model:
47
+
48
+ allows :edit, :update,
49
+ :if => proc {|article, user| article.author == user}
50
+
51
+ * Need different rules for different actions:
52
+
53
+ allows :edit,
54
+ :if => proc {|article, user| article.author.name.eql? 'Jeff'}
55
+
56
+ allows :update,
57
+ :if => proc {|article, user| article.allows_updating?}
58
+
59
+
60
+ Control which functions are displayed to a user
61
+
62
+ == View
63
+
64
+ <%= link_to('EDIT', edit_article_path(article)) if allowed_to? :edit => article -%>
65
+
66
+ * What about groups of controls:
67
+
68
+ <% if allowed_to? :edit_or_destroy => article -%>
69
+ <funky>html</funky>
70
+ <% end %>
71
+
72
+
73
+ Thats it.
74
+
75
+ == Test First
76
+
77
+ The rules that define access control, are defined in the model.
78
+ If you are testing first, start with a unit test:
79
+
80
+ * EDIT
81
+
82
+ assert @article.allows(@article.author).to_edit?
83
+
84
+ deny @article.allows(@someone_else).to_edit?
85
+
86
+ * UPDATE
87
+
88
+ assert @article.allows(@jeff).to_update?
89
+
90
+ deny @article.allows(@sammy).to_update?
91
+
92
+ These magic methods are created when you define 'allows' on your model.
93
+
94
+ When you say 'auth_required' in a before filter:
95
+ The plugin looks for an object based on the name of the controller:
96
+
97
+ So if you put the before filter in the 'articles_controller'
98
+ and you call the 'edit' action,
99
+
100
+ it generates the following call:
101
+
102
+ @article.allows(current_user).to_edit?
103
+
104
+
105
+ What happens if I am editing articles but I am not in the articles_controller?
106
+
107
+ * Just add this to the controller
108
+
109
+ class RestlessController < ApplicationController
110
+ def override_authority
111
+ @article
112
+ end
113
+ end
114
+
115
+ == Remember
116
+
117
+ 1. A nil current_user will always return access_denied.
118
+
119
+ == Access Denied is 404
120
+
121
+ Thats right deal with it or fork it.
122
+
123
+ Trying to access a resource without permission returns 404
124
+ In other words:
125
+
126
+ "Say What?"
127
+
128
+ == New & Create and complex conditons
129
+
130
+ If you have complex conditions or when creating a new object
131
+ it may not have the information you need in a before filter.
132
+
133
+ You can always get the same result by being explicit in the method:
134
+
135
+ # Articles controller
136
+
137
+ def create
138
+ @article = current_user.articles.build(params[:article])
139
+ return if access_denied?
140
+ end
141
+
142
+ == Testing my controllers
143
+
144
+ login_as @no_good_user
145
+ get :edit, :id => @article.id
146
+
147
+ assert_response :not_found
148
+ assert_template 'public/404'
149
+
150
+ If you are using mock user, you may want to stub the response
151
+
152
+ @article.expects(:allows).returns(FatModelAuth::CannedGateKeeper.allows(:edit))
153
+
154
+ or
155
+
156
+ @article.expects(:allows).returns(FatModelAuth::CannedGateKeeper.denies(:edit))
157
+
158
+
159
+ == Testing my views
160
+
161
+ Who does that?
162
+
163
+ step 1. Install should_pricot
164
+
165
+ login_as @no_good_user
166
+ get :edit, :id => @article.id
167
+
168
+ element('#power_user a[@href="/create/havok"]').should_be_missing
169
+
170
+
171
+
172
+ Copyright (c) 2009 [Brent Greeff], released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the fat_model_auth plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the fat_model_auth plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'FatModelAuth'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
@@ -0,0 +1,9 @@
1
+ require 'fat_model_auth/canned_gate_keeper'
2
+ require 'fat_model_auth/controller_helpers'
3
+ require 'fat_model_auth/gate_keeper'
4
+ require 'fat_model_auth/model_helpers'
5
+ require 'fat_model_auth/view_helpers'
6
+
7
+ ActionController::Base.send(:include, FatModelAuth::ControllerHelpers)
8
+ ActiveRecord::Base.send(:extend, FatModelAuth::ModelHelpers)
9
+ ActionView::Base.send(:include, FatModelAuth::ViewHelpers)
@@ -0,0 +1,40 @@
1
+ module FatModelAuth
2
+ class CannedGateKeeper
3
+
4
+ def self.allows(method)
5
+ self.new(method => true)
6
+ end
7
+
8
+ def self.denies(method)
9
+ self.new(method => false)
10
+ end
11
+
12
+ def self.build(params)
13
+ self.new(params)
14
+ end
15
+
16
+ def allows(user)
17
+ self
18
+ end
19
+
20
+ def initialize(params)
21
+ @map = {}
22
+ add_rules(params)
23
+ end
24
+
25
+ def add_rules(params)
26
+ for param in params
27
+ response = param.pop
28
+ @map["to_#{param.pop}?".to_sym] = lambda { response }
29
+ end
30
+ end
31
+
32
+ def method_missing(method, *args)
33
+ unless @map.has_key? method
34
+ raise NoMethodError, "undefined method allows(user).#{method} for #{self.class}"
35
+ end
36
+
37
+ @map[method].call
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ module FatModelAuth
2
+ class AuthException < Exception; end
3
+
4
+ module ControllerHelpers
5
+ protected
6
+
7
+ def auth_required
8
+ authority = get_authority
9
+
10
+ access_granted = authority.allows(current_user).send "to_#{params[:action]}?"
11
+ respond_with_404_page unless access_granted
12
+ end
13
+
14
+ def access_denied?
15
+ authority = get_authority
16
+
17
+ access_granted = authority.allows(current_user).send "to_#{params[:action]}?"
18
+ if access_granted
19
+ false
20
+ else
21
+ respond_with_404_page
22
+ true
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def get_authority
29
+ if self.respond_to? :override_authority
30
+ authority = override_authority
31
+ raise FatModelAuth::AuthException, "override_authority defined but nil" if authority.nil?
32
+ else
33
+ authority_name = params[:controller].singularize
34
+ authority = instance_variable_get("@#{authority_name}")
35
+ raise FatModelAuth::AuthException, "#{authority_name} is nil" if authority.nil?
36
+ end
37
+
38
+ return authority
39
+ end
40
+
41
+ def respond_with_404_page
42
+ render "#{RAILS_ROOT}/public/404.html", :status => 404
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ module FatModelAuth
2
+ class GateKeeper
3
+
4
+ def initialize(params)
5
+ @map = {}
6
+ add_rules(params)
7
+ end
8
+
9
+ def add_rules(params)
10
+ auth_condition = params.pop[:if]
11
+ methods = params
12
+
13
+ for method in methods
14
+ @map["to_#{method}?".to_sym] = auth_condition
15
+ end
16
+ end
17
+
18
+ def check(model, user)
19
+ @model = model
20
+ @user = user
21
+ self
22
+ end
23
+
24
+ def method_missing(method, *args)
25
+ unless @map.has_key? method
26
+ raise NoMethodError, "undefined method allows(user).#{method} for #{@model.inspect}"
27
+ end
28
+ return false if @user.nil?
29
+
30
+ @map[method].call(@model, @user)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module FatModelAuth
2
+ module ModelHelpers
3
+ def allows(*params)
4
+ if self.respond_to? :gate_keeper
5
+ class_eval do
6
+ self.gate_keeper.add_rules(params)
7
+ end
8
+ else
9
+ class_eval do
10
+ cattr_accessor :gate_keeper
11
+ self.gate_keeper = FatModelAuth::GateKeeper.new(params)
12
+
13
+ define_method "allows" do |user|
14
+ self.gate_keeper.check(self, user)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module FatModelAuth
2
+ module ViewHelpers
3
+ def allowed_to?(options)
4
+ authority = options.values.first
5
+
6
+ get_actions(options).each do |action|
7
+ return true if authority.allows(current_user).send "to_#{action}?"
8
+ end
9
+ return false
10
+ end
11
+
12
+ private
13
+
14
+ def get_actions(options)
15
+ return options.keys.first.to_s.split('_or_')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class FatModelAuthTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fat_model_auth
3
+ version: !ruby/object:Gem::Version
4
+ hash: 13
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 0
9
+ - 1
10
+ version: 2.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Brent Greeff
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-30 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Clean resource based Authorisation plugin for Rails.
23
+ email: email@brentgreeff.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - MIT-LICENSE
30
+ - README.rdoc
31
+ files:
32
+ - MIT-LICENSE
33
+ - README.rdoc
34
+ - Rakefile
35
+ - VERSION
36
+ - lib/fat_model_auth.rb
37
+ - lib/fat_model_auth/canned_gate_keeper.rb
38
+ - lib/fat_model_auth/controller_helpers.rb
39
+ - lib/fat_model_auth/gate_keeper.rb
40
+ - lib/fat_model_auth/model_helpers.rb
41
+ - lib/fat_model_auth/view_helpers.rb
42
+ - test/fat_model_auth_test.rb
43
+ - test/test_helper.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/brentgreeff/fat_model_auth
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --charset=UTF-8
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.7
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Clean resource based Authorisation plugin for Rails.
78
+ test_files: []
79
+