gruf 1.2.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +98 -119
- data/bin/gruf +9 -3
- data/lib/gruf.rb +4 -4
- data/lib/gruf/configuration.rb +11 -20
- data/lib/gruf/controllers/base.rb +82 -0
- data/lib/gruf/controllers/request.rb +96 -0
- data/lib/gruf/controllers/service_binder.rb +86 -0
- data/lib/gruf/error.rb +9 -0
- data/lib/gruf/errors/helpers.rb +40 -0
- data/lib/gruf/{hooks → interceptors}/active_record/connection_reset.rb +4 -10
- data/lib/gruf/interceptors/authentication/basic.rb +80 -0
- data/lib/gruf/interceptors/base.rb +51 -0
- data/lib/gruf/{instrumentation/output_metadata_timer.rb → interceptors/context.rb} +25 -15
- data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +59 -0
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/base.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/logstash.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/plain.rb +21 -19
- data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +191 -0
- data/lib/gruf/interceptors/instrumentation/statsd.rb +80 -0
- data/lib/gruf/interceptors/registry.rb +131 -0
- data/lib/gruf/{authentication/none.rb → interceptors/server_interceptor.rb} +8 -7
- data/lib/gruf/interceptors/timer.rb +79 -0
- data/lib/gruf/response.rb +1 -2
- data/lib/gruf/server.rb +40 -25
- data/lib/gruf/version.rb +1 -1
- metadata +19 -20
- data/lib/gruf/authentication.rb +0 -65
- data/lib/gruf/authentication/base.rb +0 -65
- data/lib/gruf/authentication/basic.rb +0 -74
- data/lib/gruf/authentication/strategies.rb +0 -107
- data/lib/gruf/hooks/base.rb +0 -66
- data/lib/gruf/hooks/registry.rb +0 -110
- data/lib/gruf/instrumentation/base.rb +0 -114
- data/lib/gruf/instrumentation/registry.rb +0 -104
- data/lib/gruf/instrumentation/request_context.rb +0 -82
- data/lib/gruf/instrumentation/request_logging/hook.rb +0 -185
- data/lib/gruf/instrumentation/statsd.rb +0 -80
- data/lib/gruf/service.rb +0 -333
@@ -0,0 +1,131 @@
|
|
1
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
4
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
5
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
6
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
7
|
+
#
|
8
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
9
|
+
# Software.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
12
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
13
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
14
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
15
|
+
#
|
16
|
+
module Gruf
|
17
|
+
module Interceptors
|
18
|
+
##
|
19
|
+
# Handles registration of interceptors
|
20
|
+
#
|
21
|
+
class Registry
|
22
|
+
class InterceptorNotFoundError < StandardError; end
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@registry ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Add an interceptor to the registry
|
30
|
+
#
|
31
|
+
# @param [Gruf::Interceptors::Base] interceptor_class The class of the interceptor to add
|
32
|
+
# @param [Hash] options A hash of options to pass into the interceptor during initialization
|
33
|
+
#
|
34
|
+
def use(interceptor_class, options = {})
|
35
|
+
interceptors_mutex do
|
36
|
+
@registry << {
|
37
|
+
klass: interceptor_class,
|
38
|
+
options: options
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Insert an interceptor before another specified interceptor
|
45
|
+
#
|
46
|
+
# @param [Gruf::Interceptors::Base] before_class The interceptor to insert before
|
47
|
+
# @param [Gruf::Interceptors::Base] interceptor_class The class of the interceptor to add
|
48
|
+
# @param [Hash] options A hash of options to pass into the interceptor during initialization
|
49
|
+
#
|
50
|
+
def insert_before(before_class, interceptor_class, options = {})
|
51
|
+
interceptors_mutex do
|
52
|
+
pos = @registry.find_index { |opts| opts.fetch(:klass, '') == before_class }
|
53
|
+
raise InterceptorNotFoundError if pos.nil?
|
54
|
+
@registry.insert(
|
55
|
+
pos,
|
56
|
+
klass: interceptor_class,
|
57
|
+
options: options
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Insert an interceptor after another specified interceptor
|
64
|
+
#
|
65
|
+
# @param [Gruf::Interceptors::Base] after_class The interceptor to insert after
|
66
|
+
# @param [Gruf::Interceptors::Base] interceptor_class The class of the interceptor to add
|
67
|
+
# @param [Hash] options A hash of options to pass into the interceptor during initialization
|
68
|
+
#
|
69
|
+
def insert_after(after_class, interceptor_class, options = {})
|
70
|
+
interceptors_mutex do
|
71
|
+
pos = @registry.find_index { |opts| opts.fetch(:klass, '') == after_class }
|
72
|
+
raise InterceptorNotFoundError if pos.nil?
|
73
|
+
@registry.insert(
|
74
|
+
(pos + 1),
|
75
|
+
klass: interceptor_class,
|
76
|
+
options: options
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Load and return all interceptors for the given request
|
83
|
+
#
|
84
|
+
# @param [Gruf::Controllers::Request] request
|
85
|
+
# @param [Gruf::Error] error
|
86
|
+
# @return [Array<Gruf::Interceptors::Base>]
|
87
|
+
#
|
88
|
+
def prepare(request, error)
|
89
|
+
is = []
|
90
|
+
interceptors_mutex do
|
91
|
+
@registry.each do |o|
|
92
|
+
is << o[:klass].new(request, error, o[:options])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
is
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Clear the registry
|
100
|
+
#
|
101
|
+
def clear
|
102
|
+
interceptors_mutex do
|
103
|
+
@registry = []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# @return [Integer] The number of interceptors currently loaded
|
109
|
+
#
|
110
|
+
def count
|
111
|
+
interceptors_mutex do
|
112
|
+
@registry ||= []
|
113
|
+
@registry.count
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
##
|
120
|
+
# Handle mutations to the interceptor registry in a thread-safe manner
|
121
|
+
#
|
122
|
+
def interceptors_mutex(&block)
|
123
|
+
@interceptors_mutex ||= begin
|
124
|
+
require 'monitor'
|
125
|
+
Monitor.new
|
126
|
+
end
|
127
|
+
@interceptors_mutex.synchronize(&block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -15,17 +15,18 @@
|
|
15
15
|
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
16
|
#
|
17
17
|
module Gruf
|
18
|
-
module
|
18
|
+
module Interceptors
|
19
19
|
##
|
20
|
-
#
|
20
|
+
# Intercepts server requests
|
21
21
|
#
|
22
|
-
class
|
22
|
+
class ServerInterceptor < Base
|
23
|
+
include Gruf::Errors::Helpers
|
24
|
+
|
23
25
|
##
|
24
|
-
#
|
25
|
-
# @return [TrueClass] Always true for this passthrough strategy.
|
26
|
+
# Call the interceptor
|
26
27
|
#
|
27
|
-
def
|
28
|
-
|
28
|
+
def call
|
29
|
+
raise NotImplementedError
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
+
# Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
+
#
|
17
|
+
module Gruf
|
18
|
+
module Interceptors
|
19
|
+
##
|
20
|
+
# Utility class that can be used by interceptors to time requests
|
21
|
+
#
|
22
|
+
class Timer
|
23
|
+
##
|
24
|
+
# Represents a timed result for an interceptor
|
25
|
+
#
|
26
|
+
class Result
|
27
|
+
attr_reader :message
|
28
|
+
attr_reader :elapsed
|
29
|
+
|
30
|
+
def initialize(message, elapsed, successful)
|
31
|
+
@message = message
|
32
|
+
@elapsed = elapsed.to_f
|
33
|
+
@successful = successful ? true : false
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# @return [Boolean] True if this was a successful request
|
38
|
+
#
|
39
|
+
def successful?
|
40
|
+
@successful
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# @return [String] The name of the message class
|
45
|
+
#
|
46
|
+
def message_class_name
|
47
|
+
@message.class.name
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Return the execution time rounded to a specified precision
|
52
|
+
#
|
53
|
+
# @param [Integer] precision The amount of decimal places to round to
|
54
|
+
# @return [Float] The execution time rounded to the appropriate decimal point
|
55
|
+
#
|
56
|
+
def elapsed_rounded(precision: 2)
|
57
|
+
@elapsed.to_f.round(precision)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Time a given code block and return a Timer::Result object
|
63
|
+
#
|
64
|
+
# @return [Gruf::Interceptors::Timer::Result]
|
65
|
+
#
|
66
|
+
def self.time
|
67
|
+
start_time = Time.now
|
68
|
+
message = yield
|
69
|
+
end_time = Time.now
|
70
|
+
elapsed = (end_time - start_time) * 1000.0
|
71
|
+
Result.new(message, elapsed, true)
|
72
|
+
rescue GRPC::BadStatus => e
|
73
|
+
end_time = Time.now
|
74
|
+
elapsed = (end_time - start_time) * 1000.0
|
75
|
+
Result.new(e, elapsed, false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/gruf/response.rb
CHANGED
@@ -63,8 +63,7 @@ module Gruf
|
|
63
63
|
# @return [Float] The execution time of the response
|
64
64
|
#
|
65
65
|
def internal_execution_time
|
66
|
-
|
67
|
-
trailing_metadata[key].to_f
|
66
|
+
trailing_metadata['timer'].to_f
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
data/lib/gruf/server.rb
CHANGED
@@ -22,21 +22,24 @@ module Gruf
|
|
22
22
|
class Server
|
23
23
|
include Gruf::Loggable
|
24
24
|
|
25
|
-
# @return [Array<Class>] The services this server is handling
|
26
|
-
attr_accessor :services
|
27
25
|
# @return [GRPC::RpcServer] The underlying GRPC server instance
|
28
26
|
attr_reader :server
|
29
27
|
# @return [Integer] The port the server is bound to
|
30
28
|
attr_reader :port
|
29
|
+
# @return [Hash] Hash of options passed into the server
|
30
|
+
attr_reader :options
|
31
31
|
|
32
32
|
##
|
33
33
|
# Initialize the server and load and setup the services
|
34
34
|
#
|
35
|
-
# @param [
|
35
|
+
# @param [Hash] options
|
36
36
|
#
|
37
|
-
def initialize(
|
37
|
+
def initialize(options = {})
|
38
|
+
@options = options || {}
|
39
|
+
@interceptors = options.fetch(:interceptor_registry, Gruf.interceptors)
|
40
|
+
@interceptors = Gruf::Interceptors::Registry.new unless @interceptors.is_a?(Gruf::Interceptors::Registry)
|
41
|
+
@services = []
|
38
42
|
setup!
|
39
|
-
load_services(services)
|
40
43
|
end
|
41
44
|
|
42
45
|
##
|
@@ -44,11 +47,9 @@ module Gruf
|
|
44
47
|
#
|
45
48
|
def server
|
46
49
|
unless @server
|
47
|
-
@server = GRPC::RpcServer.new(
|
48
|
-
@port = @server.add_http2_port(Gruf.server_binding_url, ssl_credentials)
|
49
|
-
services.each
|
50
|
-
@server.handle(s)
|
51
|
-
end
|
50
|
+
@server = GRPC::RpcServer.new(options)
|
51
|
+
@port = @server.add_http2_port(options.fetch(:hostname, Gruf.server_binding_url), ssl_credentials)
|
52
|
+
@services.each { |s| @server.handle(s) }
|
52
53
|
end
|
53
54
|
@server
|
54
55
|
end
|
@@ -64,34 +65,48 @@ module Gruf
|
|
64
65
|
end
|
65
66
|
# :nocov:
|
66
67
|
|
67
|
-
|
68
|
+
##
|
69
|
+
# @param [Class] klass
|
70
|
+
#
|
71
|
+
def add_service(klass)
|
72
|
+
@services << klass unless @services.include?(klass)
|
73
|
+
end
|
68
74
|
|
69
75
|
##
|
70
|
-
#
|
76
|
+
# Add an interceptor to the server
|
71
77
|
#
|
72
|
-
# @param [
|
73
|
-
# @
|
78
|
+
# @param [Gruf::Interceptors::Base]
|
79
|
+
# @param [Hash]
|
74
80
|
#
|
75
|
-
def
|
76
|
-
|
77
|
-
@services = Gruf.services.concat(svcs)
|
78
|
-
@services.uniq!
|
79
|
-
end
|
80
|
-
@services
|
81
|
+
def add_interceptor(klass, opts = {})
|
82
|
+
@interceptors.use(klass, opts)
|
81
83
|
end
|
82
84
|
|
85
|
+
private
|
86
|
+
|
83
87
|
##
|
84
88
|
# Auto-load all gRPC handlers
|
85
89
|
#
|
86
90
|
# :nocov:
|
87
91
|
def setup!
|
88
|
-
|
92
|
+
return unless File.directory?(controllers_path)
|
93
|
+
path = File.realpath(controllers_path)
|
94
|
+
$LOAD_PATH.unshift(path)
|
95
|
+
Dir["#{path}/**/*.rb"].each do |f|
|
96
|
+
next if f.include?('_pb') # exclude if people include proto generated files in app/rpc
|
89
97
|
logger.info "- Loading gRPC service file: #{f}"
|
90
|
-
|
98
|
+
load File.realpath(f)
|
91
99
|
end
|
92
100
|
end
|
93
101
|
# :nocov:
|
94
102
|
|
103
|
+
##
|
104
|
+
# @param [String]
|
105
|
+
#
|
106
|
+
def controllers_path
|
107
|
+
options.fetch(:controllers_path, Gruf.controllers_path)
|
108
|
+
end
|
109
|
+
|
95
110
|
##
|
96
111
|
# Load the SSL/TLS credentials for this server
|
97
112
|
#
|
@@ -99,9 +114,9 @@ module Gruf
|
|
99
114
|
#
|
100
115
|
# :nocov:
|
101
116
|
def ssl_credentials
|
102
|
-
if Gruf.use_ssl
|
103
|
-
private_key = File.read Gruf.ssl_key_file
|
104
|
-
cert_chain = File.read Gruf.ssl_crt_file
|
117
|
+
if options.fetch(:use_ssl, Gruf.use_ssl)
|
118
|
+
private_key = File.read(options.fetch(:ssl_key_file, Gruf.ssl_key_file))
|
119
|
+
cert_chain = File.read(options.fetch(:ssl_crt_file, Gruf.ssl_crt_file))
|
105
120
|
certs = [nil, [{ private_key: private_key, cert_chain: cert_chain }], false]
|
106
121
|
GRPC::Core::ServerCredentials.new(*certs)
|
107
122
|
else
|
data/lib/gruf/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gruf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shaun McCormick
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,35 +108,34 @@ files:
|
|
108
108
|
- bin/gruf
|
109
109
|
- gruf.gemspec
|
110
110
|
- lib/gruf.rb
|
111
|
-
- lib/gruf/authentication.rb
|
112
|
-
- lib/gruf/authentication/base.rb
|
113
|
-
- lib/gruf/authentication/basic.rb
|
114
|
-
- lib/gruf/authentication/none.rb
|
115
|
-
- lib/gruf/authentication/strategies.rb
|
116
111
|
- lib/gruf/client.rb
|
117
112
|
- lib/gruf/configuration.rb
|
113
|
+
- lib/gruf/controllers/base.rb
|
114
|
+
- lib/gruf/controllers/request.rb
|
115
|
+
- lib/gruf/controllers/service_binder.rb
|
118
116
|
- lib/gruf/error.rb
|
119
117
|
- lib/gruf/errors/debug_info.rb
|
120
118
|
- lib/gruf/errors/field.rb
|
121
|
-
- lib/gruf/
|
122
|
-
- lib/gruf/
|
123
|
-
- lib/gruf/
|
124
|
-
- lib/gruf/
|
125
|
-
- lib/gruf/
|
126
|
-
- lib/gruf/instrumentation/
|
127
|
-
- lib/gruf/instrumentation/
|
128
|
-
- lib/gruf/instrumentation/request_logging/formatters/
|
129
|
-
- lib/gruf/instrumentation/request_logging/formatters/
|
130
|
-
- lib/gruf/instrumentation/request_logging/
|
131
|
-
- lib/gruf/instrumentation/
|
132
|
-
- lib/gruf/
|
119
|
+
- lib/gruf/errors/helpers.rb
|
120
|
+
- lib/gruf/interceptors/active_record/connection_reset.rb
|
121
|
+
- lib/gruf/interceptors/authentication/basic.rb
|
122
|
+
- lib/gruf/interceptors/base.rb
|
123
|
+
- lib/gruf/interceptors/context.rb
|
124
|
+
- lib/gruf/interceptors/instrumentation/output_metadata_timer.rb
|
125
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/base.rb
|
126
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/logstash.rb
|
127
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/plain.rb
|
128
|
+
- lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb
|
129
|
+
- lib/gruf/interceptors/instrumentation/statsd.rb
|
130
|
+
- lib/gruf/interceptors/registry.rb
|
131
|
+
- lib/gruf/interceptors/server_interceptor.rb
|
132
|
+
- lib/gruf/interceptors/timer.rb
|
133
133
|
- lib/gruf/loggable.rb
|
134
134
|
- lib/gruf/logging.rb
|
135
135
|
- lib/gruf/response.rb
|
136
136
|
- lib/gruf/serializers/errors/base.rb
|
137
137
|
- lib/gruf/serializers/errors/json.rb
|
138
138
|
- lib/gruf/server.rb
|
139
|
-
- lib/gruf/service.rb
|
140
139
|
- lib/gruf/timer.rb
|
141
140
|
- lib/gruf/version.rb
|
142
141
|
homepage: https://github.com/bigcommerce/gruf
|
data/lib/gruf/authentication.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
require_relative 'authentication/strategies'
|
18
|
-
require_relative 'authentication/base'
|
19
|
-
require_relative 'authentication/basic'
|
20
|
-
require_relative 'authentication/none'
|
21
|
-
|
22
|
-
module Gruf
|
23
|
-
##
|
24
|
-
# Handles authentication for gruf services
|
25
|
-
#
|
26
|
-
module Authentication
|
27
|
-
##
|
28
|
-
# Custom error class for handling unauthorized requests
|
29
|
-
#
|
30
|
-
class UnauthorizedError < StandardError; end
|
31
|
-
|
32
|
-
##
|
33
|
-
# Verify a given gruf request
|
34
|
-
#
|
35
|
-
# @param [GRPC::ActiveCall] call The gRPC active call with marshalled data that is being executed
|
36
|
-
# @param [Symbol] strategy The authentication strategy to use
|
37
|
-
# @return [Boolean]
|
38
|
-
#
|
39
|
-
def self.verify(call)
|
40
|
-
credentials = call && call.respond_to?(:metadata) ? call.metadata[Gruf.authorization_metadata_key] : nil
|
41
|
-
|
42
|
-
if Gruf::Authentication::Strategies.any?
|
43
|
-
verified = false
|
44
|
-
Gruf::Authentication::Strategies.each do |_label, klass|
|
45
|
-
begin
|
46
|
-
# if a strategy passes, we've successfully authenticated and can proceed
|
47
|
-
if klass.verify(call, credentials)
|
48
|
-
verified = true
|
49
|
-
break
|
50
|
-
end
|
51
|
-
rescue => e
|
52
|
-
Gruf.logger.error "#{e.message} - #{e.backtrace[0..4].join("\n")}"
|
53
|
-
# NOOP, we don't want to fail other strategies because of a bad neighbor
|
54
|
-
# or if a strategy throws an exception because of a failed auth
|
55
|
-
# we should just proceed to the next strategy
|
56
|
-
end
|
57
|
-
end
|
58
|
-
verified
|
59
|
-
else
|
60
|
-
# we're not using any strategies, so no auth
|
61
|
-
true
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|