authorize_me 0.1.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/MIT-LICENSE +20 -0
- data/README.rdoc +74 -0
- data/lib/authorize_me.rb +6 -0
- data/lib/authorize_me/ability_checker.rb +53 -0
- data/lib/authorize_me/controller.rb +11 -0
- data/lib/authorize_me/exceptions.rb +16 -0
- data/lib/authorize_me/model.rb +70 -0
- data/lib/authorize_me/role_definition.rb +15 -0
- data/lib/authorize_me/version.rb +3 -0
- data/rails/init.rb +2 -0
- metadata +73 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 [name of plugin creator]
|
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,74 @@
|
|
1
|
+
= authorize_me
|
2
|
+
|
3
|
+
authorize_me is a gem for Rails to handle simple role-based authorization. It is similar in style to can-can.
|
4
|
+
The largest difference is that authorization rules are defined in the model they protect rather than one centralized location.
|
5
|
+
|
6
|
+
== Set up the user model
|
7
|
+
|
8
|
+
Tell the gem which model to treat as the "user".
|
9
|
+
|
10
|
+
class User
|
11
|
+
authorize_me
|
12
|
+
end
|
13
|
+
|
14
|
+
The following methods are generated:
|
15
|
+
|
16
|
+
User#can_create?(obj)
|
17
|
+
User#can_read?(obj)
|
18
|
+
User#can_update?(obj)
|
19
|
+
User#can_destroy?(obj)
|
20
|
+
|
21
|
+
Each of these methods can take a model class, instance, or symbol.
|
22
|
+
|
23
|
+
The user model is expected to have a role method that returns a string or symbol.
|
24
|
+
It could be a DB column or a method you define. Here is an example:
|
25
|
+
|
26
|
+
def role
|
27
|
+
if admin?
|
28
|
+
:admin
|
29
|
+
else
|
30
|
+
user_type
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
== Declare authorization rules
|
35
|
+
|
36
|
+
Authorization rules are declared in each model where they apply
|
37
|
+
|
38
|
+
class Article
|
39
|
+
authorization do |role|
|
40
|
+
role.admin :can => :manage
|
41
|
+
role.publisher :can => :manage, :if => :author?
|
42
|
+
role.publisher :can => [:read, :create]
|
43
|
+
role.any :can => :read
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
In this example a publisher can always read and create articles,
|
48
|
+
but they can only manage articles for which they are the author.
|
49
|
+
This declaration assumes there is an Article#author? method which
|
50
|
+
takes a user argument and returns a boolean.
|
51
|
+
|
52
|
+
:manage is shorthand for [:create, :read, :update, :destroy]
|
53
|
+
|
54
|
+
== In your controllers
|
55
|
+
|
56
|
+
The unauthorized! method simply raises an AuthorizeMe::Unauthorized exception
|
57
|
+
for you to handle as you choose.
|
58
|
+
|
59
|
+
def show
|
60
|
+
@article = Article.find(params[:id])
|
61
|
+
unauthorized! unless current_user.can_read?(@article)
|
62
|
+
end
|
63
|
+
|
64
|
+
== In your views
|
65
|
+
|
66
|
+
<% if current_user.can_update?(@article) %>
|
67
|
+
<%= link_to 'edit', edit_article_path(@article) %>
|
68
|
+
<% end %>
|
69
|
+
|
70
|
+
Copyright (c) 2010 Adam McCrea, released under the MIT license
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
data/lib/authorize_me.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module AuthorizeMe
|
2
|
+
class AbilityChecker
|
3
|
+
def initialize(ability, target, association, user)
|
4
|
+
@ability, @target, @association, @user = ability, target, association, user
|
5
|
+
@target = @target.to_s if @target.is_a?(Symbol)
|
6
|
+
end
|
7
|
+
|
8
|
+
def check
|
9
|
+
return false if access_rule.nil?
|
10
|
+
|
11
|
+
if_condition_met = access_rule[:if].nil? || call_method(access_rule[:if])
|
12
|
+
unless_condition_met = access_rule[:unless].nil? || !call_method(access_rule[:unless])
|
13
|
+
|
14
|
+
if_condition_met && unless_condition_met
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def object
|
20
|
+
@object ||= if @target.is_a?(String)
|
21
|
+
build_model_object
|
22
|
+
elsif ! @target.class.respond_to?(:authorization_rules)
|
23
|
+
raise AuthorizeMe::AuthorizationRuleMissing.new(@target)
|
24
|
+
else
|
25
|
+
@target
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_model_object
|
30
|
+
if @association
|
31
|
+
@association.send(@target.pluralize).new
|
32
|
+
else
|
33
|
+
@target.singularize.camelize.constantize.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def rules
|
38
|
+
object.class.authorization_rules[@user.role.to_sym] || {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def access_rule
|
42
|
+
rules[@ability.to_sym] || rules[:manage]
|
43
|
+
end
|
44
|
+
|
45
|
+
def call_method(method)
|
46
|
+
arity = object.send(:method, method).arity
|
47
|
+
case arity.abs
|
48
|
+
when 0 then object.send(method)
|
49
|
+
when 1 then object.send(method, @user)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AuthorizeMe
|
2
|
+
|
3
|
+
class AuthorizationRuleMissing < Exception
|
4
|
+
def initialize(obj)
|
5
|
+
@obj = obj
|
6
|
+
end
|
7
|
+
|
8
|
+
def message
|
9
|
+
"AuthorizeMe tried to access #{@obj.inspect}, which does not declare authorization rules"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Unauthorized < Exception; end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module AuthorizeMe
|
4
|
+
module Model
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.send :include, InstanceMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# define a bunch of methods on extended class
|
13
|
+
# * User#can_create?(obj)
|
14
|
+
# * User#can_read?(obj)
|
15
|
+
# * User#can_update?(obj)
|
16
|
+
# * User#can_destroy?(obj)
|
17
|
+
def authorize_me
|
18
|
+
%w{ create read update destroy }.each do |ability|
|
19
|
+
define_method "can_#{ability}?" do |*args|
|
20
|
+
obj = args[0]
|
21
|
+
association_options = args[1] || {}
|
22
|
+
check_ability_on_object ability, obj, association_options
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# declare authorization rules on a model. For example
|
28
|
+
# authorize do |role|
|
29
|
+
# role.owner :can => :manage
|
30
|
+
# role.admin :can => :manage
|
31
|
+
# role.member :can => :read, :if => :has_application_read_permission?
|
32
|
+
# role.member :can => [:create, :update, :destroy], :if => :has_application_write_permission?
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
def authorize
|
36
|
+
yield AuthorizeMe::RoleDefinition.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_authorization_rule(role, options)
|
40
|
+
role = role.to_sym
|
41
|
+
abilities = options[:can]
|
42
|
+
abilities = [abilities] unless abilities.is_a?(Array)
|
43
|
+
|
44
|
+
@authorization_rules ||= {}
|
45
|
+
@authorization_rules[role] ||= {}
|
46
|
+
|
47
|
+
abilities.each do |ability|
|
48
|
+
@authorization_rules[role][ability.to_sym] = {}
|
49
|
+
@authorization_rules[role][ability.to_sym][:if] = options[:if]
|
50
|
+
@authorization_rules[role][ability.to_sym][:unless] = options[:unless]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def authorization_rules
|
55
|
+
@authorization_rules || {}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module InstanceMethods
|
60
|
+
protected
|
61
|
+
def check_ability_on_object(ability, target, association_options)
|
62
|
+
association = association_options[:for]
|
63
|
+
checker = AuthorizeMe::AbilityChecker.new(ability, target, association, self)
|
64
|
+
checker.check
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AuthorizeMe
|
2
|
+
class RoleDefinition
|
3
|
+
def initialize(model_class)
|
4
|
+
@model_class = model_class
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(name, *args)
|
8
|
+
if args.length == 1 && args.first.is_a?(Hash)
|
9
|
+
@model_class.add_authorization_rule(name, args.first)
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/rails/init.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: authorize_me
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Adam McCrea
|
13
|
+
- John Andrews
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-10 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Simple role-based authorization
|
23
|
+
email: adam@edgecase.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- MIT-LICENSE
|
30
|
+
- README.rdoc
|
31
|
+
files:
|
32
|
+
- lib/authorize_me/ability_checker.rb
|
33
|
+
- lib/authorize_me/controller.rb
|
34
|
+
- lib/authorize_me/exceptions.rb
|
35
|
+
- lib/authorize_me/model.rb
|
36
|
+
- lib/authorize_me/role_definition.rb
|
37
|
+
- lib/authorize_me/version.rb
|
38
|
+
- lib/authorize_me.rb
|
39
|
+
- rails/init.rb
|
40
|
+
- MIT-LICENSE
|
41
|
+
- README.rdoc
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/edgecase/authorize_me
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Simple role-based authorization
|
72
|
+
test_files: []
|
73
|
+
|