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