razorrisk-cassini-common 0.26.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +5 -0
- data/README.md +2 -0
- data/Rakefile +102 -0
- data/lib/razor_risk/cassini/applications/microservice.rb +318 -0
- data/lib/razor_risk/cassini/applications/rest_framework/route_verb_dispatcher.rb +120 -0
- data/lib/razor_risk/cassini/applications/rest_framework/verb_handler.rb +117 -0
- data/lib/razor_risk/cassini/applications/route_verb_adaptors/utilities/collection_get_helper.rb +86 -0
- data/lib/razor_risk/cassini/applications/securable_microservice.rb +164 -0
- data/lib/razor_risk/cassini/applications/secured_microservice.rb +63 -0
- data/lib/razor_risk/cassini/applications/unsecured_microservice.rb +77 -0
- data/lib/razor_risk/cassini/authorisation/header_helpers.rb +271 -0
- data/lib/razor_risk/cassini/authorisation/security_model_helpers.rb +93 -0
- data/lib/razor_risk/cassini/authorisation.rb +27 -0
- data/lib/razor_risk/cassini/cli.rb +19 -0
- data/lib/razor_risk/cassini/common/version.rb +44 -0
- data/lib/razor_risk/cassini/common.rb +32 -0
- data/lib/razor_risk/cassini/constants.rb +68 -0
- data/lib/razor_risk/cassini/diagnostics/util_functions.rb +248 -0
- data/lib/razor_risk/cassini/diagnostics/zeroth_include.rb +35 -0
- data/lib/razor_risk/cassini/extensions/libclimate/common_options.rb +267 -0
- data/lib/razor_risk/cassini/extensions/libclimate.rb +26 -0
- data/lib/razor_risk/cassini/header_functions.rb +59 -0
- data/lib/razor_risk/cassini/main.rb +238 -0
- data/lib/razor_risk/cassini/mixin/razor_response_validator.rb +176 -0
- data/lib/razor_risk/cassini/testing/suppress_pantheios_logging.rb +31 -0
- data/lib/razor_risk/cassini/util/conversion_util.rb +176 -0
- data/lib/razor_risk/cassini/util/program_execution_util.rb +379 -0
- data/lib/razor_risk/cassini/util/secrets_util.rb +229 -0
- data/lib/razor_risk/cassini/util/version_util.rb +88 -0
- data/lib/razor_risk/sinatra/helpers/check_auth_helper.rb +209 -0
- data/lib/razor_risk/sinatra/helpers/validate_accept_helper.rb +69 -0
- data/lib/razor_risk/sinatra/helpers/validate_content_type_helper.rb +74 -0
- data/lib/razor_risk/sinatra/helpers/validate_query_parameters_helper.rb +198 -0
- data/test/scratch/cassini/util/convert_XML.rb +54 -0
- data/test/unit/applications/route_verb_adaptors/utilities/tc_collection_get_helper.rb +236 -0
- data/test/unit/applications/tc_verb_handler.rb +130 -0
- data/test/unit/mixin/tc_razor_response_validator.rb +328 -0
- data/test/unit/sinatra/helpers/tc_validate_query_parameters_helper.rb +134 -0
- data/test/unit/tc_authorisation_util.rb +265 -0
- data/test/unit/tc_load_secrets.rb +95 -0
- data/test/unit/util/tc_conversion_util.rb +393 -0
- data/test/unit/util/tc_program_execution_util.rb +462 -0
- metadata +380 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 236c6282305896273a4ec80db78f5455c862c718
|
4
|
+
data.tar.gz: 64be38f9a5b4f4f5ab54d0c0cea21b1166cffe3f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb2d95a8efe4270026d02f125f237dde0c2eef7865d1e94a0dc84927b3f1393b1e0bfe7803f7f56ba528b6f0a521a3997e618c0b622e5c2c99f22cab619e0cfc
|
7
|
+
data.tar.gz: b361155b9cf118c9de9af6694945384a55e40909eb2165cbff17e44366446a184aee2d44bf6f4163a30ee197953d0a3cd423641225e09b747776c68559052adf
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## [0.18.1] (2018-06-20)
|
4
|
+
|
5
|
+
**Implemented enhancements:**
|
6
|
+
|
7
|
+
none
|
8
|
+
|
9
|
+
**Fixed defects:**
|
10
|
+
|
11
|
+
none
|
12
|
+
|
13
|
+
**Dependencies and packaging:**
|
14
|
+
|
15
|
+
- separated into own project/repo/package [WEBAPI-138]
|
16
|
+
|
17
|
+
**Merged pull requests:**
|
18
|
+
|
19
|
+
none
|
20
|
+
|
21
|
+
## END OF CHANGE LOG
|
22
|
+
|
data/LICENSE
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# ######################################################################## #
|
5
|
+
#
|
6
|
+
# Copyright (c) 2019 Razor Risk Technologies Pty Limited. All rights reserved.
|
7
|
+
#
|
8
|
+
# ######################################################################## #
|
9
|
+
|
10
|
+
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
11
|
+
|
12
|
+
|
13
|
+
# ##########################################################
|
14
|
+
# bundler
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'bundler/setup'
|
18
|
+
|
19
|
+
|
20
|
+
# ######################################################################## #
|
21
|
+
# requires
|
22
|
+
|
23
|
+
require 'razor_risk/razor/control/rake_helpers/diagnostic_tasks'
|
24
|
+
require 'razor_risk/razor/control/rake_helpers/gem_tasks'
|
25
|
+
require 'razor_risk/razor/control/rake_helpers/task_helpers'
|
26
|
+
|
27
|
+
require 'rake'
|
28
|
+
require 'rake/clean'
|
29
|
+
|
30
|
+
|
31
|
+
# ##########################################################
|
32
|
+
# includes
|
33
|
+
|
34
|
+
include ::RazorRisk::Razor::Control
|
35
|
+
include ::Pantheios
|
36
|
+
|
37
|
+
|
38
|
+
# ##########################################################
|
39
|
+
# Constants
|
40
|
+
|
41
|
+
Spec = ::Gem::Specification.load(Dir['*.gemspec'].first)
|
42
|
+
LogDir = 'log'
|
43
|
+
LogThresholds = [ :informational, :informational ]
|
44
|
+
|
45
|
+
|
46
|
+
# ##########################################################
|
47
|
+
# clean/clobber
|
48
|
+
|
49
|
+
Dir[
|
50
|
+
'log',
|
51
|
+
'doc',
|
52
|
+
'test/reports',
|
53
|
+
].each { |f| CLEAN << f }
|
54
|
+
Dir[
|
55
|
+
'.bundle',
|
56
|
+
'vendor',
|
57
|
+
'GEM_HOME',
|
58
|
+
'*.gem',
|
59
|
+
'*.zip',
|
60
|
+
].each { |f| CLOBBER << f }
|
61
|
+
|
62
|
+
|
63
|
+
# ##########################################################
|
64
|
+
# Tasks
|
65
|
+
|
66
|
+
desc 'Run tests'
|
67
|
+
task :test => [ :'gem:unit_test' ]
|
68
|
+
|
69
|
+
desc 'Build gem'
|
70
|
+
task :build_gem, [ :path ] => :'gem:build'
|
71
|
+
|
72
|
+
desc 'Builds the Razor EntityConnector Gem'
|
73
|
+
task :build, [ :path ] => [
|
74
|
+
:build_gem,
|
75
|
+
]
|
76
|
+
|
77
|
+
desc 'Push the gem to the gem server.'
|
78
|
+
task :deploy => :'gem:push'
|
79
|
+
|
80
|
+
|
81
|
+
# ##########################################################
|
82
|
+
# Hooks
|
83
|
+
|
84
|
+
task :default do
|
85
|
+
puts 'Run \'bundler exec rake --tasks\' to see available tasks'
|
86
|
+
end
|
87
|
+
|
88
|
+
task :first do
|
89
|
+
::Rake::Task[:'diagnostics:init'].execute(
|
90
|
+
name: Spec.name,
|
91
|
+
version: Spec.version.to_s,
|
92
|
+
directory: LogDir,
|
93
|
+
thresholds: LogThresholds,
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
RakeHelpers::TaskHelpers.add_hooks
|
98
|
+
|
99
|
+
|
100
|
+
# ############################## end of file ############################# #
|
101
|
+
|
102
|
+
|
@@ -0,0 +1,318 @@
|
|
1
|
+
|
2
|
+
#############################################################################
|
3
|
+
# File: lib/razor_risk/cassini/applications/microservice.rb
|
4
|
+
#
|
5
|
+
# Purpose: Define the Microservice base class
|
6
|
+
#
|
7
|
+
# Author: Matthew Wilson
|
8
|
+
#
|
9
|
+
# Copyright (c) 2017, Razor Risk Technologies Pty Ltd
|
10
|
+
# All rights reserved
|
11
|
+
#
|
12
|
+
# ##########################################################################
|
13
|
+
|
14
|
+
|
15
|
+
require 'pantheios'
|
16
|
+
require 'xqsr3/quality/parameter_checking'
|
17
|
+
|
18
|
+
require 'razor_risk/cassini/constants'
|
19
|
+
|
20
|
+
require 'razor_risk/sinatra/helpers/validate_accept_helper'
|
21
|
+
require 'razor_risk/sinatra/helpers/validate_content_type_helper'
|
22
|
+
require 'razor_risk/sinatra/helpers/validate_query_parameters_helper'
|
23
|
+
require 'razor_risk/core/diagnostics/logger'
|
24
|
+
|
25
|
+
require 'sinatra/base'
|
26
|
+
|
27
|
+
require 'socket'
|
28
|
+
|
29
|
+
module RazorRisk
|
30
|
+
module Cassini
|
31
|
+
module Applications
|
32
|
+
|
33
|
+
# Common base-class for all microservices
|
34
|
+
#
|
35
|
+
# === Notable features:
|
36
|
+
# - provide class attribute +full_description+, which assumes the deriving
|
37
|
+
# class has defined the constants +FULL_DESIGNATION+ +SERVICE_TYPE+ and
|
38
|
+
# +SHORT_DESIGNATION+, that obtains a human-readable "full Cassini'
|
39
|
+
# service description
|
40
|
+
# - provides class method +init_base_service+ that is used to initialise the
|
41
|
+
# microservice class. It must be called within a class initialiser of a
|
42
|
+
# derived class
|
43
|
+
# - provides class method +run!+ that ensures class initialisation (by a
|
44
|
+
# derived microservice class) has been performed
|
45
|
+
# - provides global 'before' handler that:
|
46
|
+
# * trace
|
47
|
+
# * log of request details
|
48
|
+
# * before handle that:
|
49
|
+
# + sets 'Content-Type' to 'text/plain'
|
50
|
+
#
|
51
|
+
#
|
52
|
+
class Microservice < ::Sinatra::Base
|
53
|
+
|
54
|
+
include ::Xqsr3::Quality::ParameterChecking
|
55
|
+
include ::RazorRisk::Core::Diagnostics::Logger
|
56
|
+
|
57
|
+
helpers ::RazorRisk::Sinatra::Helpers::ValidateAcceptHelper
|
58
|
+
helpers ::RazorRisk::Sinatra::Helpers::ValidateContentTypeHelper
|
59
|
+
helpers ::RazorRisk::Sinatra::Helpers::ValidateQueryParametersHelper
|
60
|
+
|
61
|
+
private
|
62
|
+
def self.to_nil *a; end
|
63
|
+
def to_nil *a; end
|
64
|
+
|
65
|
+
def self.init_base_service_ \
|
66
|
+
host,
|
67
|
+
port,
|
68
|
+
options
|
69
|
+
|
70
|
+
trace
|
71
|
+
|
72
|
+
# Will raise Errno::EADDRINUSE if port is in use
|
73
|
+
TCPServer.new(host, port).close
|
74
|
+
|
75
|
+
# Default to 'production' rather than 'development' (default from
|
76
|
+
# Sinatra. 'APP_ENV' is a Sinatra environment variable that needs to
|
77
|
+
# be checked first (note this isn't introduced to Sinatra until 2.0).
|
78
|
+
if ENV['APP_ENV']
|
79
|
+
set :environment, ENV['APP_ENV']
|
80
|
+
elsif $DEBUG or Constants::RZ_EXPOSE_MICROSERVICE_EXCEPTIONS
|
81
|
+
set :environment, 'development'
|
82
|
+
else
|
83
|
+
set :environment, 'production'
|
84
|
+
end
|
85
|
+
|
86
|
+
# Call error handlers even in testing.
|
87
|
+
configure :test do
|
88
|
+
set :show_exceptions, :after_handler
|
89
|
+
end
|
90
|
+
|
91
|
+
# Call error handlers even in development.
|
92
|
+
configure :development do
|
93
|
+
set :show_exceptions, :after_handler
|
94
|
+
end
|
95
|
+
|
96
|
+
configure :production do
|
97
|
+
|
98
|
+
# Don't print the stack trace to the console.
|
99
|
+
disable :dump_errors
|
100
|
+
|
101
|
+
# Error handler for all uncaught exceptions when in production.
|
102
|
+
error Exception do
|
103
|
+
x = env['sinatra.error']
|
104
|
+
log :violation, "unexpected exception (#{x.class}): '#{x}'"
|
105
|
+
error 500, "Oops! Something went wrong!"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
set :bind, host unless host.nil?
|
110
|
+
set :port, port
|
111
|
+
set :server, options[:web_server] if options[:web_server]
|
112
|
+
|
113
|
+
if options[:tls_certificate_file]
|
114
|
+
|
115
|
+
cts = {
|
116
|
+
|
117
|
+
certificate_file: options[:tls_certificate_file],
|
118
|
+
public_key_file: options[:tls_public_key_file],
|
119
|
+
}
|
120
|
+
|
121
|
+
set :cassini_tls_settings, cts
|
122
|
+
end
|
123
|
+
|
124
|
+
set :microservice_base_is_initialised, Time.now
|
125
|
+
|
126
|
+
if self.respond_to? :on_init_service
|
127
|
+
|
128
|
+
self.on_init_service options
|
129
|
+
end
|
130
|
+
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
public
|
135
|
+
|
136
|
+
# Provides a full description of an including type, which must have the
|
137
|
+
# constants +FULL_DESIGNATION+, +SERVICE_TYPE+, and +SHORT_DESIGNATION+.
|
138
|
+
def self.full_description
|
139
|
+
|
140
|
+
"#{self::FULL_DESIGNATION} #{self::SERVICE_TYPE.to_s.capitalize} (#{self::SHORT_DESIGNATION})"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Defines catch-all handlers for all available verbs
|
144
|
+
#
|
145
|
+
# Unless given a block, it will create catch-all handlers with a basic
|
146
|
+
# message and obtaining a 404. If a block given, it will be invoked with
|
147
|
+
# two parameters - the method name symbol and an options hash within
|
148
|
+
# which are the options +:env+, +:params+, +:request+, and +:response+ -
|
149
|
+
# and should return an array consisting of the HTTP status code and the
|
150
|
+
# body message.
|
151
|
+
#
|
152
|
+
# NOTE: Must be the last component defining the application!
|
153
|
+
def self.define_catch_all_handlers
|
154
|
+
|
155
|
+
methods = %i(delete get head link options patch post put unlink)
|
156
|
+
|
157
|
+
if block_given?
|
158
|
+
|
159
|
+
methods.each do |method|
|
160
|
+
|
161
|
+
send method, // do
|
162
|
+
|
163
|
+
yield method, env: env, params: params, request: request, response: response
|
164
|
+
end
|
165
|
+
end
|
166
|
+
else
|
167
|
+
|
168
|
+
methods.each do |method|
|
169
|
+
|
170
|
+
send method, // do
|
171
|
+
|
172
|
+
[ 404, "'#{env['PATH_INFO']}' [#{method.to_s.upcase}] not found" ]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# This must be invoked prior to activation of the application
|
179
|
+
#
|
180
|
+
# === Signature
|
181
|
+
#
|
182
|
+
# * *Parameters:*
|
183
|
+
# - +host+:: [String] The host to which the application binds. May be:
|
184
|
+
# +nil+, in which case no binding is performed and the Sinatra
|
185
|
+
# defaults are observed; +'0.0.0.0', in which case the server will
|
186
|
+
# listen on all available interfaces; a specific IP addres, in which
|
187
|
+
# case the server will listen only on that address. It is recommend
|
188
|
+
# that a specific address is used. Required
|
189
|
+
# - +port+:: [Integer] The port on which to activate. Required
|
190
|
+
def self.init_base_service \
|
191
|
+
host: to_nil(host_not_given_ = true),
|
192
|
+
port: to_nil(port_not_given_ = true),
|
193
|
+
**options
|
194
|
+
|
195
|
+
trace ParamNames[ :host, :port, :options ], host, port, options
|
196
|
+
|
197
|
+
raise ArgumentError, 'missing keyword: host' if host_not_given_
|
198
|
+
|
199
|
+
raise ArgumentError, 'missing keyword: port' if port_not_given_
|
200
|
+
check_parameter port, 'port', type: Integer
|
201
|
+
|
202
|
+
init_base_service_ host, port, options
|
203
|
+
end
|
204
|
+
|
205
|
+
# Refinement of +::Sinatra::Base.run!+ that ensures that the
|
206
|
+
# microservice class has been initialised
|
207
|
+
def self.run!(options = {}, &block)
|
208
|
+
|
209
|
+
trace
|
210
|
+
|
211
|
+
# TODO: Change this to use proper exception
|
212
|
+
unless settings.respond_to?(:microservice_is_initialised) &&
|
213
|
+
settings.respond_to?(:microservice_base_is_initialised)
|
214
|
+
|
215
|
+
raise ArgumentError, "#{self} microservice application class is not initialised. Must first call #{self}.init_service()"
|
216
|
+
end
|
217
|
+
|
218
|
+
# Configures settings in backend service (e.g. thin, webrick)
|
219
|
+
begin
|
220
|
+
|
221
|
+
super do |server|
|
222
|
+
|
223
|
+
# Set the timeout for the backend service. This prevents thin
|
224
|
+
# from closing connections
|
225
|
+
server.timeout = nil if server.respond_to? :timeout
|
226
|
+
|
227
|
+
# This configures ssl in the backend service, which must be
|
228
|
+
# thin.
|
229
|
+
if settings.respond_to? :cassini_tls_settings
|
230
|
+
|
231
|
+
cts = settings.cassini_tls_settings
|
232
|
+
ssl_opts = {
|
233
|
+
|
234
|
+
cert_chain_file: cts[:tls_certificate_file],
|
235
|
+
private_key_file: cts[:tls_private_key_file],
|
236
|
+
verify_peer: false,
|
237
|
+
}
|
238
|
+
server.ssl = true
|
239
|
+
server.ssl_options = ssl_opts
|
240
|
+
end
|
241
|
+
end
|
242
|
+
rescue ::ArgumentError, ::NameError, ::NoMethodError, ::TypeError => x
|
243
|
+
|
244
|
+
log :violation, "unexpected exception (#{x.class}): '#{x.message}': #{x.backtrace}"
|
245
|
+
raise
|
246
|
+
rescue => x
|
247
|
+
|
248
|
+
log :alert, "exception (#{x.class}): '#{x.message}': #{x.backtrace}"
|
249
|
+
raise
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
before do
|
254
|
+
|
255
|
+
trace
|
256
|
+
|
257
|
+
# benchmarking (if enabled)
|
258
|
+
|
259
|
+
@before_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ = Time.now if severity_logged? :benchmark
|
260
|
+
|
261
|
+
# log the request information
|
262
|
+
|
263
|
+
log :informational, 'handling ', request.path_info, ' [', request.request_method, ']'
|
264
|
+
|
265
|
+
if severity_logged? :debug2
|
266
|
+
|
267
|
+
prefix = ?\t
|
268
|
+
|
269
|
+
e = env.map { |k, v| "#{prefix}'#{k}' : '#{v}'" }.sort.join("\n")
|
270
|
+
|
271
|
+
log :debug2, "ENV for #{request.path_info} [#{request.request_method}] :\n#{e}"
|
272
|
+
end
|
273
|
+
|
274
|
+
if severity_logged? :debug3
|
275
|
+
|
276
|
+
request.body.rewind
|
277
|
+
|
278
|
+
b = request.body.read.strip
|
279
|
+
|
280
|
+
request.body.rewind
|
281
|
+
|
282
|
+
log :debug3, "body for #{request.path_info} [#{request.request_method}] :", b.empty? ? 'no body' : ?\n + b
|
283
|
+
end
|
284
|
+
|
285
|
+
# general (shared) logical actions
|
286
|
+
|
287
|
+
# by default, all handlers return 'text/plain'
|
288
|
+
content_type 'text/plain'
|
289
|
+
end
|
290
|
+
|
291
|
+
after do
|
292
|
+
|
293
|
+
trace
|
294
|
+
|
295
|
+
log :informational, 'handled ', request.path_info, ' [', request.request_method, ']'
|
296
|
+
|
297
|
+
# benchmarking (if enabled)
|
298
|
+
|
299
|
+
if @before_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ && severity_logged?(:benchmark)
|
300
|
+
|
301
|
+
after_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ = Time.now
|
302
|
+
|
303
|
+
delta_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ = after_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ - @before_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_
|
304
|
+
delta_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_ *= 1000
|
305
|
+
|
306
|
+
log :benchmark, "execution of HTTP(S) request - '#{request.path_info}' - (in #{self.class}): dt=#{delta_time_01dd7eef998dwfh_23hfsdfh_777_ashdf732bf_}ms"
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
end # class Microservice
|
311
|
+
|
312
|
+
end # module Applications
|
313
|
+
end # module Cassini
|
314
|
+
end # module RazorRisk
|
315
|
+
|
316
|
+
# ############################## end of file ############################# #
|
317
|
+
|
318
|
+
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# ######################################################################## #
|
4
|
+
# File: razor_risk/cassini/applications/rest_framework/route_verb_dispatcher.rb
|
5
|
+
#
|
6
|
+
# Purpose: Adaptor for Portfolios microservice's collection GET verb
|
7
|
+
#
|
8
|
+
# Author: Matthew Wilson
|
9
|
+
#
|
10
|
+
# Copyright (c) 2018, Razor Risk Technologies Pty Ltd
|
11
|
+
# All rights reserved.
|
12
|
+
#
|
13
|
+
# ######################################################################## #
|
14
|
+
|
15
|
+
|
16
|
+
# ##########################################################################
|
17
|
+
# requires
|
18
|
+
|
19
|
+
require 'razor_risk/razor/connectivity/razor_3/razor_requester'
|
20
|
+
|
21
|
+
require 'razor_risk/cassini/constants'
|
22
|
+
|
23
|
+
require 'pantheios'
|
24
|
+
require 'xqsr3/quality/parameter_checking'
|
25
|
+
|
26
|
+
module RazorRisk
|
27
|
+
module Cassini
|
28
|
+
module Applications
|
29
|
+
module RESTFramework
|
30
|
+
|
31
|
+
# ##########################################################################
|
32
|
+
# modules
|
33
|
+
|
34
|
+
module RouteVerbDispatch
|
35
|
+
|
36
|
+
include ::Pantheios
|
37
|
+
include ::Xqsr3::Quality::ParameterChecking
|
38
|
+
|
39
|
+
def dispatch supplier, *args, **options
|
40
|
+
|
41
|
+
trace ParamNames[ :supplier, :args, :options ], supplier, args, options
|
42
|
+
|
43
|
+
if ::Class === supplier
|
44
|
+
|
45
|
+
supplier_class = supplier
|
46
|
+
supplier = supplier_class.new(self, self.class, *args, **options)
|
47
|
+
else
|
48
|
+
|
49
|
+
supplier_class = supplier.class
|
50
|
+
end
|
51
|
+
|
52
|
+
if $PARAMETER_CHECKING
|
53
|
+
|
54
|
+
check_parameter supplier, 'supplier', responds_to: :handle
|
55
|
+
end
|
56
|
+
|
57
|
+
verb = (options[:verb] || request.request_method).to_s.downcase.to_sym
|
58
|
+
|
59
|
+
# validate 'Accept'
|
60
|
+
|
61
|
+
validate_accept(request, supplier_class::HTTP_ACCEPTS) if supplier_class.const_defined?(:HTTP_ACCEPTS)
|
62
|
+
|
63
|
+
# validate 'Content-Type'
|
64
|
+
|
65
|
+
validate_content_type(request, supplier_class::HTTP_CONTENT_TYPES) if supplier_class.const_defined?(:HTTP_CONTENT_TYPES)
|
66
|
+
|
67
|
+
# validate query parameters
|
68
|
+
|
69
|
+
validated_params = validate_query_parameters(params, supplier_class.const_defined?(:QUERY_PARAMETERS) ? supplier_class::QUERY_PARAMETERS : nil, supplier_class.const_defined?(:ROUTE_VARIABLES) ? supplier_class::ROUTE_VARIABLES : nil)
|
70
|
+
|
71
|
+
# handle base-64 for all params
|
72
|
+
|
73
|
+
validated_params = validated_params.merge(validated_params) do |k, o, n|
|
74
|
+
|
75
|
+
case n
|
76
|
+
when ::String
|
77
|
+
|
78
|
+
s = n.strip
|
79
|
+
|
80
|
+
if /^===(.+)===$/ =~ s
|
81
|
+
|
82
|
+
e = $1
|
83
|
+
|
84
|
+
begin
|
85
|
+
|
86
|
+
Base64.strict_decode64(e).chomp
|
87
|
+
rescue ::ArgumentError => x
|
88
|
+
|
89
|
+
halt(*[ 422, {}, "value for query parameter '#{k}' is malformed Base-64: a valid Base-64 string must be prefixed and suffixed by '==='" ])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
|
93
|
+
n
|
94
|
+
end
|
95
|
+
else
|
96
|
+
|
97
|
+
n
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# execute handler
|
102
|
+
resp = supplier.handle(env, validated_params, request, response)
|
103
|
+
|
104
|
+
# TODO: post-process result, in terms of converting to 'Accept' type
|
105
|
+
# and calling halt / status appropriately
|
106
|
+
|
107
|
+
resp
|
108
|
+
end
|
109
|
+
|
110
|
+
end # module RouteVerbDispatch
|
111
|
+
|
112
|
+
|
113
|
+
end # module RESTFramework
|
114
|
+
end # module Applications
|
115
|
+
end # module Cassini
|
116
|
+
end # module RazorRisk
|
117
|
+
|
118
|
+
# ############################## end of file ############################# #
|
119
|
+
|
120
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# ######################################################################## #
|
4
|
+
# File: razor_risk/cassini/applications/rest_framework/verb_handler.rb
|
5
|
+
#
|
6
|
+
# Purpose: Root (abstract) verb-handler class
|
7
|
+
#
|
8
|
+
# Author: Matthew Wilson
|
9
|
+
#
|
10
|
+
# Copyright (c) 2018, Razor Risk Technologies Pty Ltd
|
11
|
+
# All rights reserved.
|
12
|
+
#
|
13
|
+
# ######################################################################## #
|
14
|
+
|
15
|
+
|
16
|
+
# ##########################################################################
|
17
|
+
# requires
|
18
|
+
|
19
|
+
require 'razor_risk/cassini/authorisation/security_model_helpers'
|
20
|
+
|
21
|
+
require 'razor_risk/extensions/rack/utils/http_status_names'
|
22
|
+
|
23
|
+
require 'pantheios'
|
24
|
+
require 'xqsr3/quality/parameter_checking'
|
25
|
+
|
26
|
+
module RazorRisk
|
27
|
+
module Cassini
|
28
|
+
module Applications
|
29
|
+
module RESTFramework
|
30
|
+
|
31
|
+
# ##########################################################################
|
32
|
+
# classes
|
33
|
+
|
34
|
+
class VerbHandler
|
35
|
+
|
36
|
+
|
37
|
+
# ##########################################################
|
38
|
+
# includes
|
39
|
+
|
40
|
+
include ::RazorRisk::Cassini::Authorisation::SecurityModelHelpers
|
41
|
+
|
42
|
+
include ::Pantheios
|
43
|
+
include ::Xqsr3::Quality::ParameterChecking
|
44
|
+
|
45
|
+
|
46
|
+
# ##########################################################
|
47
|
+
# constants
|
48
|
+
|
49
|
+
HTTP_STATUS_NAMES = ::Rack::Utils::HTTP_STATUS_NAMES
|
50
|
+
|
51
|
+
|
52
|
+
# ##########################################################
|
53
|
+
# methods
|
54
|
+
|
55
|
+
def initialize app, settings = nil, **options
|
56
|
+
|
57
|
+
check_parameter app, 'app'
|
58
|
+
|
59
|
+
settings ||= app.class
|
60
|
+
|
61
|
+
@app = app
|
62
|
+
@settings = settings
|
63
|
+
@options = options
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :app
|
67
|
+
attr_reader :settings
|
68
|
+
|
69
|
+
def content_type *args
|
70
|
+
|
71
|
+
@app.content_type(*args)
|
72
|
+
end
|
73
|
+
|
74
|
+
def halt *args
|
75
|
+
|
76
|
+
@app.halt(*args)
|
77
|
+
end
|
78
|
+
|
79
|
+
def error *args
|
80
|
+
|
81
|
+
@app.error(*args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def status *args
|
85
|
+
|
86
|
+
@app.status(*args)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Obtains a credentials-hash, which will be empty if no authentication
|
90
|
+
# is being used, or will contain +:username+ and, optionally,
|
91
|
+
# +:password+ and/or +:domain+, depending on the authentication scheme
|
92
|
+
# being used
|
93
|
+
def get_required_credentials
|
94
|
+
|
95
|
+
if settings.respond_to?(:authentication_scheme)
|
96
|
+
|
97
|
+
razor_requester_credentials_options(
|
98
|
+
settings.authentication_scheme,
|
99
|
+
app.credentials,
|
100
|
+
auth_test_mode: settings.auth_test_mode
|
101
|
+
)
|
102
|
+
else
|
103
|
+
|
104
|
+
Hash.new
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end # class VerbHandler
|
108
|
+
|
109
|
+
|
110
|
+
end # module RESTFramework
|
111
|
+
end # module Applications
|
112
|
+
end # module Cassini
|
113
|
+
end # module RazorRisk
|
114
|
+
|
115
|
+
# ############################## end of file ############################# #
|
116
|
+
|
117
|
+
|