area_51 0.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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +0 -0
- data/Rakefile +2 -0
- data/area_51.gemspec +19 -0
- data/lib/area_51.rb +192 -0
- data/lib/area_51/authorization_trigger.rb +16 -0
- data/lib/area_51/version.rb +3 -0
- metadata +64 -0
data/Gemfile
ADDED
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
data/area_51.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "area_51/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "area_51"
|
7
|
+
s.version = Area51::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Chad Boyd"]
|
10
|
+
s.email = ["hoverlover@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/hoverlover"
|
12
|
+
s.summary = %q{Gem used for simple path-based access control.}
|
13
|
+
s.description = %q{Area51 allows you to define restricted and unrestricted sections of your application by defining paths in your controllers.}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
end
|
data/lib/area_51.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
module Area51
|
2
|
+
autoload :AuthorizationTrigger, 'area_51/authorization_trigger'
|
3
|
+
|
4
|
+
module ApiMethod
|
5
|
+
|
6
|
+
# This is the entry point into the Area51 library. Here are some usage examples:
|
7
|
+
#
|
8
|
+
# class ApplicationController < ActionController::Base
|
9
|
+
# area_51 do
|
10
|
+
# authorization_trigger("current_user.active?", :unrestricted) do
|
11
|
+
# restricted_area "^/memers_only"
|
12
|
+
# unrestricted_area "^/$"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# authorization_trigger(true, :restricted) do
|
16
|
+
# restricted_area "/top/secret/path"
|
17
|
+
# unrestricted_area "/anyone_allowed"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# trigger = proc {
|
21
|
+
# # Some useful trigger condition here
|
22
|
+
# }
|
23
|
+
# authorization_trigger(trigger) do
|
24
|
+
# unrestricted_area %r{^/totally_open}
|
25
|
+
# unrestricted_area %r{^/anyone_allowed$}
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# See documentation for authorization_trigger for details on how to use this method.
|
31
|
+
#
|
32
|
+
def area_51(&block)
|
33
|
+
self.send :extend, ClassMethods
|
34
|
+
self.send :include, InstanceMethods
|
35
|
+
|
36
|
+
self.default_access = :restricted
|
37
|
+
self.before_filter :area_51_check_access
|
38
|
+
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
|
45
|
+
def self.extended(klass)
|
46
|
+
klass.cattr_accessor :authorization_trigger_paths
|
47
|
+
klass.cattr_accessor :authorization_triggers
|
48
|
+
klass.cattr_accessor :safe_zone
|
49
|
+
klass.cattr_accessor :default_access
|
50
|
+
end
|
51
|
+
|
52
|
+
# Defines a trigger condition that when met, will cause authorization
|
53
|
+
# to be performed.
|
54
|
+
#
|
55
|
+
# The +trigger+ can be either a String, +lambda+, or Proc.
|
56
|
+
# If a String, it will be +eval+'d, if a +lambda+ or Proc, it will
|
57
|
+
# be called, and anything else will be returned as-is. If the result
|
58
|
+
# does not return an explicit +true+, authorization will not be performed.
|
59
|
+
#
|
60
|
+
# The +default_access+ parameter, if provided, must be one of +:restricted+ or
|
61
|
+
# +:unrestricted+. The default is +:restricted+. This specifies what type
|
62
|
+
# of access the undefined areas will have. For example:
|
63
|
+
#
|
64
|
+
# area_51 do
|
65
|
+
# authorization_trigger("current_user.active?", :unrestricted) do
|
66
|
+
# restricted_area "^/memers_only"
|
67
|
+
# unrestricted_area "^/$"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# Now if a user tries to access a path that isn't defined above, they will be granted access
|
72
|
+
# due to the +:unrestricted+ parameter.
|
73
|
+
#
|
74
|
+
def authorization_trigger(trigger, default_access = nil, &block)
|
75
|
+
trigger = AuthorizationTrigger.new(trigger, default_access)
|
76
|
+
|
77
|
+
yield
|
78
|
+
|
79
|
+
self.authorization_triggers ||= {}
|
80
|
+
self.authorization_triggers[trigger] = self.authorization_trigger_paths.dup
|
81
|
+
self.authorization_trigger_paths.clear
|
82
|
+
end
|
83
|
+
|
84
|
+
# Ties a restricted path to the authorization trigger. Must be
|
85
|
+
# called within an authorization_trigger block:
|
86
|
+
#
|
87
|
+
# authorization_trigger("current_user.signed_in?") do
|
88
|
+
# restricted_area %r{/top/secret/path/}
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# +path+ can be either a String or a Regexp. If a String, it will
|
92
|
+
# be converted to a Regexp.
|
93
|
+
#
|
94
|
+
def restricted_area(path)
|
95
|
+
add_path_to_trigger_paths path, :restricted
|
96
|
+
end
|
97
|
+
|
98
|
+
# Ties an unrestricted path to the authorization trigger. Must be
|
99
|
+
# called within an authorization_trigger block:
|
100
|
+
#
|
101
|
+
# authorization_trigger("current_user.signed_in?") do
|
102
|
+
# unrestricted_area %r{/top/secret/path/}
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# +path+ can be either a String or a Regexp. If a String, it will
|
106
|
+
# be converted to a Regexp.
|
107
|
+
#
|
108
|
+
def unrestricted_area(path)
|
109
|
+
add_path_to_trigger_paths path, :unrestricted
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def add_path_to_trigger_paths(path, type)
|
115
|
+
path = Regexp.new(path) if path.is_a? String
|
116
|
+
|
117
|
+
self.authorization_trigger_paths ||= {}
|
118
|
+
(self.authorization_trigger_paths[type] ||= []) << path
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# This module contains methods which will be added as instance methods
|
123
|
+
# to your controller.
|
124
|
+
#
|
125
|
+
module InstanceMethods
|
126
|
+
|
127
|
+
# A +before_filter+ that checks if authorization is needed to access
|
128
|
+
# the current path. If authorization is needed, and it fails, the user
|
129
|
+
# is redirected to the safe_zone, or to root_path if safe_zone is not defined.
|
130
|
+
# It also sets +flash#notice+ with a message, which should be defined
|
131
|
+
# in a locale file with the key +:restricted+.
|
132
|
+
#
|
133
|
+
def area_51_check_access
|
134
|
+
if entering_unauthorized_area?(request.path)
|
135
|
+
flash.notice = I18n.t(:restricted)
|
136
|
+
redirect_to self.class.safe_zone || self.root_path
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Checks to see if the user is entering a restricted zone. It does this
|
141
|
+
# by enumerating through the list of configured authorization triggers
|
142
|
+
# for this controller. If one of them returns +true+, the paths tied
|
143
|
+
# to the trigger are checked against the current path.
|
144
|
+
#
|
145
|
+
# If the current path matches one of the paths configured for the trigger, and the access type
|
146
|
+
# for the trigger is +:restricted+, the method returns +true+. If it is
|
147
|
+
# +:unrestricted+, or the current path is the same as the safe_zone, it returns +false.
|
148
|
+
#
|
149
|
+
def entering_unauthorized_area?(path)
|
150
|
+
return false if path == self.class.safe_zone
|
151
|
+
|
152
|
+
self.class.authorization_triggers.any? do |trigger, paths|
|
153
|
+
if authorization_triggered? trigger
|
154
|
+
|
155
|
+
# Now that we know an authorization should be performed, let's do it!
|
156
|
+
|
157
|
+
if path.match(combined_paths(paths[:restricted]))
|
158
|
+
true
|
159
|
+
elsif path.match(combined_paths(paths[:unrestricted]))
|
160
|
+
false
|
161
|
+
else
|
162
|
+
trigger.default_access == :restricted
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def combined_paths(paths)
|
171
|
+
paths ||= []
|
172
|
+
Regexp.union(*(paths.compact))
|
173
|
+
end
|
174
|
+
|
175
|
+
def authorization_triggered?(trigger)
|
176
|
+
trigger = trigger.body
|
177
|
+
|
178
|
+
case
|
179
|
+
when trigger.is_a?(String)
|
180
|
+
result = eval trigger
|
181
|
+
when trigger.respond_to?(:call)
|
182
|
+
result = trigger.call
|
183
|
+
else
|
184
|
+
result = trigger
|
185
|
+
end
|
186
|
+
|
187
|
+
!!result
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
ActionController::Base.send :extend, Area51::ApiMethod
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Area51
|
2
|
+
class AuthorizationTrigger
|
3
|
+
attr_accessor :default_access
|
4
|
+
attr_accessor :body
|
5
|
+
|
6
|
+
def initialize(body, default_access = nil)
|
7
|
+
@body = body
|
8
|
+
|
9
|
+
if [:restricted, :unrestricted].include?(default_access)
|
10
|
+
@default_access = default_access
|
11
|
+
else
|
12
|
+
@default_access = :restricted
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: area_51
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chad Boyd
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-03-04 00:00:00 -06:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Area51 allows you to define restricted and unrestricted sections of your application by defining paths in your controllers.
|
18
|
+
email:
|
19
|
+
- hoverlover@gmail.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files: []
|
25
|
+
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- Gemfile
|
29
|
+
- README.md
|
30
|
+
- Rakefile
|
31
|
+
- area_51.gemspec
|
32
|
+
- lib/area_51.rb
|
33
|
+
- lib/area_51/authorization_trigger.rb
|
34
|
+
- lib/area_51/version.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: https://github.com/hoverlover
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.5.0
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Gem used for simple path-based access control.
|
63
|
+
test_files: []
|
64
|
+
|