roo_on_rails 1.14.0 → 1.15.0
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 +5 -5
- data/CHANGELOG.md +14 -1
- data/CONTRIBUTING.md +11 -0
- data/README.md +26 -0
- data/lib/roo_on_rails/logger.rb +16 -2
- data/lib/roo_on_rails/rack/populate_env_from_jwt.rb +101 -0
- data/lib/roo_on_rails/rack/valid_identity_service_prefixes.yml +6 -0
- data/lib/roo_on_rails/railties/roo_identity.rb +24 -0
- data/lib/roo_on_rails/version.rb +1 -1
- data/roo_on_rails.gemspec +4 -0
- metadata +35 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 350514c8b5824a6829103a912a01e155aa18074f
|
4
|
+
data.tar.gz: 827cb9bec23c0d69bab1e2df74024e63861853ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5954c887ece5accaeaf6b9acb328ef24978f6d5673ae2ba2ae2cb8d29f0bcc83f1b55346fb500371cba87ad3e8ebeeba2f44d6b0503c96ae7c696a594e03e768
|
7
|
+
data.tar.gz: 38aaf68d5cf8271b15597ba0145088f272ceb52cdbeb03602b38fb215dbf4b2220cb6d95008676bfad9062c2a4e831994b6bc1837d450fdc9366819943a701fe
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
# HEAD
|
2
2
|
|
3
|
-
_A description of
|
3
|
+
_A description of your awesome new stuff here!_
|
4
|
+
|
5
|
+
# v1.15.0
|
6
|
+
|
7
|
+
Features:
|
8
|
+
|
9
|
+
- Process JWTs in `Authorization` headers and populate the request env's `roo.identity` key with the claims, if present and valid. (#79)
|
10
|
+
- RooOnRails::Logger is now compatible with ActiveSupport::Logger on Rails versions >= 4.2 (#77)
|
11
|
+
|
12
|
+
# v1.14.0
|
13
|
+
|
14
|
+
Bug Fix:
|
15
|
+
|
16
|
+
- Routemaster Publisher was sending epoch seconds instead of milliseconds (#78)
|
4
17
|
|
5
18
|
# v1.13.1 (2017-10-18)
|
6
19
|
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
PRs are welcome to this repo to add new features that will be useful across our Ruby services.
|
4
|
+
|
5
|
+
If you're putting a PR together, please ensure that:
|
6
|
+
|
7
|
+
- There are ample **tests** for your code (they'll be executed against all our supported versions automatically)
|
8
|
+
- You've made changes to the **`README.md`** file explaining how to make use of the work you're adding
|
9
|
+
- You've added a line to the **`CHANGELOG.md`** file, with a short explanation of what you've added (feel free to add this in a commit after you've created your PR so you can add the PR number)
|
10
|
+
|
11
|
+
Thanks!
|
data/README.md
CHANGED
@@ -23,6 +23,7 @@
|
|
23
23
|
- [Sidekiq](#sidekiq)
|
24
24
|
- [HireFire](#hirefire)
|
25
25
|
- [Logging](#logging)
|
26
|
+
- [Identity](#identity)
|
26
27
|
- [Google OAuth authentication](#google-oauth-authentication)
|
27
28
|
- [Datadog Integration](#datadog-integration)
|
28
29
|
- [Routemaster Client](#routemaster-client)
|
@@ -216,6 +217,31 @@ logger.with(a: 1, b: 2).info('Stuff')
|
|
216
217
|
See the [class documentation](lib/roo_on_rails/logger.rb) for further
|
217
218
|
details.
|
218
219
|
|
220
|
+
### Identity
|
221
|
+
|
222
|
+
If your service wants to accept JWTs for identity claims, then adding the `json-jwt` gem
|
223
|
+
to your `Gemfile` and the following railtie to your app will ensure any data presented is
|
224
|
+
available:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
require 'roo_on_rails/railties/roo_identity'
|
228
|
+
```
|
229
|
+
|
230
|
+
Any inbound request which has a valid JWT will have the claims made available:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
class MyController
|
234
|
+
def index
|
235
|
+
customer_id = request.env['roo.identity']['cust']
|
236
|
+
request.env['roo.identity'].class
|
237
|
+
# => JSON::JWT
|
238
|
+
end
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
Be aware that maliciously crafted JWTs will raise 401s that your other middleware can present
|
243
|
+
and poorly configured JWT set up will raise errors that you'll be able to catch in test.
|
244
|
+
|
219
245
|
### Google OAuth authentication
|
220
246
|
|
221
247
|
When `GOOGLE_AUTH_ENABLED` is set to true we inject a `Omniauth` Rack middleware
|
data/lib/roo_on_rails/logger.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
require 'logger'
|
2
1
|
require 'delegate'
|
3
2
|
require 'roo_on_rails/logfmt'
|
3
|
+
require 'rails/version'
|
4
|
+
|
5
|
+
if Rails::VERSION::MAJOR < 4
|
6
|
+
require 'logger'
|
7
|
+
else
|
8
|
+
require 'active_support/logger'
|
9
|
+
end
|
4
10
|
|
5
11
|
module RooOnRails
|
6
12
|
# A compatible replacement for the standard Logger to provide context, similar
|
@@ -30,7 +36,7 @@ module RooOnRails
|
|
30
36
|
class Logger < SimpleDelegator
|
31
37
|
def initialize(io = STDOUT)
|
32
38
|
@show_timestamp = io.tty?
|
33
|
-
logger =
|
39
|
+
logger = _default_logger_class.new(io).tap do |l|
|
34
40
|
l.formatter = method(:_formatter)
|
35
41
|
end
|
36
42
|
super(logger)
|
@@ -100,5 +106,13 @@ module RooOnRails
|
|
100
106
|
thread_key = @_context_stack_key ||= "roo_on_rails:logging_context:#{object_id}".freeze
|
101
107
|
Thread.current[thread_key] ||= [{}]
|
102
108
|
end
|
109
|
+
|
110
|
+
def _default_logger_class
|
111
|
+
if Rails::VERSION::MAJOR < 4
|
112
|
+
::Logger
|
113
|
+
else
|
114
|
+
ActiveSupport::Logger
|
115
|
+
end
|
116
|
+
end
|
103
117
|
end
|
104
118
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'json/jwt'
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
|
5
|
+
module RooOnRails
|
6
|
+
module Rack
|
7
|
+
class PopulateEnvFromJWT
|
8
|
+
UnacceptableKeyError = Class.new(RuntimeError)
|
9
|
+
# Hardcoded URLs for valid keys per environment. These will change very infrequently.
|
10
|
+
VALID_JWK_URL_PREFIXES = YAML.load(
|
11
|
+
File.read(File.expand_path('../valid_identity_service_prefixes.yml', __FILE__))
|
12
|
+
).freeze
|
13
|
+
|
14
|
+
def initialize(app, logger:, skip_sig_verify: true)
|
15
|
+
@app = app
|
16
|
+
@keys = {}
|
17
|
+
@logger = logger
|
18
|
+
|
19
|
+
if skip_sig_verify && development?
|
20
|
+
@logger.warn "JWTs signature verifification has been switched off in development."
|
21
|
+
@verify_sigs = false
|
22
|
+
else
|
23
|
+
@verify_sigs = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(env)
|
28
|
+
env['roo.identity'] = decode_authorization_header(env['HTTP_AUTHORIZATION'])
|
29
|
+
@app.call(env)
|
30
|
+
|
31
|
+
# Other exceptions will bubble up, allowing the higher middleware to return a 500, which is
|
32
|
+
# intentional.
|
33
|
+
rescue UnacceptableKeyError, JSON::JWT::Exception => e
|
34
|
+
# Identifying user is clearly attempting to hack or has been given a totally incorrect
|
35
|
+
# token, log this and flag as Forbidden, without executing the rest of the middleware stack.
|
36
|
+
::NewRelic::Agent.notice_error(e) if defined?(NewRelic)
|
37
|
+
[401, {}, []]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def development?
|
43
|
+
if ENV['RACK_ENV'].nil?
|
44
|
+
@logger.warn "Your RACK_ENV isn't set. You probably want it set to 'development' in dev."
|
45
|
+
end
|
46
|
+
|
47
|
+
ENV['RACK_ENV'] == 'development'
|
48
|
+
end
|
49
|
+
|
50
|
+
# @raise [UnacceptableKeyError,Faraday::Error,OpenSSL::OpenSSLError] From `#public_key`
|
51
|
+
# @raise [JSON::JWT::Exception] Bubble ups from `JSON::JWT.decode`
|
52
|
+
# @return [JSON::JWT] The list of claims this header makes by way of a JWS token. Will be an
|
53
|
+
# empty hash for invalid or absent tokens.
|
54
|
+
def decode_authorization_header(header_value)
|
55
|
+
return JSON::JWT.new unless (header_value || '').starts_with?('Bearer ')
|
56
|
+
jws_token = header_value[7..-1]
|
57
|
+
|
58
|
+
JSON::JWT.decode(jws_token, :skip_verification).tap do |jwt|
|
59
|
+
jwt.verify!(public_key(jwt.header[:jku])) if @verify_sigs
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def acceptable_key?(key_url)
|
64
|
+
return false if key_url.nil?
|
65
|
+
@key_prefixes ||= VALID_JWK_URL_PREFIXES[ENV['RACK_ENV']]
|
66
|
+
@key_prefixes.any? { |acceptable| key_url.starts_with?(acceptable) }
|
67
|
+
end
|
68
|
+
|
69
|
+
# @raise [UnacceptableKeyError] When the key URL is not from a trusted location
|
70
|
+
# @raise [Faraday::Error] When the JWK at the given URL is not retrievable for some reason.
|
71
|
+
# See: https://github.com/lostisland/faraday/blob/master/lib/faraday/error.rb
|
72
|
+
# @return [JSON::JWK] The JWK for the specified URL
|
73
|
+
def public_key(key_url)
|
74
|
+
unless acceptable_key?(key_url)
|
75
|
+
raise UnacceptableKeyError, "#{key_url} is not a valid Deliveroo Key URL"
|
76
|
+
end
|
77
|
+
|
78
|
+
# NB. don't use ||= memoization, or this middleware can be attacked by
|
79
|
+
# being asked to decode large numbers of non-existant key-ids, each of
|
80
|
+
# which would fill the @keys hash with a tuple.
|
81
|
+
return @keys[key_url] if @keys.key?(key_url)
|
82
|
+
|
83
|
+
@logger.info "Downloading identity public key from #{key_url}"
|
84
|
+
json = http_request.get(key_url).body
|
85
|
+
@keys[key_url] = JSON::JWK.new(json)
|
86
|
+
rescue Faraday::ParsingError
|
87
|
+
raise JSON::JWT::InvalidFormat, 'Downloaded JWK is not a valid JSON file'
|
88
|
+
end
|
89
|
+
|
90
|
+
def http_request
|
91
|
+
Faraday.new do |conf|
|
92
|
+
conf.response :json
|
93
|
+
conf.response :raise_error
|
94
|
+
conf.request :json
|
95
|
+
|
96
|
+
conf.adapter Faraday.default_adapter
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'roo_on_rails/config'
|
2
|
+
|
3
|
+
module RooOnRails
|
4
|
+
module Railties
|
5
|
+
class RooIdentity < Rails::Railtie
|
6
|
+
initializer 'roo_on_rails.roo_identity.middleware' do |app|
|
7
|
+
Rails.logger.with initializer: 'roo_on_rails.roo_identity' do |log|
|
8
|
+
log.debug 'loading'
|
9
|
+
_add_middleware(app, log)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def _add_middleware(app, log)
|
16
|
+
require 'roo_on_rails/rack/populate_env_from_jwt'
|
17
|
+
|
18
|
+
app.config.middleware.use RooOnRails::Rack::PopulateEnvFromJWT, logger: log
|
19
|
+
rescue LoadError
|
20
|
+
log.error 'the json-jwt gem is not in the bundle so Roo Identity will not be available'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/roo_on_rails/version.rb
CHANGED
data/roo_on_rails.gemspec
CHANGED
@@ -37,6 +37,9 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.add_runtime_dependency 'faraday_middleware'
|
38
38
|
spec.add_runtime_dependency 'routemaster-client'
|
39
39
|
|
40
|
+
# Optional gems you may add to your project
|
41
|
+
spec.add_development_dependency 'json-jwt', '~> 1.8'
|
42
|
+
|
40
43
|
spec.add_development_dependency 'bundler', '~> 1.13'
|
41
44
|
spec.add_development_dependency 'rake', '~> 10.0'
|
42
45
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
@@ -46,4 +49,5 @@ Gem::Specification.new do |spec|
|
|
46
49
|
spec.add_development_dependency 'simplecov'
|
47
50
|
spec.add_development_dependency 'codecov'
|
48
51
|
spec.add_development_dependency 'rack-test'
|
52
|
+
spec.add_development_dependency 'rspec-its'
|
49
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roo_on_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Letessier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv-rails
|
@@ -226,6 +226,20 @@ dependencies:
|
|
226
226
|
- - ">="
|
227
227
|
- !ruby/object:Gem::Version
|
228
228
|
version: '0'
|
229
|
+
- !ruby/object:Gem::Dependency
|
230
|
+
name: json-jwt
|
231
|
+
requirement: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - "~>"
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: '1.8'
|
236
|
+
type: :development
|
237
|
+
prerelease: false
|
238
|
+
version_requirements: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - "~>"
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: '1.8'
|
229
243
|
- !ruby/object:Gem::Dependency
|
230
244
|
name: bundler
|
231
245
|
requirement: !ruby/object:Gem::Requirement
|
@@ -352,6 +366,20 @@ dependencies:
|
|
352
366
|
- - ">="
|
353
367
|
- !ruby/object:Gem::Version
|
354
368
|
version: '0'
|
369
|
+
- !ruby/object:Gem::Dependency
|
370
|
+
name: rspec-its
|
371
|
+
requirement: !ruby/object:Gem::Requirement
|
372
|
+
requirements:
|
373
|
+
- - ">="
|
374
|
+
- !ruby/object:Gem::Version
|
375
|
+
version: '0'
|
376
|
+
type: :development
|
377
|
+
prerelease: false
|
378
|
+
version_requirements: !ruby/object:Gem::Requirement
|
379
|
+
requirements:
|
380
|
+
- - ">="
|
381
|
+
- !ruby/object:Gem::Version
|
382
|
+
version: '0'
|
355
383
|
description: Scaffolding for building services
|
356
384
|
email:
|
357
385
|
- julien.letessier@gmail.com
|
@@ -371,6 +399,7 @@ files:
|
|
371
399
|
- ".travis.yml"
|
372
400
|
- Appraisals
|
373
401
|
- CHANGELOG.md
|
402
|
+
- CONTRIBUTING.md
|
374
403
|
- Gemfile
|
375
404
|
- Guardfile
|
376
405
|
- LICENSE.txt
|
@@ -424,7 +453,9 @@ files:
|
|
424
453
|
- lib/roo_on_rails/logfmt.rb
|
425
454
|
- lib/roo_on_rails/logger.rb
|
426
455
|
- lib/roo_on_rails/papertrail_client.rb
|
456
|
+
- lib/roo_on_rails/rack/populate_env_from_jwt.rb
|
427
457
|
- lib/roo_on_rails/rack/safe_timeouts.rb
|
458
|
+
- lib/roo_on_rails/rack/valid_identity_service_prefixes.yml
|
428
459
|
- lib/roo_on_rails/railties/database.rb
|
429
460
|
- lib/roo_on_rails/railties/env.rb
|
430
461
|
- lib/roo_on_rails/railties/google_oauth.rb
|
@@ -432,6 +463,7 @@ files:
|
|
432
463
|
- lib/roo_on_rails/railties/logging.rb
|
433
464
|
- lib/roo_on_rails/railties/new_relic.rb
|
434
465
|
- lib/roo_on_rails/railties/rake_tasks.rb
|
466
|
+
- lib/roo_on_rails/railties/roo_identity.rb
|
435
467
|
- lib/roo_on_rails/railties/routemaster.rb
|
436
468
|
- lib/roo_on_rails/railties/sidekiq.rb
|
437
469
|
- lib/roo_on_rails/routemaster/lifecycle_events.rb
|
@@ -470,7 +502,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
470
502
|
version: '0'
|
471
503
|
requirements: []
|
472
504
|
rubyforge_project:
|
473
|
-
rubygems_version: 2.
|
505
|
+
rubygems_version: 2.6.11
|
474
506
|
signing_key:
|
475
507
|
specification_version: 4
|
476
508
|
summary: Scaffolding for building services
|