flexible_accessibility 0.3.2 → 0.3.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/Gemfile.lock +1 -1
- data/README.md +30 -4
- data/flexible_accessibility.gemspec +3 -3
- data/lib/flexible_accessibility/controller_methods.rb +32 -17
- data/lib/flexible_accessibility/exceptions.rb +22 -9
- data/lib/flexible_accessibility/filters.rb +5 -2
- data/lib/flexible_accessibility/permission.rb +3 -3
- data/lib/flexible_accessibility/utils.rb +24 -4
- metadata +2 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -8,17 +8,43 @@ Installation:
|
|
|
8
8
|
|
|
9
9
|
or add to your Gemfile
|
|
10
10
|
|
|
11
|
-
gem 'flexible_accessibility', '0.3.
|
|
11
|
+
gem 'flexible_accessibility', '0.3.3'
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
then do
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
rails g flexible_accessibility:install
|
|
16
16
|
|
|
17
17
|
to install migrations
|
|
18
18
|
|
|
19
|
+
Usage:
|
|
20
|
+
|
|
21
|
+
All routes in application are closed by default
|
|
22
|
+
To add route for check or open it you have to use 'authorize' macro in your controller
|
|
23
|
+
The macro has a couple of options:
|
|
24
|
+
|
|
25
|
+
Add all routes to check:
|
|
26
|
+
|
|
27
|
+
authorize :all
|
|
28
|
+
|
|
29
|
+
Add some routes to check but close all others
|
|
30
|
+
|
|
31
|
+
authorize :only => [:index, :new]
|
|
32
|
+
|
|
33
|
+
Add all routes except :index to check, :index remains closed
|
|
34
|
+
|
|
35
|
+
authorize :except => [:index]
|
|
36
|
+
|
|
37
|
+
Add :index and :new to check, skip (open) create for all
|
|
38
|
+
|
|
39
|
+
authorize :only => [:index, :new], :skip => [:create]
|
|
40
|
+
|
|
41
|
+
Open all routes for all
|
|
42
|
+
|
|
43
|
+
authorize :skip => :all
|
|
44
|
+
|
|
19
45
|
======================
|
|
20
46
|
|
|
21
47
|
## Copyright
|
|
22
|
-
Copyright (c) 2012-
|
|
48
|
+
Copyright (c) 2012-2014 Sergey Avanesov and 7 Pikes, Inc.
|
|
23
49
|
|
|
24
50
|

|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'flexible_accessibility'
|
|
5
|
-
s.version = '0.3.
|
|
5
|
+
s.version = '0.3.3'
|
|
6
6
|
s.authors = ['Sergey Avanesov']
|
|
7
|
-
s.date = '
|
|
7
|
+
s.date = '2014-01-08'
|
|
8
8
|
s.summary = 'Flexible access control system'
|
|
9
9
|
s.description = 'Flexible access control system for your rails application. Based on analysis of controller actions'
|
|
10
10
|
s.email = 'sergey.awanesov@gmail.com'
|
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
s.files = `git ls-files`.split("\n")
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
17
|
|
|
18
|
-
s.rubygems_version =
|
|
18
|
+
s.rubygems_version = '1.8.24'
|
|
19
19
|
s.required_rubygems_version = Gem::Requirement.new('> 1.3.1') if s.respond_to? :required_rubygems_version=
|
|
20
20
|
|
|
21
21
|
s.add_development_dependency 'i18n'
|
|
@@ -4,39 +4,54 @@ module FlexibleAccessibility
|
|
|
4
4
|
|
|
5
5
|
# Compatibility with previous versions
|
|
6
6
|
def skip_authorization_here
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
# Macro for define actions without authorization
|
|
11
|
-
def not_authorize(args={})
|
|
12
|
-
valid_arguments = parse_and_validate_arguments(args)
|
|
13
|
-
self.instance_variable_set(:@_non_verifiable_routes, self.action_methods) if valid_arguments[:all]
|
|
14
|
-
self.instance_variable_set(:@_non_verifiable_routes, valid_arguments[:only]) unless valid_arguments[:only].nil?
|
|
15
|
-
self.instance_variable_set(:@_verifiable_routes, []) if self.instance_variable_get(:@_non_verifiable_routes).nil?
|
|
7
|
+
authorize :skip => :all
|
|
16
8
|
end
|
|
17
9
|
|
|
18
10
|
# Macro for define actions with authorization
|
|
19
11
|
def authorize(args={})
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
self.
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
arguments = parse_arguments(args)
|
|
13
|
+
validate_arguments(arguments)
|
|
14
|
+
available_routes = Utils.new.app_routes[self.to_s.gsub(/Controller/, '')]
|
|
15
|
+
available_routes = available_routes.to_set unless available_routes.nil?
|
|
16
|
+
unless available_routes.nil?
|
|
17
|
+
self.instance_variable_set(:@_verifiable_routes, available_routes) if arguments[:all]
|
|
18
|
+
self.instance_variable_set(:@_verifiable_routes, arguments[:only]) unless arguments[:only].nil?
|
|
19
|
+
self.instance_variable_set(:@_verifiable_routes, available_routes - arguments[:except]) unless arguments[:except].nil?
|
|
20
|
+
unless arguments[:skip].nil?
|
|
21
|
+
non_verifiable_routes = arguments[:skip].first == 'all' ? available_routes : arguments[:skip]
|
|
22
|
+
self.instance_variable_set(:@_non_verifiable_routes, non_verifiable_routes)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
private
|
|
28
28
|
# Parse arguments from macro calls
|
|
29
|
-
def
|
|
29
|
+
def parse_arguments(args={})
|
|
30
30
|
result = {}
|
|
31
|
-
(result[:all] =
|
|
32
|
-
[:only, :except].each do |key|
|
|
31
|
+
(result[:all] = ['all'].to_set) and return result if args.to_s == 'all'
|
|
32
|
+
[:only, :except, :skip].each do |key|
|
|
33
33
|
unless args[key].nil?
|
|
34
|
+
result[key] = [args[key].to_s].to_set and next if args[key].to_s == 'all' && key == :skip
|
|
34
35
|
raise ActionsValueException unless args[key].instance_of?(Array)
|
|
35
36
|
result[key] = args[key].map!{ |v| v.to_s }.to_set
|
|
36
37
|
end
|
|
37
38
|
end
|
|
38
39
|
result
|
|
39
40
|
end
|
|
41
|
+
|
|
42
|
+
def validate_arguments(args={})
|
|
43
|
+
return if args.count == 1 && args.keys.include?(:all)
|
|
44
|
+
only_options = args[:only] || Set.new
|
|
45
|
+
except_options = args[:except] || Set.new
|
|
46
|
+
skip_options = args[:skip] || Set.new
|
|
47
|
+
unless (only_options & except_options).empty? &&
|
|
48
|
+
(only_options & skip_options).empty?
|
|
49
|
+
raise IncorrectArgumentException.new(nil, 'The same arguments shouldn\'t be used with different keys excluding except and skip')
|
|
50
|
+
end
|
|
51
|
+
if args[:skip] == 'all' && args.count > 1
|
|
52
|
+
raise IncorrectArgumentException.new(nil, 'Option \'skip\' with argument \'all\' shouldn\'t be used with another options')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
40
55
|
end
|
|
41
56
|
|
|
42
57
|
# Callback is needed for include methods and define helper method
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module FlexibleAccessibility
|
|
2
2
|
class FlexibleAccessibilityException < StandardError
|
|
3
|
-
attr_reader :action, :subject
|
|
3
|
+
attr_reader :action, :subject
|
|
4
4
|
|
|
5
5
|
def initialize(action = nil, subject = nil)
|
|
6
6
|
@action = action
|
|
@@ -8,71 +8,84 @@ module FlexibleAccessibility
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def to_s
|
|
11
|
-
message || default_message
|
|
11
|
+
message || default_message || @subject
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
private
|
|
15
14
|
def message
|
|
16
|
-
nil
|
|
15
|
+
@subject || nil
|
|
17
16
|
end
|
|
18
17
|
|
|
18
|
+
private
|
|
19
19
|
def default_message
|
|
20
20
|
'An exception is occurred'
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
class AccessDeniedException < FlexibleAccessibilityException
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
def message
|
|
27
27
|
I18n.t('flexible_accessibility.errors.access_denied', :action => @action)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
private
|
|
30
31
|
def default_message
|
|
31
32
|
"The access for resource #{@action} is denied"
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
class UserNotLoggedInException < FlexibleAccessibilityException
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
def message
|
|
38
39
|
I18n.t('flexible_accessibility.errors.user_is_not_logged_in')
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
private
|
|
41
43
|
def default_message
|
|
42
44
|
'Current user is not logged in'
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
class NoWayToDetectLoggerUserException < FlexibleAccessibilityException
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
def message
|
|
49
51
|
I18n.t('flexible_accessibility.errors.no_way_to_detect_logged_user')
|
|
50
52
|
end
|
|
51
53
|
|
|
54
|
+
private
|
|
52
55
|
def default_message
|
|
53
56
|
'No way to detect a logged user - may you have forgot to define a current_user helper'
|
|
54
57
|
end
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
class UnknownUserException < FlexibleAccessibilityException
|
|
58
|
-
|
|
61
|
+
|
|
59
62
|
def message
|
|
60
63
|
I18n.t('flexible_accessibility.errors.unknown_user')
|
|
61
64
|
end
|
|
62
65
|
|
|
66
|
+
private
|
|
63
67
|
def default_message
|
|
64
68
|
'Probably you have forgot to send a user in has_access?'
|
|
65
69
|
end
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
class ActionsValueException < FlexibleAccessibilityException
|
|
69
|
-
|
|
73
|
+
|
|
70
74
|
def message
|
|
71
75
|
I18n.t('flexible_accessibility.errors.incorrect_value_of_actions')
|
|
72
76
|
end
|
|
73
77
|
|
|
78
|
+
private
|
|
74
79
|
def default_message
|
|
75
80
|
'The value of any \'authorize\' macro argument should be declared as Array'
|
|
76
81
|
end
|
|
77
82
|
end
|
|
83
|
+
|
|
84
|
+
class IncorrectArgumentException < FlexibleAccessibilityException
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
def default_message
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
end
|
|
78
91
|
end
|
|
@@ -31,14 +31,17 @@ module FlexibleAccessibility
|
|
|
31
31
|
|
|
32
32
|
# Check access to route and we expected the existing of current_user helper
|
|
33
33
|
def check_permission_to_route
|
|
34
|
+
self.class.instance_variable_set(:@_verifiable_routes, []) if self.class.instance_variable_get(:@_verifiable_routes).nil?
|
|
35
|
+
self.class.instance_variable_set(:@_non_verifiable_routes, []) if self.class.instance_variable_get(:@_non_verifiable_routes).nil?
|
|
36
|
+
|
|
34
37
|
if self.class.instance_variable_get(:@_verifiable_routes).include?(current_action)
|
|
35
38
|
raise UserNotLoggedInException.new(current_route, nil) if logged_user.nil?
|
|
36
|
-
|
|
39
|
+
self.class.instance_variable_set(:@_route_permitted, AccessProvider.is_action_permitted_for_user?(current_route, logged_user))
|
|
37
40
|
elsif self.class.instance_variable_get(:@_non_verifiable_routes).include? current_action
|
|
38
41
|
self.class.instance_variable_set(:@_route_permitted, true)
|
|
39
42
|
else
|
|
40
43
|
self.class.instance_variable_set(:@_route_permitted, false)
|
|
41
|
-
|
|
44
|
+
end
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
def allow_route
|
|
@@ -20,11 +20,11 @@ module FlexibleAccessibility
|
|
|
20
20
|
class << self
|
|
21
21
|
def all
|
|
22
22
|
permissions = []
|
|
23
|
-
Utils.new.
|
|
23
|
+
Utils.new.app_controllers.each do |scope|
|
|
24
24
|
namespace = scope.first.to_s
|
|
25
25
|
scope.last.each do |resource|
|
|
26
|
-
resource = "#{namespace}/#{resource}" unless namespace ==
|
|
27
|
-
permissions << Permission.new(:resource => resource.gsub(/_controller/,
|
|
26
|
+
resource = "#{namespace}/#{resource}" unless namespace == 'default'
|
|
27
|
+
permissions << Permission.new(:resource => resource.gsub(/_controller/, ''), :actions => ApplicationResource.new(resource).klass.instance_variable_get(:@_verifiable_routes))
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
permissions
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
module FlexibleAccessibility
|
|
2
2
|
class Utils
|
|
3
|
+
@@routes ||= {}
|
|
4
|
+
|
|
3
5
|
def initialize
|
|
4
6
|
@path = "#{::Rails.root}/app/controllers/"
|
|
5
7
|
@controllers = {}
|
|
6
8
|
end
|
|
7
9
|
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
+
def app_controllers
|
|
11
|
+
app_controllers_recursive(@path)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def app_routes
|
|
15
|
+
app_routes_as_hash if @@routes.empty?
|
|
16
|
+
@@routes
|
|
10
17
|
end
|
|
11
18
|
|
|
19
|
+
private
|
|
12
20
|
# All controller classes placed in :default scope
|
|
13
|
-
def
|
|
21
|
+
def app_controllers_recursive(path)
|
|
14
22
|
(Dir.new(path).entries - ['..', '.']).each do |entry|
|
|
15
23
|
if File.directory?(path + entry)
|
|
16
|
-
|
|
24
|
+
app_controllers_recursive(path + entry + '/')
|
|
17
25
|
else
|
|
18
26
|
parent_directory = File.dirname(path + entry).split(/\//).last
|
|
19
27
|
container = parent_directory == 'controllers' ? 'default' : parent_directory
|
|
@@ -23,5 +31,17 @@ module FlexibleAccessibility
|
|
|
23
31
|
end
|
|
24
32
|
@controllers
|
|
25
33
|
end
|
|
34
|
+
|
|
35
|
+
# Routes from routes.rb
|
|
36
|
+
def app_routes_as_hash
|
|
37
|
+
Rails.application.routes.routes.each do |route|
|
|
38
|
+
controller = route.defaults[:controller]
|
|
39
|
+
unless controller.nil?
|
|
40
|
+
key = controller.split('/').map { |p| p.camelize }.join('::')
|
|
41
|
+
@@routes[key] ||= []
|
|
42
|
+
@@routes[key] << route.defaults[:action]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
26
46
|
end
|
|
27
47
|
end
|
metadata
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
name: flexible_accessibility
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.3.
|
|
5
|
+
version: 0.3.3
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Sergey Avanesov
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2014-01-08 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
prerelease: false
|