authoreyes 0.2.1 → 0.2.2
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +2 -1
- data/Rakefile +0 -6
- data/authoreyes.gemspec +0 -2
- data/authorization_rules.dist.rb +8 -8
- data/bin/console +3 -3
- data/bin/test +1 -1
- data/lib/authoreyes/authorization/anonymous_user.rb +1 -1
- data/lib/authoreyes/authorization/attribute.rb +36 -37
- data/lib/authoreyes/authorization/attribute_with_permission.rb +25 -24
- data/lib/authoreyes/authorization/authorization_rule.rb +18 -19
- data/lib/authoreyes/authorization/authorization_rule_set.rb +5 -4
- data/lib/authoreyes/authorization/engine.rb +63 -52
- data/lib/authoreyes/helpers.rb +0 -1
- data/lib/authoreyes/helpers/in_controller.rb +20 -14
- data/lib/authoreyes/parser.rb +2 -2
- data/lib/authoreyes/parser/authorization_rules_parser.rb +41 -40
- data/lib/authoreyes/parser/dsl_parser.rb +4 -4
- data/lib/authoreyes/parser/priveleges_reader.rb +2 -2
- data/lib/authoreyes/railtie.rb +3 -3
- data/lib/authoreyes/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7be13cd0becb63d94264c6dfb29cbe2dd27aef29
|
4
|
+
data.tar.gz: d01d1328cf588685dbd013b12a2479988d21eb88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8deb67b53bfe0082cb034b72d02a8319b6903c901eed415f1c9eab5effad1b0e4618ba9e347f1aad0dd1098114cd0921df9977732de1ce73ea4f7977340da16
|
7
|
+
data.tar.gz: ad6eef6945afbf09c4efc5822184d7fff1b5d009ba875beb6988999497ee5bb74a581d46428fc124235f09bab19040b9fbccd6843dd113f30a2a524c44a0f76e
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -14,11 +14,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
14
14
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
17
|
require 'bundler/gem_tasks'
|
23
18
|
|
24
19
|
require 'rake/testtask'
|
@@ -30,5 +25,4 @@ Rake::TestTask.new(:test) do |t|
|
|
30
25
|
t.verbose = false
|
31
26
|
end
|
32
27
|
|
33
|
-
|
34
28
|
task default: :test
|
data/authoreyes.gemspec
CHANGED
@@ -17,7 +17,6 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.homepage = 'https://www.github.com/tektite-software/authoreyes'
|
18
18
|
spec.license = 'MIT'
|
19
19
|
|
20
|
-
|
21
20
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
21
|
spec.bindir = 'exe'
|
23
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -33,5 +32,4 @@ Gem::Specification.new do |spec|
|
|
33
32
|
spec.add_development_dependency 'sqlite3'
|
34
33
|
spec.add_development_dependency 'devise'
|
35
34
|
spec.add_development_dependency 'byebug'
|
36
|
-
|
37
35
|
end
|
data/authorization_rules.dist.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
authorization do
|
2
2
|
role :guest do
|
3
3
|
# add permissions for guests here, e.g.
|
4
|
-
#has_permission_on :conferences, :to => :read
|
4
|
+
# has_permission_on :conferences, :to => :read
|
5
5
|
end
|
6
6
|
|
7
7
|
# permissions on other roles, such as
|
8
|
-
#role :admin do
|
8
|
+
# role :admin do
|
9
9
|
# has_permission_on :conferences, :to => :manage
|
10
|
-
#end
|
10
|
+
# end
|
11
11
|
end
|
12
12
|
|
13
13
|
privileges do
|
14
14
|
# default privilege hierarchies to facilitate RESTful Rails apps
|
15
|
-
privilege :manage, :
|
16
|
-
privilege :read, :
|
17
|
-
privilege :create, :
|
18
|
-
privilege :update, :
|
19
|
-
privilege :delete, :
|
15
|
+
privilege :manage, includes: [:create, :read, :update, :delete]
|
16
|
+
privilege :read, includes: [:index, :show]
|
17
|
+
privilege :create, includes: :new
|
18
|
+
privilege :update, includes: :edit
|
19
|
+
privilege :delete, includes: :destroy
|
20
20
|
end
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'authoreyes'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "authoreyes"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start
|
data/bin/test
CHANGED
@@ -3,7 +3,7 @@ module Authoreyes
|
|
3
3
|
# Represents a pseudo-user to facilitate anonymous users in applications
|
4
4
|
class AnonymousUser
|
5
5
|
attr_reader :role_symbols
|
6
|
-
def initialize
|
6
|
+
def initialize(roles = [Authorization.default_role])
|
7
7
|
@role_symbols = roles
|
8
8
|
end
|
9
9
|
end
|
@@ -4,20 +4,20 @@ module Authoreyes
|
|
4
4
|
# attr_conditions_hash of form
|
5
5
|
# { :object_attribute => [operator, value_block], ... }
|
6
6
|
# { :object_attribute => { :attr => ... } }
|
7
|
-
def initialize
|
7
|
+
def initialize(conditions_hash)
|
8
8
|
@conditions_hash = conditions_hash
|
9
9
|
end
|
10
10
|
|
11
|
-
def initialize_copy
|
11
|
+
def initialize_copy(_from)
|
12
12
|
@conditions_hash = deep_hash_clone(@conditions_hash)
|
13
13
|
end
|
14
14
|
|
15
|
-
def validate?
|
15
|
+
def validate?(attr_validator, object = nil, hash = nil)
|
16
16
|
object ||= attr_validator.object
|
17
17
|
return false unless object
|
18
18
|
|
19
|
-
if
|
20
|
-
|
19
|
+
if Authorization.is_a_association_proxy?(object) &&
|
20
|
+
object.respond_to?(:empty?)
|
21
21
|
return false if object.empty?
|
22
22
|
object.each do |member|
|
23
23
|
return true if validate?(attr_validator, member, hash)
|
@@ -32,12 +32,12 @@ module Authoreyes
|
|
32
32
|
attr_value.any? do |inner_value|
|
33
33
|
validate?(attr_validator, inner_value, value)
|
34
34
|
end
|
35
|
-
elsif attr_value
|
35
|
+
elsif attr_value.nil?
|
36
36
|
raise NilAttributeValueError, "Attribute #{attr.inspect} is nil in #{object.inspect}."
|
37
37
|
else
|
38
38
|
validate?(attr_validator, attr_value, value)
|
39
39
|
end
|
40
|
-
elsif value.is_a?(Array)
|
40
|
+
elsif value.is_a?(Array) && value.length == 2 && value.first.is_a?(Symbol)
|
41
41
|
evaluated = if value[1].is_a?(Proc)
|
42
42
|
attr_validator.evaluate(value[1])
|
43
43
|
else
|
@@ -52,41 +52,41 @@ module Authoreyes
|
|
52
52
|
begin
|
53
53
|
attr_value.include?(evaluated)
|
54
54
|
rescue NoMethodError => e
|
55
|
-
raise AuthorizationUsageError,
|
56
|
-
|
57
|
-
|
55
|
+
raise AuthorizationUsageError, 'Operator contains requires a ' \
|
56
|
+
"subclass of Enumerable as attribute value, got: #{attr_value.inspect} " \
|
57
|
+
"contains #{evaluated.inspect}: #{e}"
|
58
58
|
end
|
59
59
|
when :does_not_contain
|
60
60
|
begin
|
61
61
|
!attr_value.include?(evaluated)
|
62
62
|
rescue NoMethodError => e
|
63
|
-
raise AuthorizationUsageError,
|
64
|
-
|
65
|
-
|
63
|
+
raise AuthorizationUsageError, 'Operator does_not_contain requires a ' \
|
64
|
+
"subclass of Enumerable as attribute value, got: #{attr_value.inspect} " \
|
65
|
+
"does_not_contain #{evaluated.inspect}: #{e}"
|
66
66
|
end
|
67
67
|
when :intersects_with
|
68
68
|
begin
|
69
69
|
!(evaluated.to_set & attr_value.to_set).empty?
|
70
70
|
rescue NoMethodError => e
|
71
|
-
raise AuthorizationUsageError,
|
72
|
-
|
73
|
-
|
71
|
+
raise AuthorizationUsageError, 'Operator intersects_with requires ' \
|
72
|
+
"subclasses of Enumerable, got: #{attr_value.inspect} " \
|
73
|
+
"intersects_with #{evaluated.inspect}: #{e}"
|
74
74
|
end
|
75
75
|
when :is_in
|
76
76
|
begin
|
77
77
|
evaluated.include?(attr_value)
|
78
78
|
rescue NoMethodError => e
|
79
|
-
raise AuthorizationUsageError,
|
80
|
-
|
81
|
-
|
79
|
+
raise AuthorizationUsageError, 'Operator is_in requires a ' \
|
80
|
+
"subclass of Enumerable as value, got: #{attr_value.inspect} " \
|
81
|
+
"is_in #{evaluated.inspect}: #{e}"
|
82
82
|
end
|
83
83
|
when :is_not_in
|
84
84
|
begin
|
85
85
|
!evaluated.include?(attr_value)
|
86
86
|
rescue NoMethodError => e
|
87
|
-
raise AuthorizationUsageError,
|
88
|
-
|
89
|
-
|
87
|
+
raise AuthorizationUsageError, 'Operator is_not_in requires a ' \
|
88
|
+
"subclass of Enumerable as value, got: #{attr_value.inspect} " \
|
89
|
+
"is_not_in #{evaluated.inspect}: #{e}"
|
90
90
|
end
|
91
91
|
when :lt
|
92
92
|
attr_value && attr_value < evaluated
|
@@ -100,32 +100,32 @@ module Authoreyes
|
|
100
100
|
raise AuthorizationError, "Unknown operator #{value[0]}"
|
101
101
|
end
|
102
102
|
else
|
103
|
-
raise AuthorizationError,
|
103
|
+
raise AuthorizationError, 'Wrong conditions hash format'
|
104
104
|
end
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
108
|
# resolves all the values in condition_hash
|
109
|
-
def obligation
|
109
|
+
def obligation(attr_validator, hash = nil)
|
110
110
|
hash = (hash || @conditions_hash).clone
|
111
111
|
hash.each do |attr, value|
|
112
112
|
if value.is_a?(Hash)
|
113
113
|
hash[attr] = obligation(attr_validator, value)
|
114
|
-
elsif value.is_a?(Array)
|
114
|
+
elsif value.is_a?(Array) && value.length == 2
|
115
115
|
hash[attr] = [value[0], attr_validator.evaluate(value[1])]
|
116
116
|
else
|
117
|
-
raise AuthorizationError,
|
117
|
+
raise AuthorizationError, 'Wrong conditions hash format'
|
118
118
|
end
|
119
119
|
end
|
120
120
|
hash
|
121
121
|
end
|
122
122
|
|
123
|
-
def to_long_s
|
123
|
+
def to_long_s(hash = nil)
|
124
124
|
if hash
|
125
125
|
hash.inject({}) do |memo, key_val|
|
126
126
|
key, val = key_val
|
127
127
|
memo[key] = case val
|
128
|
-
when Array then "#{val[0]} { #{val[1].respond_to?(:to_ruby) ? val[1].to_ruby.gsub(/^proc \{\n?(.*)\n?\}$/m, '\1') :
|
128
|
+
when Array then "#{val[0]} { #{val[1].respond_to?(:to_ruby) ? val[1].to_ruby.gsub(/^proc \{\n?(.*)\n?\}$/m, '\1') : '...'} }"
|
129
129
|
when Hash then to_long_s(val)
|
130
130
|
end
|
131
131
|
memo
|
@@ -136,17 +136,16 @@ module Authoreyes
|
|
136
136
|
end
|
137
137
|
|
138
138
|
protected
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
139
|
+
|
140
|
+
def object_attribute_value(object, attr)
|
141
|
+
object.send(attr)
|
142
|
+
rescue ArgumentError, NoMethodError => e
|
143
|
+
raise AuthorizationUsageError, "Error occurred while validating attribute ##{attr} on #{object.inspect}: #{e}.\n" \
|
144
|
+
"Please check your authorization rules and ensure the attribute is correctly spelled and \n" \
|
145
|
+
'corresponds to a method on the model you are authorizing for.'
|
147
146
|
end
|
148
147
|
|
149
|
-
def deep_hash_clone
|
148
|
+
def deep_hash_clone(hash)
|
150
149
|
hash.inject({}) do |memo, (key, val)|
|
151
150
|
memo[key] = case val
|
152
151
|
when Hash
|
@@ -5,17 +5,17 @@ module Authoreyes
|
|
5
5
|
class AttributeWithPermission < Attribute
|
6
6
|
# E.g. privilege :read, attr_or_hash either :attribute or
|
7
7
|
# { :attribute => :deeper_attribute }
|
8
|
-
def initialize
|
8
|
+
def initialize(privilege, attr_or_hash, context = nil)
|
9
9
|
@privilege = privilege
|
10
10
|
@context = context
|
11
11
|
@attr_hash = attr_or_hash
|
12
12
|
end
|
13
13
|
|
14
|
-
def initialize_copy
|
14
|
+
def initialize_copy(_from)
|
15
15
|
@attr_hash = deep_hash_clone(@attr_hash) if @attr_hash.is_a?(Hash)
|
16
16
|
end
|
17
17
|
|
18
|
-
def validate?
|
18
|
+
def validate?(attr_validator, object = nil, hash_or_attr = nil)
|
19
19
|
object ||= attr_validator.object
|
20
20
|
hash_or_attr ||= @attr_hash
|
21
21
|
return false unless object
|
@@ -28,15 +28,15 @@ module Authoreyes
|
|
28
28
|
raise NilAttributeValueError, "Attribute #{hash_or_attr.inspect} is nil in #{object.inspect}."
|
29
29
|
when Enumerable
|
30
30
|
attr_value.any? do |inner_value|
|
31
|
-
attr_validator.engine.permit? @privilege, :
|
31
|
+
attr_validator.engine.permit? @privilege, object: inner_value, user: attr_validator.user
|
32
32
|
end
|
33
33
|
else
|
34
|
-
attr_validator.engine.permit? @privilege, :
|
34
|
+
attr_validator.engine.permit? @privilege, object: attr_value, user: attr_validator.user
|
35
35
|
end
|
36
36
|
when Hash
|
37
37
|
hash_or_attr.all? do |attr, sub_hash|
|
38
38
|
attr_value = object_attribute_value(object, attr)
|
39
|
-
if attr_value
|
39
|
+
if attr_value.nil?
|
40
40
|
raise NilAttributeValueError, "Attribute #{attr.inspect} is nil in #{object.inspect}."
|
41
41
|
elsif attr_value.is_a?(Enumerable)
|
42
42
|
attr_value.any? do |inner_value|
|
@@ -47,14 +47,14 @@ module Authoreyes
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
when NilClass
|
50
|
-
attr_validator.engine.permit? @privilege, :
|
50
|
+
attr_validator.engine.permit? @privilege, object: object, user: attr_validator.user
|
51
51
|
else
|
52
52
|
raise AuthorizationError, "Wrong conditions hash format: #{hash_or_attr.inspect}"
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
# may return an array of obligations to be OR'ed
|
57
|
-
def obligation
|
57
|
+
def obligation(attr_validator, hash_or_attr = nil, path = [])
|
58
58
|
hash_or_attr ||= @attr_hash
|
59
59
|
case hash_or_attr
|
60
60
|
when Symbol
|
@@ -71,23 +71,23 @@ module Authoreyes
|
|
71
71
|
end
|
72
72
|
|
73
73
|
obligations = attr_validator.engine.obligations(@privilege,
|
74
|
-
|
75
|
-
|
74
|
+
context: @context,
|
75
|
+
user: attr_validator.user)
|
76
76
|
|
77
|
-
obligations.collect {|obl| {hash_or_attr => obl} }
|
77
|
+
obligations.collect { |obl| { hash_or_attr => obl } }
|
78
78
|
when Hash
|
79
79
|
obligations_array_attrs = []
|
80
80
|
obligations =
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
all
|
81
|
+
hash_or_attr.inject({}) do |all, pair|
|
82
|
+
attr, sub_hash = pair
|
83
|
+
all[attr] = obligation(attr_validator, sub_hash, path + [attr])
|
84
|
+
if all[attr].length > 1
|
85
|
+
obligations_array_attrs << attr
|
86
|
+
else
|
87
|
+
all[attr] = all[attr].first
|
90
88
|
end
|
89
|
+
all
|
90
|
+
end
|
91
91
|
obligations = [obligations]
|
92
92
|
obligations_array_attrs.each do |attr|
|
93
93
|
next_array_size = obligations.first[attr].length
|
@@ -102,8 +102,8 @@ module Authoreyes
|
|
102
102
|
obligations
|
103
103
|
when NilClass
|
104
104
|
attr_validator.engine.obligations(@privilege,
|
105
|
-
|
106
|
-
|
105
|
+
context: attr_validator.context,
|
106
|
+
user: attr_validator.user)
|
107
107
|
else
|
108
108
|
raise AuthorizationError, "Wrong conditions hash format: #{hash_or_attr.inspect}"
|
109
109
|
end
|
@@ -114,10 +114,11 @@ module Authoreyes
|
|
114
114
|
end
|
115
115
|
|
116
116
|
private
|
117
|
-
|
117
|
+
|
118
|
+
def self.reflection_for_path(parent_model, path)
|
118
119
|
reflection = path.empty? ? parent_model : begin
|
119
120
|
parent = reflection_for_path(parent_model, path[0..-2])
|
120
|
-
if !parent.respond_to?(:proxy_reflection)
|
121
|
+
if !parent.respond_to?(:proxy_reflection) && parent.respond_to?(:klass)
|
121
122
|
parent.klass.reflect_on_association(path.last)
|
122
123
|
else
|
123
124
|
parent.reflect_on_association(path.last)
|
@@ -2,10 +2,10 @@ module Authoreyes
|
|
2
2
|
module Authorization
|
3
3
|
class AuthorizationRule
|
4
4
|
attr_reader :attributes, :contexts, :role, :privileges, :join_operator,
|
5
|
-
|
5
|
+
:source_file, :source_line
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
|
7
|
+
def initialize(role, privileges = [], contexts = nil, join_operator = :or,
|
8
|
+
options = {})
|
9
9
|
@role = role
|
10
10
|
@privileges = Set.new(privileges)
|
11
11
|
@contexts = Set.new((contexts && !contexts.is_a?(Array) ? [contexts] : contexts))
|
@@ -15,28 +15,28 @@ module Authoreyes
|
|
15
15
|
@source_line = options[:source_line]
|
16
16
|
end
|
17
17
|
|
18
|
-
def initialize_copy
|
18
|
+
def initialize_copy(_from)
|
19
19
|
@privileges = @privileges.clone
|
20
20
|
@contexts = @contexts.clone
|
21
|
-
@attributes = @attributes.collect
|
21
|
+
@attributes = @attributes.collect(&:clone)
|
22
22
|
end
|
23
23
|
|
24
|
-
def append_privileges
|
24
|
+
def append_privileges(privs)
|
25
25
|
@privileges.merge(privs)
|
26
26
|
end
|
27
27
|
|
28
|
-
def append_attribute
|
28
|
+
def append_attribute(attribute)
|
29
29
|
@attributes << attribute
|
30
30
|
end
|
31
31
|
|
32
|
-
def matches?
|
32
|
+
def matches?(roles, privs, context = nil)
|
33
33
|
roles = [roles] unless roles.is_a?(Array)
|
34
|
-
@contexts.include?(context)
|
35
|
-
|
34
|
+
@contexts.include?(context) && roles.include?(@role) &&
|
35
|
+
!(@privileges & privs).empty?
|
36
36
|
end
|
37
37
|
|
38
|
-
def validate?
|
39
|
-
skip_attribute
|
38
|
+
def validate?(attr_validator, skip_attribute = false)
|
39
|
+
skip_attribute || @attributes.empty? ||
|
40
40
|
@attributes.send(@join_operator == :and ? :all? : :any?) do |attr|
|
41
41
|
begin
|
42
42
|
attr.validate?(attr_validator)
|
@@ -46,7 +46,7 @@ module Authoreyes
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def obligations
|
49
|
+
def obligations(attr_validator)
|
50
50
|
exceptions = []
|
51
51
|
obligations = @attributes.collect do |attr|
|
52
52
|
begin
|
@@ -57,13 +57,13 @@ module Authoreyes
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
if exceptions.
|
61
|
-
raise NotAuthorized, "Missing authorization in collecting obligations: #{exceptions.map(&:to_s) *
|
60
|
+
if !exceptions.empty? && (@join_operator == :and || exceptions.length == @attributes.length)
|
61
|
+
raise NotAuthorized, "Missing authorization in collecting obligations: #{exceptions.map(&:to_s) * ', '}"
|
62
62
|
end
|
63
63
|
|
64
|
-
if @join_operator == :and
|
64
|
+
if @join_operator == :and && !obligations.empty?
|
65
65
|
# cross product of OR'ed obligations in arrays
|
66
|
-
arrayed_obligations = obligations.map {|obligation| obligation.is_a?(Hash) ? [obligation] : obligation}
|
66
|
+
arrayed_obligations = obligations.map { |obligation| obligation.is_a?(Hash) ? [obligation] : obligation }
|
67
67
|
merged_obligations = arrayed_obligations.first
|
68
68
|
arrayed_obligations[1..-1].each do |inner_obligations|
|
69
69
|
previous_merged_obligations = merged_obligations
|
@@ -81,9 +81,8 @@ module Authoreyes
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def to_long_s
|
84
|
-
attributes.collect
|
84
|
+
attributes.collect(&:to_long_s) * '; '
|
85
85
|
end
|
86
86
|
end
|
87
|
-
|
88
87
|
end
|
89
88
|
end
|
@@ -10,8 +10,8 @@ module Authoreyes
|
|
10
10
|
reset!
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize_copy(
|
14
|
-
@rules = @rules.collect
|
13
|
+
def initialize_copy(_source)
|
14
|
+
@rules = @rules.collect(&:clone)
|
15
15
|
reset!
|
16
16
|
end
|
17
17
|
|
@@ -28,7 +28,7 @@ module Authoreyes
|
|
28
28
|
reset!
|
29
29
|
end
|
30
30
|
|
31
|
-
def <<
|
31
|
+
def <<(rule)
|
32
32
|
@rules << rule
|
33
33
|
reset!
|
34
34
|
end
|
@@ -38,8 +38,9 @@ module Authoreyes
|
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
41
|
+
|
41
42
|
def reset!
|
42
|
-
@cached_auth_rules =nil
|
43
|
+
@cached_auth_rules = nil
|
43
44
|
end
|
44
45
|
|
45
46
|
def cached_auth_rules
|
@@ -18,7 +18,7 @@ module Authoreyes
|
|
18
18
|
options = {
|
19
19
|
reader: nil
|
20
20
|
}.merge(options)
|
21
|
-
|
21
|
+
# @auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules
|
22
22
|
@reader = ::Authoreyes::Parser::DSLParser.factory(options[:reader] || AUTH_DSL_FILES)
|
23
23
|
end
|
24
24
|
|
@@ -75,18 +75,18 @@ module Authoreyes
|
|
75
75
|
# Should NotAuthorized exceptions be raised
|
76
76
|
# Defaults to true.
|
77
77
|
#
|
78
|
-
def permit!
|
78
|
+
def permit!(privilege, options = {})
|
79
79
|
return true if Authorization.ignore_access_control
|
80
80
|
options = {
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
:
|
81
|
+
object: nil,
|
82
|
+
skip_attribute_test: false,
|
83
|
+
context: nil,
|
84
|
+
bang: true
|
85
85
|
}.merge(options)
|
86
86
|
|
87
87
|
# Make sure we're handling all privileges as symbols.
|
88
|
-
privilege = privilege.is_a?(
|
89
|
-
privilege.flatten.collect
|
88
|
+
privilege = privilege.is_a?(Array) ?
|
89
|
+
privilege.flatten.collect(&:to_sym) :
|
90
90
|
privilege.to_sym
|
91
91
|
|
92
92
|
# Convert context to symbol as well
|
@@ -102,18 +102,22 @@ module Authoreyes
|
|
102
102
|
# Example: permit!( :edit, :object => user.posts )
|
103
103
|
#
|
104
104
|
if Authorization.is_a_association_proxy?(options[:object]) && options[:object].respond_to?(:new)
|
105
|
-
options[:object] = (Rails.version <
|
105
|
+
options[:object] = (Rails.version < '3.0' ? options[:object] : options[:object].where(nil)).new
|
106
106
|
end
|
107
107
|
|
108
|
-
|
109
|
-
options[:object]
|
110
|
-
|
111
|
-
|
112
|
-
|
108
|
+
begin
|
109
|
+
options[:context] ||= options[:object] && (
|
110
|
+
options[:object].class.respond_to?(:decl_auth_context) ?
|
111
|
+
options[:object].class.decl_auth_context :
|
112
|
+
options[:object].class.name.tableize.to_sym
|
113
|
+
)
|
114
|
+
rescue
|
115
|
+
NoMethodError
|
116
|
+
end
|
113
117
|
|
114
118
|
user, roles, privileges = user_roles_privleges_from_options(privilege, options)
|
115
119
|
|
116
|
-
return true if roles.is_a?(Array)
|
120
|
+
return true if roles.is_a?(Array) && !(roles & omnipotent_roles).empty?
|
117
121
|
|
118
122
|
# find a authorization rule that matches for at least one of the roles and
|
119
123
|
# at least one of the given privileges
|
@@ -127,9 +131,9 @@ module Authoreyes
|
|
127
131
|
|
128
132
|
if options[:bang]
|
129
133
|
if rules.empty?
|
130
|
-
raise NotAuthorized, "No matching rules found for #{privilege} for #{user.inspect} "
|
131
|
-
|
132
|
-
|
134
|
+
raise NotAuthorized, "No matching rules found for #{privilege} for #{user.inspect} " \
|
135
|
+
"(roles #{roles.inspect}, privileges #{privileges.inspect}, " \
|
136
|
+
"context #{options[:context].inspect})."
|
133
137
|
else
|
134
138
|
raise AttributeAuthorizationError, "#{privilege} not allowed for #{user.inspect} on #{(options[:object] || options[:context]).inspect}."
|
135
139
|
end
|
@@ -140,8 +144,8 @@ module Authoreyes
|
|
140
144
|
|
141
145
|
# Calls permit! but doesn't raise authorization errors. If no exception is
|
142
146
|
# raised, permit? returns true and yields to the optional block.
|
143
|
-
def permit?
|
144
|
-
if permit!(privilege, options.merge(:
|
147
|
+
def permit?(privilege, options = {}) # :yields:
|
148
|
+
if permit!(privilege, options.merge(bang: false))
|
145
149
|
yield if block_given?
|
146
150
|
true
|
147
151
|
else
|
@@ -165,13 +169,13 @@ module Authoreyes
|
|
165
169
|
# [:+context+] See permit!
|
166
170
|
# [:+user+] See permit!
|
167
171
|
#
|
168
|
-
def obligations
|
169
|
-
options = {:
|
172
|
+
def obligations(privilege, options = {})
|
173
|
+
options = { context: nil }.merge(options)
|
170
174
|
user, roles, privileges = user_roles_privleges_from_options(privilege, options)
|
171
175
|
|
172
|
-
permit!(privilege, :
|
176
|
+
permit!(privilege, skip_attribute_test: true, user: user, context: options[:context])
|
173
177
|
|
174
|
-
return [] if roles.is_a?(Array)
|
178
|
+
return [] if roles.is_a?(Array) && !(roles & omnipotent_roles).empty?
|
175
179
|
|
176
180
|
attr_validator = AttributeValidator.new(self, user, nil, privilege, options[:context])
|
177
181
|
matching_auth_rules(roles, privileges, options[:context]).collect do |rule|
|
@@ -182,31 +186,31 @@ module Authoreyes
|
|
182
186
|
# Returns the description for the given role. The description may be
|
183
187
|
# specified with the authorization rules. Returns +nil+ if none was
|
184
188
|
# given.
|
185
|
-
def description_for
|
189
|
+
def description_for(role)
|
186
190
|
role_descriptions[role]
|
187
191
|
end
|
188
192
|
|
189
193
|
# Returns the title for the given role. The title may be
|
190
194
|
# specified with the authorization rules. Returns +nil+ if none was
|
191
195
|
# given.
|
192
|
-
def title_for
|
196
|
+
def title_for(role)
|
193
197
|
role_titles[role]
|
194
198
|
end
|
195
199
|
|
196
200
|
# Returns the role symbols of the given user.
|
197
|
-
def roles_for
|
201
|
+
def roles_for(user)
|
198
202
|
user ||= Authorization.current_user
|
199
203
|
raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.inspect})" \
|
200
|
-
if !user.respond_to?(:role_symbols)
|
204
|
+
if !user.respond_to?(:role_symbols) && !user.respond_to?(:roles)
|
201
205
|
|
202
|
-
Rails.logger.info(
|
203
|
-
|
206
|
+
Rails.logger.info('The use of user.roles is deprecated. Please add a method ' \
|
207
|
+
'role_symbols to your User model.') if defined?(Rails) && Rails.respond_to?(:logger) && !user.respond_to?(:role_symbols)
|
204
208
|
|
205
209
|
roles = user.respond_to?(:role_symbols) ? user.role_symbols : user.roles
|
206
210
|
|
207
|
-
raise AuthorizationUsageError, "User.#{user.respond_to?(:role_symbols) ? 'role_symbols' : 'roles'} "
|
208
|
-
|
209
|
-
if !roles.is_a?(Array)
|
211
|
+
raise AuthorizationUsageError, "User.#{user.respond_to?(:role_symbols) ? 'role_symbols' : 'roles'} " \
|
212
|
+
"doesn't return an Array of Symbols (#{roles.inspect})" \
|
213
|
+
if !roles.is_a?(Array) || (!roles.empty? && !roles[0].is_a?(Symbol))
|
210
214
|
|
211
215
|
(roles.empty? ? [Authorization.default_role] : roles)
|
212
216
|
end
|
@@ -218,7 +222,13 @@ module Authoreyes
|
|
218
222
|
|
219
223
|
def self.development_reload?
|
220
224
|
if Rails.env.development?
|
221
|
-
mod_time = AUTH_DSL_FILES.map
|
225
|
+
mod_time = AUTH_DSL_FILES.map do |m|
|
226
|
+
begin
|
227
|
+
File.mtime(m)
|
228
|
+
rescue
|
229
|
+
Time.at(0)
|
230
|
+
end
|
231
|
+
end.flatten.max
|
222
232
|
@@auth_dsl_last_modified ||= mod_time
|
223
233
|
if mod_time > @@auth_dsl_last_modified
|
224
234
|
@@auth_dsl_last_modified = mod_time
|
@@ -230,8 +240,8 @@ module Authoreyes
|
|
230
240
|
# Returns an instance of Engine, which is created if there isn't one
|
231
241
|
# yet. If +dsl_file+ is given, it is passed on to Engine.new and
|
232
242
|
# a new instance is always created.
|
233
|
-
def self.instance
|
234
|
-
if dsl_file
|
243
|
+
def self.instance(dsl_file = nil)
|
244
|
+
if dsl_file || development_reload?
|
235
245
|
@@instance = new(dsl_file)
|
236
246
|
else
|
237
247
|
@@instance ||= new
|
@@ -240,7 +250,7 @@ module Authoreyes
|
|
240
250
|
|
241
251
|
class AttributeValidator # :nodoc:
|
242
252
|
attr_reader :user, :object, :engine, :context, :privilege
|
243
|
-
def initialize
|
253
|
+
def initialize(engine, user, object = nil, privilege = nil, context = nil)
|
244
254
|
@engine = engine
|
245
255
|
@user = user
|
246
256
|
@object = object
|
@@ -248,33 +258,34 @@ module Authoreyes
|
|
248
258
|
@context = context
|
249
259
|
end
|
250
260
|
|
251
|
-
def evaluate
|
252
|
-
# TODO cache?
|
261
|
+
def evaluate(value_block)
|
262
|
+
# TODO: cache?
|
253
263
|
instance_eval(&value_block)
|
254
264
|
end
|
255
265
|
end
|
256
266
|
|
257
267
|
private
|
268
|
+
|
258
269
|
def user_roles_privleges_from_options(privilege, options)
|
259
270
|
options = {
|
260
|
-
:
|
261
|
-
:
|
262
|
-
:
|
271
|
+
user: nil,
|
272
|
+
context: nil,
|
273
|
+
user_roles: nil
|
263
274
|
}.merge(options)
|
264
275
|
user = options[:user] || Authorization.current_user
|
265
276
|
privileges = privilege.is_a?(Array) ? privilege : [privilege]
|
266
277
|
|
267
|
-
raise AuthorizationUsageError, "No user object given (#{user.inspect}) or "
|
268
|
-
|
278
|
+
raise AuthorizationUsageError, "No user object given (#{user.inspect}) or " \
|
279
|
+
'set through Authorization.current_user' unless user
|
269
280
|
|
270
281
|
roles = options[:user_roles] || flatten_roles(roles_for(user))
|
271
282
|
privileges = flatten_privileges privileges, options[:context]
|
272
283
|
[user, roles, privileges]
|
273
284
|
end
|
274
285
|
|
275
|
-
def flatten_roles
|
276
|
-
# TODO caching?
|
277
|
-
roles.reject {|role| flattened_roles.include?(role)}.each do |role|
|
286
|
+
def flatten_roles(roles, flattened_roles = Set.new)
|
287
|
+
# TODO: caching?
|
288
|
+
roles.reject { |role| flattened_roles.include?(role) }.each do |role|
|
278
289
|
flattened_roles << role
|
279
290
|
flatten_roles(role_hierarchy[role], flattened_roles) if role_hierarchy[role]
|
280
291
|
end
|
@@ -282,10 +293,10 @@ module Authoreyes
|
|
282
293
|
end
|
283
294
|
|
284
295
|
# Returns the privilege hierarchy flattened for given privileges in context.
|
285
|
-
def flatten_privileges
|
286
|
-
# TODO caching?
|
287
|
-
raise AuthorizationUsageError,
|
288
|
-
privileges.reject {|priv| flattened_privileges.include?(priv)}.each do |priv|
|
296
|
+
def flatten_privileges(privileges, context = nil, flattened_privileges = Set.new)
|
297
|
+
# TODO: caching?
|
298
|
+
raise AuthorizationUsageError, 'No context given or inferable from object' unless context
|
299
|
+
privileges.reject { |priv| flattened_privileges.include?(priv) }.each do |priv|
|
289
300
|
flattened_privileges << priv
|
290
301
|
flatten_privileges(rev_priv_hierarchy[[priv, nil]], context, flattened_privileges) if rev_priv_hierarchy[[priv, nil]]
|
291
302
|
flatten_privileges(rev_priv_hierarchy[[priv, context]], context, flattened_privileges) if rev_priv_hierarchy[[priv, context]]
|
@@ -293,7 +304,7 @@ module Authoreyes
|
|
293
304
|
flattened_privileges.to_a
|
294
305
|
end
|
295
306
|
|
296
|
-
def matching_auth_rules
|
307
|
+
def matching_auth_rules(roles, privileges, context)
|
297
308
|
auth_rules.matching(roles, privileges, context)
|
298
309
|
end
|
299
310
|
end
|
data/lib/authoreyes/helpers.rb
CHANGED
@@ -14,7 +14,6 @@ module Authoreyes
|
|
14
14
|
|
15
15
|
# TODO: Implement this!
|
16
16
|
def filter_resource_access(options = {})
|
17
|
-
|
18
17
|
end
|
19
18
|
|
20
19
|
ActionController::Base.send(:define_method, :redirect_if_unauthorized) do
|
@@ -36,16 +35,24 @@ module Authoreyes
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
38
|
+
ActionController::Metal.send(:define_method, :authorization_object) do
|
39
|
+
if params[:id].present?
|
40
|
+
begin
|
41
|
+
controller_name.singularize.capitalize.constantize.find(params[:id])
|
42
|
+
rescue NameError
|
43
|
+
logger.warn '[Authoreyes] Could not interpolate object!'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
39
48
|
ActionController::API.send(:define_method, :render_unauthorized) do
|
40
49
|
begin
|
41
|
-
permitted_to! action_name
|
50
|
+
permitted_to! action_name, authorization_object
|
42
51
|
rescue Authoreyes::Authorization::NotAuthorized => e
|
43
|
-
|
44
|
-
response_object = ActiveModelSerializers::Model.new
|
45
|
-
response_object.attributes.merge!(
|
46
|
-
|
47
|
-
controller: controller_name
|
48
|
-
})
|
52
|
+
logger.warn "[Authoreyes] #{e}"
|
53
|
+
response_object = ActiveModelSerializers::Model.new
|
54
|
+
response_object.attributes.merge!(action: action_name,
|
55
|
+
controller: controller_name)
|
49
56
|
response_object.errors.add :action, e
|
50
57
|
# Assumes ActiveModel::Serializers is used.
|
51
58
|
# If not used, you will have to override `render_unauthorized`
|
@@ -94,22 +101,21 @@ module Authoreyes
|
|
94
101
|
context = object = nil
|
95
102
|
if object_or_sym.nil?
|
96
103
|
context = controller_name.to_sym
|
97
|
-
elsif !Authorization.is_a_association_proxy?(object_or_sym)
|
104
|
+
elsif !Authorization.is_a_association_proxy?(object_or_sym) && object_or_sym.is_a?(Symbol)
|
98
105
|
context = object_or_sym
|
99
106
|
else
|
100
107
|
object = object_or_sym
|
101
108
|
end
|
102
109
|
|
103
|
-
result = {:
|
104
|
-
|
105
|
-
|
106
|
-
|
110
|
+
result = { object: object,
|
111
|
+
context: context,
|
112
|
+
# :skip_attribute_test => object.nil?,
|
113
|
+
bang: bang }.merge(options)
|
107
114
|
result[:user] = current_user unless result.key?(:user)
|
108
115
|
result
|
109
116
|
end
|
110
117
|
|
111
118
|
class_methods do
|
112
|
-
|
113
119
|
end
|
114
120
|
end
|
115
121
|
end
|
data/lib/authoreyes/parser.rb
CHANGED
@@ -9,9 +9,9 @@ module Authoreyes
|
|
9
9
|
# constructs a data model of its contents.
|
10
10
|
module Parser
|
11
11
|
# Signals that the specified file to load was not found.
|
12
|
-
class DSLFileNotFoundError <
|
12
|
+
class DSLFileNotFoundError < RuntimeError; end
|
13
13
|
# Signals errors that occur while reading and parsing an authorization DSL
|
14
|
-
class DSLError <
|
14
|
+
class DSLError < RuntimeError; end
|
15
15
|
# Signals errors in the syntax of an authorization DSL.
|
16
16
|
class DSLSyntaxError < DSLError; end
|
17
17
|
end
|
@@ -34,7 +34,7 @@ module Authoreyes
|
|
34
34
|
#
|
35
35
|
class AuthorizationRulesParser
|
36
36
|
attr_reader :roles, :role_hierarchy, :auth_rules,
|
37
|
-
|
37
|
+
:role_descriptions, :role_titles, :omnipotent_roles # :nodoc:
|
38
38
|
|
39
39
|
def initialize # :nodoc:
|
40
40
|
@current_role = nil
|
@@ -48,7 +48,7 @@ module Authoreyes
|
|
48
48
|
@auth_rules = ::Authoreyes::Authorization::AuthorizationRuleSet.new
|
49
49
|
end
|
50
50
|
|
51
|
-
def initialize_copy
|
51
|
+
def initialize_copy(from) # :nodoc:
|
52
52
|
[
|
53
53
|
:roles,
|
54
54
|
:role_hierarchy,
|
@@ -61,7 +61,7 @@ module Authoreyes
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
def append_role
|
64
|
+
def append_role(role, options = {}) # :nodoc:
|
65
65
|
@roles << role unless @roles.include? role
|
66
66
|
@role_titles[role] = options[:title] if options[:title]
|
67
67
|
@role_descriptions[role] =
|
@@ -74,7 +74,7 @@ module Authoreyes
|
|
74
74
|
# has_permissions_on ...
|
75
75
|
# end
|
76
76
|
#
|
77
|
-
def role
|
77
|
+
def role(role, options = {})
|
78
78
|
append_role role, options
|
79
79
|
@current_role = role
|
80
80
|
yield
|
@@ -92,8 +92,8 @@ module Authoreyes
|
|
92
92
|
# has_permission_on :employees, :to => :read
|
93
93
|
# end
|
94
94
|
#
|
95
|
-
def includes
|
96
|
-
raise DSLError,
|
95
|
+
def includes(*roles)
|
96
|
+
raise DSLError, 'includes only in role blocks' if @current_role.nil?
|
97
97
|
@role_hierarchy[@current_role] ||= []
|
98
98
|
@role_hierarchy[@current_role] += roles.flatten
|
99
99
|
end
|
@@ -127,27 +127,27 @@ module Authoreyes
|
|
127
127
|
# of the has_permission_on block. May be :+and+ or :+or+.
|
128
128
|
# Defaults to :+or+.
|
129
129
|
#
|
130
|
-
def has_permission_on
|
130
|
+
def has_permission_on(*args)
|
131
131
|
options = args.extract_options!
|
132
132
|
context = args.flatten
|
133
133
|
|
134
|
-
raise DSLError,
|
135
|
-
options = {:
|
134
|
+
raise DSLError, 'has_permission_on only allowed in role blocks' if @current_role.nil?
|
135
|
+
options = { to: [], join_by: :or }.merge(options)
|
136
136
|
|
137
137
|
privs = options[:to]
|
138
138
|
privs = [privs] unless privs.is_a?(Array)
|
139
|
-
raise DSLError,
|
139
|
+
raise DSLError, 'has_permission_on either needs a block or :to option' if !block_given? && privs.empty?
|
140
140
|
|
141
141
|
file, line = file_and_line_number_from_call_stack
|
142
142
|
rule = ::Authoreyes::Authorization::AuthorizationRule.new(@current_role, privs, context, options[:join_by],
|
143
|
-
|
143
|
+
source_file: file, source_line: line)
|
144
144
|
@auth_rules << rule
|
145
145
|
if block_given?
|
146
146
|
@current_rule = rule
|
147
147
|
yield
|
148
148
|
raise DSLError, "has_permission_on block
|
149
149
|
content specifies no privileges" if rule.privileges.empty?
|
150
|
-
# TODO ensure?
|
150
|
+
# TODO: ensure?
|
151
151
|
@current_rule = nil
|
152
152
|
end
|
153
153
|
end
|
@@ -157,7 +157,7 @@ module Authoreyes
|
|
157
157
|
# has_omnipotence
|
158
158
|
# end
|
159
159
|
def has_omnipotence
|
160
|
-
raise DSLError,
|
160
|
+
raise DSLError, 'has_omnipotence only allowed in role blocks' if @current_role.nil?
|
161
161
|
@omnipotent_roles << @current_role
|
162
162
|
end
|
163
163
|
|
@@ -166,8 +166,8 @@ module Authoreyes
|
|
166
166
|
# description "To be assigned to administrative personnel"
|
167
167
|
# has_permission_on ...
|
168
168
|
# end
|
169
|
-
def description
|
170
|
-
raise DSLError,
|
169
|
+
def description(text)
|
170
|
+
raise DSLError, 'description only allowed in role blocks' if @current_role.nil?
|
171
171
|
role_descriptions[@current_role] = text
|
172
172
|
end
|
173
173
|
|
@@ -176,8 +176,8 @@ module Authoreyes
|
|
176
176
|
# title "Administrator"
|
177
177
|
# has_permission_on ...
|
178
178
|
# end
|
179
|
-
def title
|
180
|
-
raise DSLError,
|
179
|
+
def title(text)
|
180
|
+
raise DSLError, 'title only allowed in role blocks' if @current_role.nil?
|
181
181
|
role_titles[@current_role] = text
|
182
182
|
end
|
183
183
|
|
@@ -189,8 +189,8 @@ module Authoreyes
|
|
189
189
|
# to :create, :read, :update, :delete
|
190
190
|
# end
|
191
191
|
# end
|
192
|
-
def to
|
193
|
-
raise DSLError,
|
192
|
+
def to(*privs)
|
193
|
+
raise DSLError, 'to only allowed in has_permission_on blocks' if @current_rule.nil?
|
194
194
|
@current_rule.append_privileges(privs.flatten)
|
195
195
|
end
|
196
196
|
|
@@ -248,8 +248,8 @@ module Authoreyes
|
|
248
248
|
# if_attribute :type => "special"
|
249
249
|
# if_attribute :id => [1,2]
|
250
250
|
#
|
251
|
-
def if_attribute
|
252
|
-
raise DSLError,
|
251
|
+
def if_attribute(attr_conditions_hash)
|
252
|
+
raise DSLError, 'if_attribute only in has_permission blocks' if @current_rule.nil?
|
253
253
|
parse_attribute_conditions_hash!(attr_conditions_hash)
|
254
254
|
@current_rule.append_attribute ::Authoreyes::Authorization::Attribute.new(attr_conditions_hash)
|
255
255
|
end
|
@@ -300,37 +300,37 @@ module Authoreyes
|
|
300
300
|
# if_permitted_to :read, :home_branch, :context => :branches
|
301
301
|
# if_permitted_to :read, :branch => :main_company, :context => :companies
|
302
302
|
#
|
303
|
-
def if_permitted_to
|
304
|
-
raise DSLError,
|
303
|
+
def if_permitted_to(privilege, attr_or_hash = nil, options = {})
|
304
|
+
raise DSLError, 'if_permitted_to only in has_permission blocks' if @current_rule.nil?
|
305
305
|
options[:context] ||= attr_or_hash.delete(:context) if attr_or_hash.is_a?(Hash)
|
306
306
|
# only :context option in attr_or_hash:
|
307
|
-
attr_or_hash = nil if attr_or_hash.is_a?(Hash)
|
307
|
+
attr_or_hash = nil if attr_or_hash.is_a?(Hash) && attr_or_hash.empty?
|
308
308
|
@current_rule.append_attribute ::Authoreyes::Authorization::AttributeWithPermission.new(privilege,
|
309
|
-
|
309
|
+
attr_or_hash, options[:context])
|
310
310
|
end
|
311
311
|
|
312
312
|
# In an if_attribute statement, is says that the value has to be
|
313
313
|
# met exactly by the if_attribute attribute. For information on the block
|
314
314
|
# argument, see if_attribute.
|
315
|
-
def is
|
315
|
+
def is(&block)
|
316
316
|
[:is, block]
|
317
317
|
end
|
318
318
|
|
319
319
|
# The negation of is.
|
320
|
-
def is_not
|
320
|
+
def is_not(&block)
|
321
321
|
[:is_not, block]
|
322
322
|
end
|
323
323
|
|
324
324
|
# In an if_attribute statement, contains says that the value has to be
|
325
325
|
# part of the collection specified by the if_attribute attribute.
|
326
326
|
# For information on the block argument, see if_attribute.
|
327
|
-
def contains
|
327
|
+
def contains(&block)
|
328
328
|
[:contains, block]
|
329
329
|
end
|
330
330
|
|
331
331
|
# The negation of contains. Currently, query rewriting is disabled
|
332
332
|
# for does_not_contain.
|
333
|
-
def does_not_contain
|
333
|
+
def does_not_contain(&block)
|
334
334
|
[:does_not_contain, block]
|
335
335
|
end
|
336
336
|
|
@@ -338,51 +338,52 @@ module Authoreyes
|
|
338
338
|
# one of the values has to be part of the collection specified by the
|
339
339
|
# if_attribute attribute. The value block needs to evaluate to an
|
340
340
|
# Enumerable. For information on the block argument, see if_attribute.
|
341
|
-
def intersects_with
|
341
|
+
def intersects_with(&block)
|
342
342
|
[:intersects_with, block]
|
343
343
|
end
|
344
344
|
|
345
345
|
# In an if_attribute statement, is_in says that the value has to
|
346
346
|
# contain the attribute value.
|
347
347
|
# For information on the block argument, see if_attribute.
|
348
|
-
def is_in
|
348
|
+
def is_in(&block)
|
349
349
|
[:is_in, block]
|
350
350
|
end
|
351
351
|
|
352
352
|
# The negation of is_in.
|
353
|
-
def is_not_in
|
353
|
+
def is_not_in(&block)
|
354
354
|
[:is_not_in, block]
|
355
355
|
end
|
356
356
|
|
357
357
|
# Less than
|
358
|
-
def lt
|
358
|
+
def lt(&block)
|
359
359
|
[:lt, block]
|
360
360
|
end
|
361
361
|
|
362
362
|
# Less than or equal to
|
363
|
-
def lte
|
363
|
+
def lte(&block)
|
364
364
|
[:lte, block]
|
365
365
|
end
|
366
366
|
|
367
367
|
# Greater than
|
368
|
-
def gt
|
368
|
+
def gt(&block)
|
369
369
|
[:gt, block]
|
370
370
|
end
|
371
371
|
|
372
372
|
# Greater than or equal to
|
373
|
-
def gte
|
373
|
+
def gte(&block)
|
374
374
|
[:gte, block]
|
375
375
|
end
|
376
376
|
|
377
377
|
private
|
378
|
-
|
378
|
+
|
379
|
+
def parse_attribute_conditions_hash!(hash)
|
379
380
|
merge_hash = {}
|
380
381
|
hash.each do |key, value|
|
381
382
|
if value.is_a?(Hash)
|
382
383
|
parse_attribute_conditions_hash!(value)
|
383
384
|
elsif !value.is_a?(Array)
|
384
385
|
merge_hash[key] = [:is, proc { value }]
|
385
|
-
elsif value.is_a?(Array)
|
386
|
+
elsif value.is_a?(Array) && !value[0].is_a?(Symbol)
|
386
387
|
merge_hash[key] = [:is_in, proc { value }]
|
387
388
|
end
|
388
389
|
end
|
@@ -391,8 +392,8 @@ module Authoreyes
|
|
391
392
|
|
392
393
|
def file_and_line_number_from_call_stack
|
393
394
|
caller_parts = caller(2).first.split(':')
|
394
|
-
[caller_parts[0] ==
|
395
|
-
|
395
|
+
[caller_parts[0] == '(eval)' ? nil : caller_parts[0],
|
396
|
+
caller_parts[1] && caller_parts[1].to_i]
|
396
397
|
end
|
397
398
|
end
|
398
399
|
end
|
@@ -13,7 +13,7 @@ module Authoreyes
|
|
13
13
|
@auth_rules_reader = AuthorizationRulesParser.new
|
14
14
|
end
|
15
15
|
|
16
|
-
def initialize_copy
|
16
|
+
def initialize_copy(from) # :nodoc:
|
17
17
|
@privileges_reader = from.privileges_reader.clone
|
18
18
|
@auth_rules_reader = from.auth_rules_reader.clone
|
19
19
|
end
|
@@ -40,8 +40,8 @@ module Authoreyes
|
|
40
40
|
else
|
41
41
|
DSLMethods.new(self).instance_eval(dsl_data)
|
42
42
|
end
|
43
|
-
|
44
|
-
|
43
|
+
rescue SyntaxError, NoMethodError, NameError => e
|
44
|
+
raise DSLSyntaxError, "Illegal DSL syntax: #{e}"
|
45
45
|
end
|
46
46
|
|
47
47
|
# Load and parse a DSL from the given file name.
|
@@ -59,7 +59,7 @@ module Authoreyes
|
|
59
59
|
|
60
60
|
# Loads and parses DSL files and returns a new reader
|
61
61
|
def self.load(dsl_files)
|
62
|
-
# TODO cache reader in production mode?
|
62
|
+
# TODO: cache reader in production mode?
|
63
63
|
reader = new
|
64
64
|
dsl_files = [dsl_files].flatten
|
65
65
|
dsl_files.each do |file|
|
@@ -3,7 +3,7 @@ module Authoreyes
|
|
3
3
|
# The PrivilegeReader handles the part of the authorization DSL in
|
4
4
|
# a +privileges+ block. Here, privilege hierarchies are defined.
|
5
5
|
class PrivilegesReader
|
6
|
-
# TODO handle privileges with separated context
|
6
|
+
# TODO: handle privileges with separated context
|
7
7
|
attr_reader :privileges, :privilege_hierarchy # :nodoc:
|
8
8
|
|
9
9
|
def initialize # :nodoc:
|
@@ -47,7 +47,7 @@ module Authoreyes
|
|
47
47
|
# be used inside a privilege block.
|
48
48
|
def includes(*privileges)
|
49
49
|
raise DSLError,
|
50
|
-
|
50
|
+
'includes only in privilege block' if @current_privelege.nil?
|
51
51
|
privileges.each do |priv|
|
52
52
|
append_privilege priv
|
53
53
|
@privilege_hierarchy[@current_privelege] ||= []
|
data/lib/authoreyes/railtie.rb
CHANGED
@@ -10,7 +10,7 @@ module Authoreyes
|
|
10
10
|
# +auth_rules_file+ is the path of the authorization rules file.
|
11
11
|
config.authoreyes = ActiveSupport::OrderedOptions.new
|
12
12
|
|
13
|
-
initializer 'authoreyes.setup', before: 'authoreyes.engine' do |
|
13
|
+
initializer 'authoreyes.setup', before: 'authoreyes.engine' do |_app|
|
14
14
|
# Set default Authoreyes options
|
15
15
|
default_options = ActiveSupport::OrderedOptions.new
|
16
16
|
default_options.auth_rules_file =
|
@@ -20,7 +20,7 @@ module Authoreyes
|
|
20
20
|
# Validates options
|
21
21
|
unless [nil, :whitelist, :blacklist].include? config.authoreyes.mode
|
22
22
|
raise InvalidConfigurationOption,
|
23
|
-
|
23
|
+
'Unrecognized mode. Valid options are :whitelist and :blacklist'
|
24
24
|
end
|
25
25
|
|
26
26
|
# Merge user options with defaults
|
@@ -28,7 +28,7 @@ module Authoreyes
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Controller integration
|
31
|
-
initializer 'authoreyes.in_controller' do |
|
31
|
+
initializer 'authoreyes.in_controller' do |_app|
|
32
32
|
ActiveSupport.on_load :action_controller do
|
33
33
|
if Rails.application.config.api_only
|
34
34
|
before_action :render_unauthorized
|
data/lib/authoreyes/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authoreyes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tektite Software
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-01-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|