authoreyes 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|