fat_model_auth 2.0.1

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