checkin 0.4.3
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/.document +5 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +19 -0
- data/LICENSE.txt +20 -0
- data/README.md +188 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/checkin.gemspec +57 -0
- data/lib/checkin/access_denied.rb +46 -0
- data/lib/checkin/dsl/permissions.rb +167 -0
- data/lib/checkin/dsl/roles.rb +149 -0
- data/lib/checkin/filters.rb +78 -0
- data/lib/checkin/role.rb +26 -0
- data/lib/checkin/rule.rb +104 -0
- data/lib/checkin/subject.rb +137 -0
- data/lib/checkin.rb +32 -0
- data/test/helper.rb +18 -0
- data/test/test_checkin.rb +7 -0
- metadata +84 -0
data/.document
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
git (1.2.5)
|
|
5
|
+
jeweler (1.8.3)
|
|
6
|
+
bundler (~> 1.0)
|
|
7
|
+
git (>= 1.2.5)
|
|
8
|
+
rake
|
|
9
|
+
rdoc
|
|
10
|
+
json (1.7.1)
|
|
11
|
+
rake (0.9.2.2)
|
|
12
|
+
rdoc (3.12)
|
|
13
|
+
json (~> 1.4)
|
|
14
|
+
|
|
15
|
+
PLATFORMS
|
|
16
|
+
ruby
|
|
17
|
+
|
|
18
|
+
DEPENDENCIES
|
|
19
|
+
jeweler (~> 1.8.3)
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2012 mcasimir
|
|
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.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Checkin
|
|
2
|
+
|
|
3
|
+
**Checkin** is an authorization gem for Ruby on Rails
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Put this in your Gemfile
|
|
8
|
+
|
|
9
|
+
gem 'checkin'
|
|
10
|
+
|
|
11
|
+
and update your bundle
|
|
12
|
+
|
|
13
|
+
bundle install
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Create a **subject class** in your load path
|
|
18
|
+
|
|
19
|
+
_ex._
|
|
20
|
+
|
|
21
|
+
``` rb
|
|
22
|
+
class UserSubject < Checkin::Subject
|
|
23
|
+
|
|
24
|
+
role :guest, :alias => :anonymous do
|
|
25
|
+
!subject_model
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
role :logged_in, :alias => [:connected] do
|
|
29
|
+
!!subject_model
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
role :owner, :require => [:logged_in, :author], :method => :own do |object|
|
|
33
|
+
object && object.respond_to?(:author) && ( subject_model == object.author )
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
role :author, :require => :logged_in do
|
|
37
|
+
subject_model.has_role?(:contributor) || subject_model.has_role?(:author)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
role :editor, :require => :logged_in do
|
|
41
|
+
subject_model.has_role?(:editor)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
role :administrator, :require => :logged_in, :alias => :admin do
|
|
45
|
+
subject_model.has_role?(:administrator)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
role :mantainer, :require => :logged_in do
|
|
49
|
+
subject_model.has_role?(:mantainer)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
role :staff, :require => :logged_in do
|
|
53
|
+
subject_model.has_role?(:administrator) ||
|
|
54
|
+
subject_model.has_role?(:mantainer) ||
|
|
55
|
+
subject_model.has_role?(:editor) ||
|
|
56
|
+
subject_model.has_role?(:author) ||
|
|
57
|
+
subject_model.has_role?(:contributor) ||
|
|
58
|
+
subject_model.has_role?(:photographer)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
role :tester, :require => :logged_in do
|
|
62
|
+
subject_model.has_role?(:tester)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
role :nexta_supervisor, :require => :logged_in do
|
|
66
|
+
subject_model.has_role?(:nexta)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
role :self, :require => :logged_in do |object|
|
|
70
|
+
object && object.is_a?(User) && subject_model == object
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Permissions
|
|
75
|
+
#
|
|
76
|
+
|
|
77
|
+
scope :site do
|
|
78
|
+
permissions :for => [:messages, :replies] do
|
|
79
|
+
allow :logged_in
|
|
80
|
+
allow :guests, :to => [:show, :index]
|
|
81
|
+
deny :guests
|
|
82
|
+
end
|
|
83
|
+
permissions :for => :network do
|
|
84
|
+
allow [:administrators, :nexta_supervisors], :to => [:see]
|
|
85
|
+
deny
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Admin
|
|
90
|
+
scope :admin do
|
|
91
|
+
permissions do
|
|
92
|
+
allow :administrators, :mantainers
|
|
93
|
+
deny
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
scope :api do
|
|
98
|
+
allow :staff
|
|
99
|
+
deny
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Mantainer
|
|
103
|
+
scope :mantainer do
|
|
104
|
+
permissions do
|
|
105
|
+
allow :mantainers
|
|
106
|
+
deny
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Staff
|
|
111
|
+
scope :staff do
|
|
112
|
+
permissions do
|
|
113
|
+
allow :administrators, :mantainers
|
|
114
|
+
allow :editors, :to => [:edit, :update]
|
|
115
|
+
allow :authors, :to => [:new, :create]
|
|
116
|
+
allow :owners, :to => [:edit, :update]
|
|
117
|
+
deny
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
permissions :for => :guides do
|
|
121
|
+
allow :administrators, :mantainers
|
|
122
|
+
allow :logged_in, :to => [:index, :show]
|
|
123
|
+
deny
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
permissions :for => :drafts do
|
|
127
|
+
allow :authors, :to => :submit
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
permissions_to_set :published do
|
|
131
|
+
allow :editors, :administrators, :mantainers
|
|
132
|
+
deny
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Use in controller
|
|
140
|
+
|
|
141
|
+
_ex._
|
|
142
|
+
|
|
143
|
+
``` rb
|
|
144
|
+
class ApplicationController < ActionController::Base
|
|
145
|
+
rescue_from Checkin::AccessDenied, :with => :rescue_access_denied
|
|
146
|
+
|
|
147
|
+
protect_from_forgery
|
|
148
|
+
checkin(:scope => :admin)
|
|
149
|
+
|
|
150
|
+
protected
|
|
151
|
+
|
|
152
|
+
def rescue_access_denied
|
|
153
|
+
if subject.guest?
|
|
154
|
+
redirect_to new_user_session_path, :notice => "Accedi per completare l'operazione"
|
|
155
|
+
else
|
|
156
|
+
render :text => "Not Authorized", :status => 403
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
Copyright (c) 2012 mcasimir
|
|
169
|
+
|
|
170
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
171
|
+
a copy of this software and associated documentation files (the
|
|
172
|
+
"Software"), to deal in the Software without restriction, including
|
|
173
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
174
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
175
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
176
|
+
the following conditions:
|
|
177
|
+
|
|
178
|
+
The above copyright notice and this permission notice shall be
|
|
179
|
+
included in all copies or substantial portions of the Software.
|
|
180
|
+
|
|
181
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
182
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
183
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
184
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
185
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
186
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
187
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
188
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
begin
|
|
6
|
+
Bundler.setup(:default, :development)
|
|
7
|
+
rescue Bundler::BundlerError => e
|
|
8
|
+
$stderr.puts e.message
|
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
10
|
+
exit e.status_code
|
|
11
|
+
end
|
|
12
|
+
require 'rake'
|
|
13
|
+
|
|
14
|
+
require 'jeweler'
|
|
15
|
+
Jeweler::Tasks.new do |gem|
|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
17
|
+
gem.name = "checkin"
|
|
18
|
+
gem.homepage = "http://github.com/mcasimir/checkin"
|
|
19
|
+
gem.license = "MIT"
|
|
20
|
+
gem.summary = %Q{Checkin is an authorization gem for Ruby on Rails}
|
|
21
|
+
gem.description = %Q{Checkin is an authorization gem for Ruby on Rails}
|
|
22
|
+
gem.email = "maurizio.cas@gmail.com"
|
|
23
|
+
gem.authors = ["mcasimir"]
|
|
24
|
+
# dependencies defined in Gemfile
|
|
25
|
+
end
|
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.4.3
|
data/checkin.gemspec
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = "checkin"
|
|
8
|
+
s.version = "0.4.3"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["mcasimir"]
|
|
12
|
+
s.date = "2012-05-07"
|
|
13
|
+
s.description = "Checkin is an authorization gem for Ruby on Rails"
|
|
14
|
+
s.email = "maurizio.cas@gmail.com"
|
|
15
|
+
s.extra_rdoc_files = [
|
|
16
|
+
"LICENSE.txt",
|
|
17
|
+
"README.md"
|
|
18
|
+
]
|
|
19
|
+
s.files = [
|
|
20
|
+
".document",
|
|
21
|
+
"Gemfile",
|
|
22
|
+
"Gemfile.lock",
|
|
23
|
+
"LICENSE.txt",
|
|
24
|
+
"README.md",
|
|
25
|
+
"Rakefile",
|
|
26
|
+
"VERSION",
|
|
27
|
+
"checkin.gemspec",
|
|
28
|
+
"lib/checkin.rb",
|
|
29
|
+
"lib/checkin/access_denied.rb",
|
|
30
|
+
"lib/checkin/dsl/permissions.rb",
|
|
31
|
+
"lib/checkin/dsl/roles.rb",
|
|
32
|
+
"lib/checkin/filters.rb",
|
|
33
|
+
"lib/checkin/role.rb",
|
|
34
|
+
"lib/checkin/rule.rb",
|
|
35
|
+
"lib/checkin/subject.rb",
|
|
36
|
+
"test/helper.rb",
|
|
37
|
+
"test/test_checkin.rb"
|
|
38
|
+
]
|
|
39
|
+
s.homepage = "http://github.com/mcasimir/checkin"
|
|
40
|
+
s.licenses = ["MIT"]
|
|
41
|
+
s.require_paths = ["lib"]
|
|
42
|
+
s.rubygems_version = "1.8.24"
|
|
43
|
+
s.summary = "Checkin is an authorization gem for Ruby on Rails"
|
|
44
|
+
|
|
45
|
+
if s.respond_to? :specification_version then
|
|
46
|
+
s.specification_version = 3
|
|
47
|
+
|
|
48
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
49
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
|
50
|
+
else
|
|
51
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
module Checkin
|
|
24
|
+
class AccessDenied < StandardError
|
|
25
|
+
attr_reader :subject, :action, :resource, :object
|
|
26
|
+
|
|
27
|
+
def initialize(subject, action, object_or_resource, options = {})
|
|
28
|
+
|
|
29
|
+
@message = options[:message]
|
|
30
|
+
@subject = subject
|
|
31
|
+
@action = action
|
|
32
|
+
@object = ( object_or_resource.is_a?(Symbol) || object_or_resource.is_a?(String)) ? nil : object_or_resource
|
|
33
|
+
@resource = object ? object.class.name.demodulize.underscore.to_sym : "#{object_or_resource}".singularize.to_sym
|
|
34
|
+
|
|
35
|
+
@default_message = I18n.t(:"unauthorized.default", :default => "You are not authorized to access this page.")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def scope
|
|
39
|
+
@subject.scope if @subject
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
@message || @default_message
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require 'checkin/rule'
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Permissions DSL
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
module Checkin
|
|
30
|
+
module Dsl
|
|
31
|
+
module Permissions
|
|
32
|
+
extend ActiveSupport::Concern
|
|
33
|
+
|
|
34
|
+
included do
|
|
35
|
+
attr_writer :explain
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module ClassMethods
|
|
39
|
+
|
|
40
|
+
def rules
|
|
41
|
+
@rules ||= []
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def add_rule_block(rules)
|
|
45
|
+
@rules ||= []
|
|
46
|
+
@rules = rules + @rules
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def attribute_rules
|
|
50
|
+
@attribute_rules ||= []
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def add_attribute_rules_block(rules)
|
|
54
|
+
@attribute_rules ||= []
|
|
55
|
+
@attribute_rules = rules + @attribute_rules
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def scope(scope, &block)
|
|
59
|
+
_current_options[:scope] = scope
|
|
60
|
+
yield
|
|
61
|
+
_current_options.delete(:scope)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def permissions(*args)
|
|
65
|
+
_current_options[:mode] = :cascade
|
|
66
|
+
opts = args.extract_options!
|
|
67
|
+
_current_options[:resources] = [opts[:for]].flatten.compact.uniq.map {|r| "#{r}".singularize.to_sym}
|
|
68
|
+
yield
|
|
69
|
+
add_rule_block(_current_rule_block)
|
|
70
|
+
_reset_current_options
|
|
71
|
+
_reset_current_rule_block
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def permissions_to_set(*args)
|
|
75
|
+
_current_options[:mode] = :attributes
|
|
76
|
+
opts = args.extract_options!
|
|
77
|
+
resources_options = opts[:on]
|
|
78
|
+
_current_options[:resources] = [resources_options].flatten.compact.uniq.map {|r| "#{r}".singularize.to_sym}
|
|
79
|
+
_current_options[:attributes] = args.flatten
|
|
80
|
+
yield
|
|
81
|
+
add_attribute_rules_block(_current_attributes_block)
|
|
82
|
+
_reset_current_options
|
|
83
|
+
_reset_current_attributes_block
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def allow(*args)
|
|
87
|
+
if _current_options[:mode] == :cascade
|
|
88
|
+
_add_rule_to_current_rule_block(:allow, *args)
|
|
89
|
+
elsif _current_options[:mode] == :attributes
|
|
90
|
+
_add_rule_to_current_attributes_block(:allow, *args)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def deny(*args)
|
|
95
|
+
if _current_options[:mode] == :cascade
|
|
96
|
+
_add_rule_to_current_rule_block(:deny, *args)
|
|
97
|
+
elsif _current_options[:mode] == :attributes
|
|
98
|
+
_add_rule_to_current_attributes_block(:deny, *args)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def _current_options
|
|
103
|
+
@_current_options ||= ::ActiveSupport::HashWithIndifferentAccess.new
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def _reset_current_options
|
|
107
|
+
scope = _current_options[:scope]
|
|
108
|
+
@_current_options = ::ActiveSupport::HashWithIndifferentAccess.new
|
|
109
|
+
@_current_options[:scope] = scope
|
|
110
|
+
@_current_options
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def _current_rule_block
|
|
114
|
+
@_current_rule_block ||= []
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def _reset_current_rule_block
|
|
118
|
+
@_current_rule_block = []
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def _add_rule_to_current_rule_block(kind, *args)
|
|
122
|
+
opts = args.extract_options!
|
|
123
|
+
actions = _actions_from_options(args, opts)
|
|
124
|
+
roles = _roles_from_options(args, opts)
|
|
125
|
+
|
|
126
|
+
rule = ::Checkin::Rule.new(kind, :resources => _current_options[:resources], :roles => roles, :actions_or_attributes => actions, :scope => _current_options[:scope])
|
|
127
|
+
|
|
128
|
+
@_current_rule_block ||= []
|
|
129
|
+
@_current_rule_block << rule
|
|
130
|
+
|
|
131
|
+
rule
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def _current_attributes_block
|
|
135
|
+
@_current_attributes_block ||= []
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def _reset_current_attributes_block
|
|
139
|
+
@_current_attributes_block = []
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def _add_rule_to_current_attributes_block(kind, *args)
|
|
143
|
+
opts = args.extract_options!
|
|
144
|
+
roles = _roles_from_options(args, opts)
|
|
145
|
+
|
|
146
|
+
rule = ::Checkin::Rule.new(kind, :resources => _current_options[:resources], :roles => roles, :actions_or_attributes => _current_options[:attributes], :scope => _current_options[:scope])
|
|
147
|
+
|
|
148
|
+
@_current_attributes_block ||= []
|
|
149
|
+
@_current_attributes_block << rule
|
|
150
|
+
|
|
151
|
+
rule
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def _actions_from_options(args, opts)
|
|
155
|
+
[ opts[:to] ].flatten.compact.uniq.map {|a| "#{a}".to_sym}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def _roles_from_options(args, opts)
|
|
159
|
+
args.flatten.compact.uniq.map {|a| "#{a}".singularize.to_sym}
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require 'checkin/role'
|
|
24
|
+
|
|
25
|
+
module Checkin
|
|
26
|
+
module Dsl
|
|
27
|
+
module Roles
|
|
28
|
+
extend ActiveSupport::Concern
|
|
29
|
+
|
|
30
|
+
module ClassMethods
|
|
31
|
+
|
|
32
|
+
def role(*args, &block)
|
|
33
|
+
opts = args.extract_options!
|
|
34
|
+
|
|
35
|
+
if args.empty?
|
|
36
|
+
raise ::ArgumentError.new("wrong number of arguments")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
role_name = args.first
|
|
40
|
+
|
|
41
|
+
if role_name.to_s =~ /^can_([A-z]_)+\?$/
|
|
42
|
+
raise "bad role name: '#{role_name}'. Roles can not be in the form of 'can [...]?''"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if role_name.to_s.singularize != role_name.to_s
|
|
46
|
+
raise "bad role name: '#{role_name}'. Roles can not be in the plural form"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
role = ::Checkin::Role.new
|
|
50
|
+
role.name = role_name
|
|
51
|
+
role.dependencies = [ opts[:require] ].flatten.compact.uniq
|
|
52
|
+
role.check_proc = block
|
|
53
|
+
role.aliases = ([ opts[:alias] ] + [ opts[:aliases] ]).flatten.compact.uniq.map {|a| "#{a.to_s.gsub(/\?$/, "")}?"}
|
|
54
|
+
role.check_method_name = "#{(opts[:method] || role_name).to_s.gsub(/\?$/, "")}?"
|
|
55
|
+
|
|
56
|
+
self.register_role(role)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def roles
|
|
60
|
+
@roles ||= ::ActiveSupport::HashWithIndifferentAccess.new
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def role_methods
|
|
64
|
+
@role_methods ||= ::ActiveSupport::HashWithIndifferentAccess.new
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def register_role(role)
|
|
68
|
+
|
|
69
|
+
self.register_role_method(role.check_method_name, role)
|
|
70
|
+
|
|
71
|
+
role.aliases.each do |a|
|
|
72
|
+
self.register_role_method(a, role)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
self.roles[role.name] = role
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def register_role_method(meth, role)
|
|
80
|
+
self.role_methods[meth] = role
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def find_role_by_method(meth)
|
|
84
|
+
self.role_methods[meth]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def find_role_by_name(name)
|
|
88
|
+
self.roles[name]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def role_names
|
|
92
|
+
self.roles.keys.map {|k| k.to_s}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def symbolized_role_names
|
|
96
|
+
self.roles.keys.map {|k| k.to_sym}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def roles(*args)
|
|
102
|
+
roles = []
|
|
103
|
+
self.class.roles.each do |role_key, role|
|
|
104
|
+
roles << "#{role_key}".to_sym if check_role(role, *args)
|
|
105
|
+
end
|
|
106
|
+
roles
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def role?(role, *args)
|
|
110
|
+
!!( check_role(role, *args) if (role = find_role_by_name(name)) )
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
protected
|
|
114
|
+
|
|
115
|
+
def find_role_by_method(meth)
|
|
116
|
+
self.class.find_role_by_method(meth)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def find_role_by_name(name)
|
|
120
|
+
self.class.find_role_by_name(name)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def is_role_method?(meth)
|
|
124
|
+
!!find_role_by_method(meth)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def check_role(role, *args)
|
|
128
|
+
|
|
129
|
+
roles_chain = role.dependencies.map{|d|
|
|
130
|
+
find_role_by_name(d) || (raise "required role not found '#{d}' for '#{role.name}")
|
|
131
|
+
} + [role]
|
|
132
|
+
|
|
133
|
+
roles_chain.each do |chain_role|
|
|
134
|
+
check_proc = chain_role.check_proc
|
|
135
|
+
check_args = args.slice(0, chain_role.check_proc.arity)
|
|
136
|
+
|
|
137
|
+
if !instance_exec(*check_args, &check_proc)
|
|
138
|
+
return false
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
true
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Checkin
|
|
2
|
+
module Filters
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
module ClassMethods
|
|
6
|
+
# checkin(:subject => :user, :scope => nil, :skip_authorization => false, :object => :object, rescue_with => lambda {
|
|
7
|
+
# if subject.guest?
|
|
8
|
+
# redirect_to new_user_session_path, :notice => "Accedi per completare l'operazione"
|
|
9
|
+
# else
|
|
10
|
+
# render :text => "Not Authorized", :status => 403
|
|
11
|
+
# end
|
|
12
|
+
# })
|
|
13
|
+
|
|
14
|
+
def checkin(opts = {})
|
|
15
|
+
opts.symbolize_keys!
|
|
16
|
+
from_subject = :"#{(opts[:subject] || :user_subject)}"
|
|
17
|
+
subject_name = :"#{(opts[:as] || :subject)}"
|
|
18
|
+
subject_model = :"#{(opts[:from] || :current_user)}"
|
|
19
|
+
subject_class = from_subject.to_s.camelize.constantize
|
|
20
|
+
object_method = :"#{(opts[:object] || :fetch_object)}"
|
|
21
|
+
find_method = opts[:find_object]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
define_method "#{subject_name}" do
|
|
25
|
+
if !instance_variable_get("@checkin_#{subject_name}")
|
|
26
|
+
instance_variable_set("@checkin_#{subject_name}", subject_class.new(self.send(subject_model), :scope => opts[:scope]))
|
|
27
|
+
else
|
|
28
|
+
instance_variable_get("@checkin_#{subject_name}")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
helper_method :"#{subject_name}"
|
|
33
|
+
|
|
34
|
+
if opts[:rescue_with]
|
|
35
|
+
block = opts[:rescue_with]
|
|
36
|
+
define_method :rescue_from_checkin_access_denied, &block
|
|
37
|
+
rescue_from Checkin::AccessDenied, :with => :rescue_from_checkin_access_denied
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if !opts[:skip_authorization]
|
|
41
|
+
define_method :"#{object_method}" do
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if params[:id]
|
|
45
|
+
model_class = self.controller_name.singularize.camelize.constantize
|
|
46
|
+
singular_name = :"#{model_class.name.underscore.singularize}"
|
|
47
|
+
if !instance_variable_get("@#{singular_name}")
|
|
48
|
+
find_method = if find_method.nil?
|
|
49
|
+
Proc.new {|model_class, params|
|
|
50
|
+
model_class.find(params[:id])
|
|
51
|
+
}
|
|
52
|
+
elsif find_method.is_a?(Proc) || find_method.is_a?(Method)
|
|
53
|
+
find_method
|
|
54
|
+
elsif find_method.is_a?(Symbol) || find_method.is_a?(String)
|
|
55
|
+
self.method(find_method)
|
|
56
|
+
else
|
|
57
|
+
raise "'#{find_method.class.name}' is an invalid type for find method"
|
|
58
|
+
end
|
|
59
|
+
instance_variable_set("@#{singular_name}", find_method.call(model_class, params))
|
|
60
|
+
else
|
|
61
|
+
instance_variable_get("@#{singular_name}")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
before_filter do |controller|
|
|
67
|
+
if Rails.env.development?
|
|
68
|
+
controller.send(subject_name).explain!
|
|
69
|
+
end
|
|
70
|
+
controller.send(subject_name).checkin!( :"#{controller.action_name}", (controller.send(:"#{object_method}") || {:for => :"#{controller.controller_name}"}) )
|
|
71
|
+
controller.send(subject_name).delete_denied_params( :"#{controller.action_name}", (controller.send(:"#{object_method}") || {:for => :"#{controller.controller_name}"}), (params[:"#{controller.controller_name.singularize}"] || {}) )
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
data/lib/checkin/role.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
class Checkin::Role
|
|
24
|
+
attr_accessor :name, :dependencies, :check_proc, :aliases, :check_method_name
|
|
25
|
+
end
|
|
26
|
+
|
data/lib/checkin/rule.rb
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
class Checkin::Rule
|
|
24
|
+
attr_accessor :kind, :actions_or_attributes, :roles, :resources, :scope
|
|
25
|
+
|
|
26
|
+
def initialize(kind, *args)
|
|
27
|
+
opts = args.extract_options!
|
|
28
|
+
@kind = kind
|
|
29
|
+
@actions_or_attributes = (opts[:actions_or_attributes] || []).map {|a| "#{a}".to_sym }
|
|
30
|
+
@roles = (opts[:roles] || []).map {|r| "#{r}".to_sym }
|
|
31
|
+
@resources = (opts[:resources] || []).map {|r| "#{r}".singularize.to_sym }
|
|
32
|
+
@scope = opts[:scope].present? ? opts[:scope].to_sym : nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def check(subject, action_or_attribute, object_or_resource)
|
|
36
|
+
scope = subject.scope
|
|
37
|
+
action = "#{action}".to_sym
|
|
38
|
+
|
|
39
|
+
object_or_resource = object_or_resource[:for] if object_or_resource.is_a?(Hash)
|
|
40
|
+
object = ( object_or_resource.is_a?(Symbol) || object_or_resource.is_a?(String)) ? nil : object_or_resource
|
|
41
|
+
resource = object ? object.class.name.demodulize.underscore.to_sym : "#{object_or_resource}".singularize.to_sym
|
|
42
|
+
|
|
43
|
+
if affect_scope?(scope) && affect_role?(subject, object) && affect_action_or_attribute?(action_or_attribute) && affect_resource?(resource)
|
|
44
|
+
deny? ? :denied : :allowed
|
|
45
|
+
else
|
|
46
|
+
:skip
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
formatted_roles = roles.map {|r| ":#{r}" }.join(", ") if roles.any?
|
|
52
|
+
formatted_actions = ":to => [" + actions_or_attributes.map {|a| ":#{a}" }.join(", ") + "]" if actions_or_attributes.any?
|
|
53
|
+
formatted_scope = ":scope => :#{scope}" if scope
|
|
54
|
+
formatted_resources = ":resources => [" + actions_or_attributes.map {|r| ":#{r}" }.join(", ") + "]" if resources.any?
|
|
55
|
+
args = [formatted_roles, formatted_actions, formatted_resources, formatted_scope].compact.join(", ")
|
|
56
|
+
"#{kind}(#{args})"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def affect_scope?(scope)
|
|
62
|
+
scope && ( any_scope? || @scope == scope.to_sym )
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def affect_role?(subject, object)
|
|
66
|
+
args = [object].compact
|
|
67
|
+
any_role? || (subject.roles(*args) & @roles).any?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def affect_action_or_attribute?(action_or_attribute)
|
|
71
|
+
any_action_or_attribute? || @actions_or_attributes.include?(action_or_attribute)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def affect_resource?(resource)
|
|
75
|
+
any_resource? || @resources.include?(resource)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def any_role?
|
|
79
|
+
!!@roles.empty?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def any_action_or_attribute?
|
|
83
|
+
!!@actions_or_attributes.empty?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def any_scope?
|
|
87
|
+
@scope.blank?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def any_resource?
|
|
91
|
+
!!@resources.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def deny?
|
|
95
|
+
@kind == :deny
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def allow?
|
|
99
|
+
@kind == :allow
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require 'checkin/dsl/roles'
|
|
24
|
+
require 'checkin/dsl/permissions'
|
|
25
|
+
|
|
26
|
+
class Checkin::Subject
|
|
27
|
+
include ::Checkin::Dsl::Roles
|
|
28
|
+
include ::Checkin::Dsl::Permissions
|
|
29
|
+
|
|
30
|
+
def initialize(subject_model, scope = {})
|
|
31
|
+
@subject_model = subject_model
|
|
32
|
+
@scope = scope[:scope]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def subject_model
|
|
36
|
+
@subject_model
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def scope
|
|
40
|
+
:"#{@scope}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def can?(action, object_or_resource)
|
|
44
|
+
|
|
45
|
+
if @explain
|
|
46
|
+
Rails.logger.info " + can?(:#{action}, #{object_or_resource})"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
self.class.rules.each do|rule|
|
|
50
|
+
result = rule.check(self, :"#{action}", object_or_resource)
|
|
51
|
+
|
|
52
|
+
if @explain
|
|
53
|
+
Rails.logger.info [" - #{rule}".ljust(65), ":#{result}"].join(" => ")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
case result
|
|
57
|
+
when :denied
|
|
58
|
+
return false
|
|
59
|
+
when :allowed
|
|
60
|
+
return true
|
|
61
|
+
else
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def allowed_to_set?(attribute, on = {})
|
|
68
|
+
|
|
69
|
+
object = on[:on]
|
|
70
|
+
if @explain
|
|
71
|
+
Rails.logger.info " + allowed_to_set?(:#{attribute}, on => #{object})"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
self.class.attribute_rules.each do|rule|
|
|
75
|
+
result = rule.check(self, :"#{attribute}", object)
|
|
76
|
+
|
|
77
|
+
if @explain
|
|
78
|
+
Rails.logger.info [" - #{rule}".ljust(65), ":#{result}"].join(" => ")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
case result
|
|
82
|
+
when :denied
|
|
83
|
+
return false
|
|
84
|
+
when :allowed
|
|
85
|
+
return true
|
|
86
|
+
else
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def explain!
|
|
94
|
+
@explain = true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def stop_explaining!
|
|
98
|
+
@explain = false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def checkin!(action, object_or_resource)
|
|
102
|
+
raise Checkin::AccessDenied.new(self, action, object_or_resource) unless self.can?(action, object_or_resource)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def delete_denied_params(action, object_or_resource, resource_params)
|
|
106
|
+
to_be_deleted = []
|
|
107
|
+
resource_params.keys.each {|key|
|
|
108
|
+
to_be_deleted.push(key) unless self.allowed_to_set?(key, :on => object_or_resource)
|
|
109
|
+
}
|
|
110
|
+
to_be_deleted.each do |key_to_delete|
|
|
111
|
+
resource_params.delete(key_to_delete)
|
|
112
|
+
end
|
|
113
|
+
resource_params
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def method_missing(mid, *args)
|
|
117
|
+
missing_method = mid.to_s
|
|
118
|
+
prefixed_with_can = (missing_method =~ /^can_/) && (missing_method =~ /\?$/)
|
|
119
|
+
|
|
120
|
+
if prefixed_with_can
|
|
121
|
+
action = missing_method.gsub(/^can_/, "").gsub(/\?$/, "")
|
|
122
|
+
self.can?(action, *args)
|
|
123
|
+
|
|
124
|
+
elsif self.respond_to?(:"is_role_method?") && self.is_role_method?(missing_method)
|
|
125
|
+
role = self.find_role_by_method(missing_method)
|
|
126
|
+
self.check_role(role, *args)
|
|
127
|
+
|
|
128
|
+
elsif @subject_model && @subject_model.respond_to?(missing_method)
|
|
129
|
+
@subject_model.send(missing_method, *args)
|
|
130
|
+
|
|
131
|
+
else
|
|
132
|
+
raise NoMethodError.new("undefined method `#{missing_method}' for #{self.class.name}")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
data/lib/checkin.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Author:: Maurizio Casimirri (mailto:maurizio.cas@gmail.com)
|
|
2
|
+
# Copyright:: Copyright (c) 2012 Maurizio Casimirri
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
module Checkin
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require 'checkin/filters'
|
|
27
|
+
require 'checkin/subject'
|
|
28
|
+
require 'checkin/access_denied'
|
|
29
|
+
|
|
30
|
+
class ActionController::Base
|
|
31
|
+
include Checkin::Filters
|
|
32
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler'
|
|
3
|
+
begin
|
|
4
|
+
Bundler.setup(:default, :development)
|
|
5
|
+
rescue Bundler::BundlerError => e
|
|
6
|
+
$stderr.puts e.message
|
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
8
|
+
exit e.status_code
|
|
9
|
+
end
|
|
10
|
+
require 'test/unit'
|
|
11
|
+
require 'shoulda'
|
|
12
|
+
|
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
15
|
+
require 'checkin'
|
|
16
|
+
|
|
17
|
+
class Test::Unit::TestCase
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: checkin
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.4.3
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- mcasimir
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-05-07 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: jeweler
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.8.3
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 1.8.3
|
|
30
|
+
description: Checkin is an authorization gem for Ruby on Rails
|
|
31
|
+
email: maurizio.cas@gmail.com
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files:
|
|
35
|
+
- LICENSE.txt
|
|
36
|
+
- README.md
|
|
37
|
+
files:
|
|
38
|
+
- .document
|
|
39
|
+
- Gemfile
|
|
40
|
+
- Gemfile.lock
|
|
41
|
+
- LICENSE.txt
|
|
42
|
+
- README.md
|
|
43
|
+
- Rakefile
|
|
44
|
+
- VERSION
|
|
45
|
+
- checkin.gemspec
|
|
46
|
+
- lib/checkin.rb
|
|
47
|
+
- lib/checkin/access_denied.rb
|
|
48
|
+
- lib/checkin/dsl/permissions.rb
|
|
49
|
+
- lib/checkin/dsl/roles.rb
|
|
50
|
+
- lib/checkin/filters.rb
|
|
51
|
+
- lib/checkin/role.rb
|
|
52
|
+
- lib/checkin/rule.rb
|
|
53
|
+
- lib/checkin/subject.rb
|
|
54
|
+
- test/helper.rb
|
|
55
|
+
- test/test_checkin.rb
|
|
56
|
+
homepage: http://github.com/mcasimir/checkin
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
post_install_message:
|
|
60
|
+
rdoc_options: []
|
|
61
|
+
require_paths:
|
|
62
|
+
- lib
|
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
64
|
+
none: false
|
|
65
|
+
requirements:
|
|
66
|
+
- - ! '>='
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
segments:
|
|
70
|
+
- 0
|
|
71
|
+
hash: 1307085424481181596
|
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
requirements: []
|
|
79
|
+
rubyforge_project:
|
|
80
|
+
rubygems_version: 1.8.24
|
|
81
|
+
signing_key:
|
|
82
|
+
specification_version: 3
|
|
83
|
+
summary: Checkin is an authorization gem for Ruby on Rails
|
|
84
|
+
test_files: []
|