patrick-lockdown 2.0.4.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/README.md +42 -0
- data/Rakefile +54 -0
- data/lib/lockdown.rb +42 -0
- data/lib/lockdown/access.rb +108 -0
- data/lib/lockdown/configuration.rb +209 -0
- data/lib/lockdown/database.rb +122 -0
- data/lib/lockdown/delivery.rb +28 -0
- data/lib/lockdown/errors.rb +7 -0
- data/lib/lockdown/frameworks/rails.rb +77 -0
- data/lib/lockdown/frameworks/rails/controller.rb +145 -0
- data/lib/lockdown/frameworks/rails/view.rb +51 -0
- data/lib/lockdown/helper.rb +40 -0
- data/lib/lockdown/orms/active_record.rb +66 -0
- data/lib/lockdown/permission.rb +56 -0
- data/lib/lockdown/resource.rb +54 -0
- data/lib/lockdown/session.rb +50 -0
- data/lib/lockdown/user_group.rb +16 -0
- data/patrick-lockdown.gemspec +62 -0
- data/tags +142 -0
- data/test/helper.rb +10 -0
- data/test/lockdown/test_access.rb +80 -0
- data/test/lockdown/test_configuration.rb +195 -0
- data/test/lockdown/test_delivery.rb +224 -0
- data/test/lockdown/test_helper.rb +33 -0
- data/test/lockdown/test_permission.rb +73 -0
- data/test/lockdown/test_resource.rb +47 -0
- data/test/lockdown/test_session.rb +31 -0
- data/test/lockdown/test_user_group.rb +17 -0
- metadata +96 -0
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
## Description
|
2
|
+
|
3
|
+
**Lockdown 2.0.x does not support a Rails application that is deployed to a subdirectory, although Lockdown 1.x did.
|
4
|
+
It looks like Lockdown is no longer maintained by Andy Stone since it has been removed from github.
|
5
|
+
Therefore we use updated Lockdown 2.0.4, renamed it and added it to github.**
|
6
|
+
|
7
|
+
Lockdown is an authorization system for RubyOnRails. It is designed to handle a simple public vs private configuration to very fine grained access controls.
|
8
|
+
|
9
|
+
If you are starting a site and just have public and protected (user required) areas, use Lockdown. Lockdown includes built in user groups of public and protected. From there you can easily add/extend permissions and create new user groups as your site needs grow.
|
10
|
+
|
11
|
+
If you already have a complex permission scheme, use Lockdown to simplify the management of access rules.
|
12
|
+
|
13
|
+
Follow me on Twitter (@stonean) to keep up to date.
|
14
|
+
|
15
|
+
## DOCS:
|
16
|
+
|
17
|
+
[http://docs.stonean.com/page/lockdown](http://docs.stonean.com/page/lockdown)
|
18
|
+
|
19
|
+
## LICENSE:
|
20
|
+
|
21
|
+
(The MIT License)
|
22
|
+
|
23
|
+
Copyright (c) 2010 Andrew Stone
|
24
|
+
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
26
|
+
a copy of this software and associated documentation files (the
|
27
|
+
'Software'), to deal in the Software without restriction, including
|
28
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
29
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
30
|
+
permit persons to whom the Software is furnished to do so, subject to
|
31
|
+
the following conditions:
|
32
|
+
|
33
|
+
The above copyright notice and this permission notice shall be
|
34
|
+
included in all copies or substantial portions of the Software.
|
35
|
+
|
36
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
37
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
38
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
39
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
40
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
41
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
42
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), "lib", "lockdown")
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = "patrick-lockdown"
|
10
|
+
gem.version = Lockdown.version
|
11
|
+
gem.summary = "Authorization system for Rails"
|
12
|
+
gem.description = "Restrict access to your controller actions. "
|
13
|
+
gem.email = "patrick.baselier@gmail.com"
|
14
|
+
gem.homepage = "https://github.com/ludo/patrick-lockdown"
|
15
|
+
gem.authors = ["Andrew Stone", "Patrick Baselier"]
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'yard'
|
24
|
+
YARD::Rake::YardocTask.new do |t|
|
25
|
+
t.files = FileList['lib/**/*.rb']
|
26
|
+
t.options = ['-r'] # optional
|
27
|
+
end
|
28
|
+
rescue LoadError
|
29
|
+
task :yard do
|
30
|
+
abort "YARD is not available. In order to run yard, you must: sudo gem install yard"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'rake/testtask'
|
35
|
+
Rake::TestTask.new(:test) do |test|
|
36
|
+
test.libs << 'lib' << 'test'
|
37
|
+
test.pattern = 'test/**/test_*.rb'
|
38
|
+
test.verbose = true
|
39
|
+
end
|
40
|
+
|
41
|
+
begin
|
42
|
+
require 'rcov/rcovtask'
|
43
|
+
Rcov::RcovTask.new do |test|
|
44
|
+
test.libs << 'test'
|
45
|
+
test.pattern = 'test/**/test_*.rb'
|
46
|
+
test.verbose = true
|
47
|
+
end
|
48
|
+
rescue LoadError
|
49
|
+
task :rcov do
|
50
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
task :default => 'test'
|
data/lib/lockdown.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__)
|
4
|
+
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
require File.join("lockdown", "errors")
|
8
|
+
require File.join("lockdown", "helper")
|
9
|
+
require File.join("lockdown", "configuration")
|
10
|
+
require File.join("lockdown", "session")
|
11
|
+
require File.join("lockdown", "delivery")
|
12
|
+
require File.join("lockdown", "resource")
|
13
|
+
require File.join("lockdown", "permission")
|
14
|
+
require File.join("lockdown", "user_group")
|
15
|
+
require File.join("lockdown", "access")
|
16
|
+
require File.join("lockdown", "database")
|
17
|
+
|
18
|
+
|
19
|
+
module Lockdown
|
20
|
+
extend Lockdown::Helper
|
21
|
+
|
22
|
+
class << self
|
23
|
+
attr_accessor :logger
|
24
|
+
|
25
|
+
# @return the version string for the library.
|
26
|
+
def version
|
27
|
+
'2.0.4.1'
|
28
|
+
end
|
29
|
+
|
30
|
+
def rails_mixin
|
31
|
+
require File.join("lockdown", "frameworks", "rails")
|
32
|
+
include Lockdown::Frameworks::Rails
|
33
|
+
|
34
|
+
require File.join("lockdown", "orms", "active_record")
|
35
|
+
include Lockdown::Orms::ActiveRecord
|
36
|
+
end
|
37
|
+
|
38
|
+
end # class block
|
39
|
+
|
40
|
+
self.logger = Logger.new(STDOUT)
|
41
|
+
|
42
|
+
end # Lockdown
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Lockdown
|
4
|
+
module Access
|
5
|
+
# Define permision that defines how your application is accessed.
|
6
|
+
# # All methods on the site resource will be open to users who have
|
7
|
+
# # this permission.
|
8
|
+
# permission :public_pages do
|
9
|
+
# resource :site
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# # Can use multiple resource statements
|
13
|
+
# permission :public_pages do
|
14
|
+
# resource :site
|
15
|
+
# resource :posts
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # Only methods show, edit and update on the users resource will
|
19
|
+
# # be open to users who have this permission.
|
20
|
+
# permission :my_account_pages do
|
21
|
+
# resource :users do
|
22
|
+
# only :show, :edit, :update
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # All methods except destroy on the users resource will be
|
27
|
+
# # open to users who have this permission.
|
28
|
+
# permission :manage_users do
|
29
|
+
# resource :users do
|
30
|
+
# except :destroy
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @param [String,Symbol] name permission reference.
|
35
|
+
# @yield [Lockdown::Permission.new(name)] new permission object
|
36
|
+
def permission(name, &block)
|
37
|
+
permission = Lockdown::Permission.new(name)
|
38
|
+
if block_given?
|
39
|
+
permission.instance_eval(&block)
|
40
|
+
else
|
41
|
+
permission.resource(permission.name)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless Lockdown::Configuration.has_permission?(permission)
|
45
|
+
Lockdown::Configuration.permissions << permission
|
46
|
+
end
|
47
|
+
|
48
|
+
permission
|
49
|
+
end
|
50
|
+
|
51
|
+
# Define which permissions are accessible to everyone
|
52
|
+
# public_access :site, :user_registration
|
53
|
+
#
|
54
|
+
# @param *[String,Symbol] permissions that are accessible to everyone
|
55
|
+
def public_access(*permissions)
|
56
|
+
permissions.each do |name|
|
57
|
+
Lockdown::Configuration.make_permission_public(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
Lockdown::Configuration.public_access = regexes(permissions)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Define which permissions are accessible to everyone
|
64
|
+
# protected_access :my_account, :site_administration
|
65
|
+
#
|
66
|
+
# @param *[String,Symbol] permissions that are accessbile to authenticated users
|
67
|
+
def protected_access(*permissions)
|
68
|
+
permissions.each do |name|
|
69
|
+
Lockdown::Configuration.make_permission_protected(name)
|
70
|
+
end
|
71
|
+
|
72
|
+
Lockdown::Configuration.protected_access = regexes(permissions)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create user group by giving it a name and a list of permission names.
|
76
|
+
# @param [String, Array] user group name, permission names
|
77
|
+
def user_group(name, *permissions)
|
78
|
+
return if permissions.empty?
|
79
|
+
name = name.to_s
|
80
|
+
ug = Lockdown::Configuration.find_or_create_user_group(name)
|
81
|
+
|
82
|
+
permissions.each do |name|
|
83
|
+
if (perm = Lockdown::Configuration.permission(name))
|
84
|
+
ug.permissions << perm unless ug.permissions.include?(perm)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Lockdown::Configuration.maybe_add_user_group(ug)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Method called by Lockdown::Delivery to trigger parsing of class methods
|
92
|
+
def configure
|
93
|
+
unless Lockdown::Configuration.configured
|
94
|
+
Lockdown::Database.sync_with_db unless Lockdown::Configuration.skip_sync?
|
95
|
+
Lockdown::Configuration.configured = true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def regexes(permissions)
|
102
|
+
permissions.collect!{|p| p.to_s}
|
103
|
+
perms = Lockdown::Configuration.permissions.select{|p| permissions.include?(p.name)}
|
104
|
+
perms.collect{|p| p.regex_pattern}.join("|")
|
105
|
+
end
|
106
|
+
|
107
|
+
end # Access
|
108
|
+
end # Lockdown
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Lockdown
|
4
|
+
module Configuration
|
5
|
+
class << self
|
6
|
+
# Flag to determine if configuration method has been executed
|
7
|
+
# Default false
|
8
|
+
attr_accessor :configured
|
9
|
+
# Regex string of paths that are publicly accessible.
|
10
|
+
# Default "\/"
|
11
|
+
attr_accessor :public_access
|
12
|
+
# Array of paths that are restricted to an authenticated user.
|
13
|
+
# Default ""
|
14
|
+
attr_accessor :protected_access
|
15
|
+
# Array of permission objects that defines the access to the application.
|
16
|
+
# Default []
|
17
|
+
attr_accessor :permissions
|
18
|
+
# Array of user group objects
|
19
|
+
# Default []
|
20
|
+
attr_accessor :user_groups
|
21
|
+
# Method used to get the id of the user responsible for
|
22
|
+
# the current action.
|
23
|
+
# Default :current_user_id
|
24
|
+
attr_accessor :who_did_it
|
25
|
+
# User id to associate to system actions
|
26
|
+
# Default 1
|
27
|
+
attr_accessor :default_who_did_it
|
28
|
+
# Path to redirect to if access is denied.
|
29
|
+
# Default: '/'
|
30
|
+
attr_accessor :access_denied_path
|
31
|
+
# Redirect to path on successful login
|
32
|
+
# Default "/"
|
33
|
+
attr_accessor :successful_login_path
|
34
|
+
# Logout user if attempt to access restricted resource
|
35
|
+
# Default false
|
36
|
+
attr_accessor :logout_on_access_violation
|
37
|
+
# When using the links helper, this character will be
|
38
|
+
# used to separate the links.
|
39
|
+
# Default "|"
|
40
|
+
attr_accessor :link_separator
|
41
|
+
# The model used to represent the grouping of permisssion. Common
|
42
|
+
# choices are 'Role' and 'UserGroup'.
|
43
|
+
# Default "UserGroup"
|
44
|
+
attr_accessor :user_group_model
|
45
|
+
# The model used to represent the user. Common choices
|
46
|
+
# are 'User' and 'Person'.
|
47
|
+
# Default "User"
|
48
|
+
attr_accessor :user_model
|
49
|
+
# Which environments Lockdown should not sync with db
|
50
|
+
# Default ['test']
|
51
|
+
attr_accessor :skip_db_sync_in
|
52
|
+
# If deploying to a subdirectory, set that here. Defaults to nil
|
53
|
+
# Notice: Do not add leading or trailing slashes, Lockdown will handle this
|
54
|
+
attr_accessor :subdirectory
|
55
|
+
#
|
56
|
+
# Set defaults.
|
57
|
+
def reset
|
58
|
+
@configured = false
|
59
|
+
@public_access = ""
|
60
|
+
@protected_access = ""
|
61
|
+
@permissions = []
|
62
|
+
@user_groups = []
|
63
|
+
|
64
|
+
@who_did_it = :current_user_id
|
65
|
+
@default_who_did_it = 1
|
66
|
+
|
67
|
+
@access_denied_path = "/"
|
68
|
+
@successful_login_path = "/"
|
69
|
+
@logout_on_access_violation = false
|
70
|
+
|
71
|
+
@link_separator = "|"
|
72
|
+
|
73
|
+
@user_group_model = "UserGroup"
|
74
|
+
@user_model = "User"
|
75
|
+
|
76
|
+
@skip_db_sync_in = ['test']
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [String] concatentation of public_access + "|" + protected_access
|
80
|
+
def authenticated_access
|
81
|
+
public_access + "|" + protected_access
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param [String,Symbol] name permission name
|
85
|
+
# @return Lockdown::Permission object
|
86
|
+
def permission(name)
|
87
|
+
name = name.to_s
|
88
|
+
perm = permissions.detect{|perm| name == perm.name}
|
89
|
+
raise Lockdown::PermissionNotFound.new("Permission: #{name} not found") unless perm
|
90
|
+
perm
|
91
|
+
end
|
92
|
+
|
93
|
+
# Defines the permission as public
|
94
|
+
# @param [String,Symbol] name permission name
|
95
|
+
def make_permission_public(name)
|
96
|
+
permission(name).is_public
|
97
|
+
end
|
98
|
+
|
99
|
+
# Defines the permission as protected
|
100
|
+
# @param [String,Symbol] name permission name
|
101
|
+
def make_permission_protected(name)
|
102
|
+
permission(name).is_protected
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return Array of permission names
|
106
|
+
def permission_names
|
107
|
+
permissions.collect{|p| p.name}
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param [Lockdown::Permission] permission Lockdown::Permission object
|
111
|
+
# @return [true|false] true if object exists with same name
|
112
|
+
def has_permission?(permission)
|
113
|
+
permissions.any?{|p| permission.name == p.name}
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param [String|Symbol] name permission name
|
117
|
+
# @return [true|false] true if permission is either public or protected
|
118
|
+
def permission_assigned_automatically?(name)
|
119
|
+
name = name.to_s
|
120
|
+
|
121
|
+
perm = permission(name)
|
122
|
+
|
123
|
+
perm.public? || perm.protected?
|
124
|
+
end
|
125
|
+
|
126
|
+
# @param [String,Symbol] name user group name
|
127
|
+
# @return [Lockdown::UserGroup] object
|
128
|
+
def user_group(name)
|
129
|
+
name = name.to_s
|
130
|
+
user_groups.detect{|ug| name == ug.name}
|
131
|
+
end
|
132
|
+
|
133
|
+
def maybe_add_user_group(group)
|
134
|
+
@user_groups << group unless user_group_names.include?(group.name)
|
135
|
+
end
|
136
|
+
|
137
|
+
# @return [Lockdown::UserGroup]
|
138
|
+
def find_or_create_user_group(name)
|
139
|
+
name = name.to_s
|
140
|
+
user_group(name) || Lockdown::UserGroup.new(name)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Array] names
|
144
|
+
def user_group_names
|
145
|
+
user_groups.collect{|ug| ug.name}
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param [String] name user group name
|
149
|
+
# @return [Array] permissions names
|
150
|
+
def user_group_permissions_names(name)
|
151
|
+
user_group(name).permissions.collect{|p| p.name}
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [True|False] true if user has 'Administrators' group
|
155
|
+
def administrator?(user)
|
156
|
+
user_has_user_group?(user, Lockdown.administrator_group_name)
|
157
|
+
end
|
158
|
+
|
159
|
+
# @param [User] user User object you want to make an administrator
|
160
|
+
def make_user_administrator(user)
|
161
|
+
user_groups = user.send(Lockdown.user_groups_hbtm_reference)
|
162
|
+
user_groups << Lockdown.user_group_class.
|
163
|
+
find_or_create_by_name(Lockdown.administrator_group_name)
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
# @param [User, String] user,name user model, name of user group
|
168
|
+
# @return [True|False] true if user has user group with name
|
169
|
+
def user_has_user_group?(user, name)
|
170
|
+
user_groups = user.send(Lockdown.user_groups_hbtm_reference)
|
171
|
+
user_groups.any?{|ug| name == ug.name}
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return [Regex]
|
175
|
+
def access_rights_for_user(user)
|
176
|
+
return unless user
|
177
|
+
return Lockdown::Resource.regex if administrator?(user)
|
178
|
+
|
179
|
+
user_groups = user.send(Lockdown.user_groups_hbtm_reference)
|
180
|
+
|
181
|
+
permission_names = []
|
182
|
+
|
183
|
+
user_groups.each do |ug|
|
184
|
+
ug.permissions.each do |p|
|
185
|
+
permission_names << p.name
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
if permission_names.empty?
|
190
|
+
authenticated_access
|
191
|
+
else
|
192
|
+
authenticated_access + "|" + access_rights_for_permissions(*permission_names)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# @param [Array(String)] names permission names
|
197
|
+
# @return [String] combination of regex_patterns from permissions
|
198
|
+
def access_rights_for_permissions(*names)
|
199
|
+
names.collect{|name| "(#{permission(name).regex_pattern})"}.join('|')
|
200
|
+
end
|
201
|
+
|
202
|
+
def skip_sync?
|
203
|
+
true
|
204
|
+
end
|
205
|
+
end # class block
|
206
|
+
|
207
|
+
self.reset
|
208
|
+
end # Configuration
|
209
|
+
end # Lockdown
|