lhc 14.0.0 → 15.1.1
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 +4 -4
- data/README.md +56 -5
- data/lhc.gemspec +1 -0
- data/lib/lhc/config.rb +13 -0
- data/lib/lhc/error.rb +3 -4
- data/lib/lhc/interceptors/auth.rb +7 -1
- data/lib/lhc/interceptors/logging.rb +2 -2
- data/lib/lhc/interceptors/rollbar.rb +2 -2
- data/lib/lhc/request.rb +25 -1
- data/lib/lhc/response.rb +6 -0
- data/lib/lhc/scrubber.rb +45 -0
- data/lib/lhc/scrubbers/auth_scrubber.rb +33 -0
- data/lib/lhc/scrubbers/body_scrubber.rb +28 -0
- data/lib/lhc/scrubbers/cache_scrubber.rb +35 -0
- data/lib/lhc/scrubbers/effective_url_scrubber.rb +32 -0
- data/lib/lhc/scrubbers/headers_scrubber.rb +50 -0
- data/lib/lhc/scrubbers/params_scrubber.rb +14 -0
- data/lib/lhc/version.rb +1 -1
- data/lib/lhc.rb +16 -0
- data/spec/config/scrubs_spec.rb +108 -0
- data/spec/error/to_s_spec.rb +9 -7
- data/spec/interceptors/logging/main_spec.rb +21 -1
- data/spec/interceptors/rollbar/main_spec.rb +27 -15
- data/spec/request/scrubbed_headers_spec.rb +103 -0
- data/spec/request/scrubbed_options_spec.rb +214 -0
- data/spec/request/scrubbed_params_spec.rb +35 -0
- data/spec/response/scrubbed_options_spec.rb +20 -0
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 301499c3239741a748386c3e33d552611f2817f2880579b3df9e320b336db894
|
4
|
+
data.tar.gz: 27c61057ca12aa70076e0fbe71da8cf8f0eac225420dcdd11ba297336aea85e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 890dd068ed2902de6990b1b90ef5082f4f6d0c26e65022db14157615dd858f7302a8419b8457f6da403f3423aabdfa13f0838a748846f7f93e13339c0415eca6
|
7
|
+
data.tar.gz: e66683421af741d105294a5eb5fb33f26dbab024653b51647f3597e3256cd2bb114202d1599e4f0019f6157b08123afea794c68ddddd6f286518a99476c9dc9d
|
data/README.md
CHANGED
@@ -51,6 +51,7 @@ use it like:
|
|
51
51
|
* [Configuration](#configuration)
|
52
52
|
* [Configuring endpoints](#configuring-endpoints)
|
53
53
|
* [Configuring placeholders](#configuring-placeholders)
|
54
|
+
* [Configuring scrubs](#configuring-scrubs)
|
54
55
|
* [Interceptors](#interceptors)
|
55
56
|
* [Quick start: Configure/Enable Interceptors](#quick-start-configureenable-interceptors)
|
56
57
|
* [Interceptors on local request level](#interceptors-on-local-request-level)
|
@@ -491,6 +492,50 @@ You can configure global placeholders, that are used when generating urls from u
|
|
491
492
|
LHC.get(:feedbacks) # http://datastore/v2/feedbacks
|
492
493
|
```
|
493
494
|
|
495
|
+
### Configuring scrubs
|
496
|
+
|
497
|
+
You can filter out sensitive request data from your log files and rollbar by appending them to `LHS.config.scrubs`. These values will be marked `[FILTERED]` in the log and on rollbar. Also nested parameters are being filtered.
|
498
|
+
The scrubbing configuration affects all request done by LHC independent of the endpoint. You can scrub any attribute within `:params`, `:headers` or `:body`. For `:auth` you either can choose `:bearer` or `:basic` (default is both).
|
499
|
+
|
500
|
+
LHS scrubs per default:
|
501
|
+
- Bearer Token within the Request Header
|
502
|
+
- Basic Auth `username` and `password` within the Request Header
|
503
|
+
- `password` and `password_confirmation` within the Request Body
|
504
|
+
|
505
|
+
Enhance the default scrubbing by pushing the name of the parameter, which should be scrubbed, as string to the existing configuration.
|
506
|
+
You can also add multiple parameters at once by pushing multiple strings.
|
507
|
+
|
508
|
+
Example:
|
509
|
+
```ruby
|
510
|
+
LHC.configure do |c|
|
511
|
+
c.scrubs[:params] << 'api_key'
|
512
|
+
c.scrubs[:body].push('user_token', 'secret_key')
|
513
|
+
end
|
514
|
+
```
|
515
|
+
|
516
|
+
For disabling scrubbing, add following configuration:
|
517
|
+
```ruby
|
518
|
+
LHC.configure do |c|
|
519
|
+
c.scrubs = {}
|
520
|
+
end
|
521
|
+
```
|
522
|
+
|
523
|
+
If you want to turn off `:bearer` or `:basic` scrubbing, then just overwrite the `:auth` configuration.
|
524
|
+
|
525
|
+
Example:
|
526
|
+
```ruby
|
527
|
+
LHC.configure do |c|
|
528
|
+
c.scrubs[:auth] = [:bearer]
|
529
|
+
end
|
530
|
+
```
|
531
|
+
|
532
|
+
If your app has a different authentication strategy than Bearer Authentication or Basic Authentication then you can filter the data by scrubbing the whole header:
|
533
|
+
```ruby
|
534
|
+
LHC.configure do |c|
|
535
|
+
c.scrubs[:headers] << 'Authorization'
|
536
|
+
end
|
537
|
+
```
|
538
|
+
|
494
539
|
## Interceptors
|
495
540
|
|
496
541
|
To monitor and manipulate the HTTP communication done with LHC, you can define interceptors that follow the (Inteceptor Pattern)[https://en.wikipedia.org/wiki/Interceptor_pattern].
|
@@ -573,12 +618,18 @@ Adds the following to body of all requests:
|
|
573
618
|
|
574
619
|
##### Reauthenticate
|
575
620
|
|
576
|
-
The current implementation
|
577
|
-
|
578
|
-
|
579
|
-
|
621
|
+
The current implementation offers only reauthentication for _client access tokens_.
|
622
|
+
Make sure that your interceptors contain `LHC::Auth` and `LHC::Retry`, whereas `LHC::Retry` comes _after_ `LHC::Auth` in the chain.
|
623
|
+
Provide the refresh token as following:
|
624
|
+
```ruby
|
625
|
+
LHC.get('http://local.ch', auth: { bearer: -> { access_token }, refresh_client_token: -> { TokenRefreshUtil.client_access_token(true) })
|
626
|
+
```
|
627
|
+
Where `TokenRefreshUtil.client_access_token(true)` forces a refresh of the token and returns the new token. It is also expected that this implementation will handle invalidating caches if necessary.
|
580
628
|
|
581
|
-
|
629
|
+
You can also set a global `refresh_client_token`. This is not recommended for apps with multiple endpoint and different access tokens.
|
630
|
+
```ruby
|
631
|
+
LHC::Auth.refresh_client_token = -> { TokenRefreshUtil.client_access_token(true) }
|
632
|
+
```
|
582
633
|
|
583
634
|
Reauthentication will be initiated if:
|
584
635
|
|
data/lhc.gemspec
CHANGED
data/lib/lhc/config.rb
CHANGED
@@ -5,9 +5,12 @@ require 'singleton'
|
|
5
5
|
class LHC::Config
|
6
6
|
include Singleton
|
7
7
|
|
8
|
+
attr_accessor :scrubs
|
9
|
+
|
8
10
|
def initialize
|
9
11
|
@endpoints = {}
|
10
12
|
@placeholders = {}
|
13
|
+
@scrubs = default_scrubs
|
11
14
|
end
|
12
15
|
|
13
16
|
def endpoint(name, url, options = {})
|
@@ -42,9 +45,19 @@ class LHC::Config
|
|
42
45
|
@interceptors = interceptors
|
43
46
|
end
|
44
47
|
|
48
|
+
def default_scrubs
|
49
|
+
{
|
50
|
+
auth: [:bearer, :basic],
|
51
|
+
params: [],
|
52
|
+
headers: [],
|
53
|
+
body: ['password', 'password_confirmation']
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
45
57
|
def reset
|
46
58
|
@endpoints = {}
|
47
59
|
@placeholders = {}
|
48
60
|
@interceptors = nil
|
61
|
+
@scrubs = default_scrubs
|
49
62
|
end
|
50
63
|
end
|
data/lib/lhc/error.rb
CHANGED
@@ -72,13 +72,12 @@ class LHC::Error < StandardError
|
|
72
72
|
|
73
73
|
debug = []
|
74
74
|
debug << [request.method, request.url].map { |str| self.class.fix_invalid_encoding(str) }.join(' ')
|
75
|
-
debug << "Options: #{request.
|
76
|
-
debug << "Headers: #{request.
|
75
|
+
debug << "Options: #{request.scrubbed_options}"
|
76
|
+
debug << "Headers: #{request.scrubbed_headers}"
|
77
77
|
debug << "Response Code: #{response.code} (#{response.options[:return_code]})"
|
78
|
-
debug << "Response Options: #{response.
|
78
|
+
debug << "Response Options: #{response.scrubbed_options}"
|
79
79
|
debug << response.body
|
80
80
|
debug << _message
|
81
|
-
|
82
81
|
debug.map { |str| self.class.fix_invalid_encoding(str) }.join("\n")
|
83
82
|
end
|
84
83
|
end
|
@@ -30,7 +30,7 @@ class LHC::Auth < LHC::Interceptor
|
|
30
30
|
def basic_authentication!
|
31
31
|
auth = auth_options[:basic]
|
32
32
|
credentials = "#{auth[:username]}:#{auth[:password]}"
|
33
|
-
|
33
|
+
set_basic_authorization_header(Base64.strict_encode64(credentials).chomp)
|
34
34
|
end
|
35
35
|
|
36
36
|
def bearer_authentication!
|
@@ -44,7 +44,13 @@ class LHC::Auth < LHC::Interceptor
|
|
44
44
|
request.headers['Authorization'] = value
|
45
45
|
end
|
46
46
|
|
47
|
+
def set_basic_authorization_header(base_64_encoded_credentials)
|
48
|
+
request.options[:auth][:basic].merge!(base_64_encoded_credentials: base_64_encoded_credentials)
|
49
|
+
set_authorization_header("Basic #{base_64_encoded_credentials}")
|
50
|
+
end
|
51
|
+
|
47
52
|
def set_bearer_authorization_header(token)
|
53
|
+
request.options[:auth].merge!(bearer_token: token)
|
48
54
|
set_authorization_header("Bearer #{token}")
|
49
55
|
end
|
50
56
|
# rubocop:enable Style/AccessorMethodName
|
@@ -14,8 +14,8 @@ class LHC::Logging < LHC::Interceptor
|
|
14
14
|
"<#{request.object_id}>",
|
15
15
|
request.method.upcase,
|
16
16
|
"#{request.url} at #{Time.now.iso8601}",
|
17
|
-
"Params=#{request.
|
18
|
-
"Headers=#{request.
|
17
|
+
"Params=#{request.scrubbed_params}",
|
18
|
+
"Headers=#{request.scrubbed_headers}",
|
19
19
|
request.source ? "\nCalled from #{request.source}" : nil
|
20
20
|
].compact.join(' ')
|
21
21
|
)
|
@@ -23,8 +23,8 @@ class LHC::Rollbar < LHC::Interceptor
|
|
23
23
|
request: {
|
24
24
|
url: request.url,
|
25
25
|
method: request.method,
|
26
|
-
headers: request.
|
27
|
-
params: request.
|
26
|
+
headers: request.scrubbed_headers,
|
27
|
+
params: request.scrubbed_params
|
28
28
|
}
|
29
29
|
}.merge additional_params
|
30
30
|
begin
|
data/lib/lhc/request.rb
CHANGED
@@ -12,7 +12,13 @@ class LHC::Request
|
|
12
12
|
|
13
13
|
TYPHOEUS_OPTIONS ||= [:params, :method, :body, :headers, :follow_location, :params_encoding]
|
14
14
|
|
15
|
-
attr_accessor :response,
|
15
|
+
attr_accessor :response,
|
16
|
+
:options,
|
17
|
+
:raw,
|
18
|
+
:format,
|
19
|
+
:error_handler,
|
20
|
+
:errors_ignored,
|
21
|
+
:source
|
16
22
|
|
17
23
|
def initialize(options, self_executing = true)
|
18
24
|
self.errors_ignored = (options.fetch(:ignore, []) || []).to_a.compact
|
@@ -56,6 +62,24 @@ class LHC::Request
|
|
56
62
|
raw.run
|
57
63
|
end
|
58
64
|
|
65
|
+
def scrubbed_params
|
66
|
+
LHC::ParamsScrubber.new(params.deep_dup).scrubbed
|
67
|
+
end
|
68
|
+
|
69
|
+
def scrubbed_headers
|
70
|
+
LHC::HeadersScrubber.new(headers.deep_dup, options[:auth]).scrubbed
|
71
|
+
end
|
72
|
+
|
73
|
+
def scrubbed_options
|
74
|
+
scrubbed_options = options.deep_dup
|
75
|
+
scrubbed_options[:cache] = LHC::CacheScrubber.new(scrubbed_options[:cache]).scrubbed
|
76
|
+
scrubbed_options[:params] = LHC::ParamsScrubber.new(scrubbed_options[:params]).scrubbed
|
77
|
+
scrubbed_options[:headers] = LHC::HeadersScrubber.new(scrubbed_options[:headers], scrubbed_options[:auth]).scrubbed
|
78
|
+
scrubbed_options[:auth] = LHC::AuthScrubber.new(scrubbed_options[:auth]).scrubbed
|
79
|
+
scrubbed_options[:body] = LHC::BodyScrubber.new(scrubbed_options[:body]).scrubbed
|
80
|
+
scrubbed_options
|
81
|
+
end
|
82
|
+
|
59
83
|
private
|
60
84
|
|
61
85
|
attr_accessor :interceptors
|
data/lib/lhc/response.rb
CHANGED
@@ -54,6 +54,12 @@ class LHC::Response
|
|
54
54
|
request.format
|
55
55
|
end
|
56
56
|
|
57
|
+
def scrubbed_options
|
58
|
+
scrubbed_options = options.deep_dup
|
59
|
+
scrubbed_options[:effective_url] = LHC::EffectiveUrlScrubber.new(scrubbed_options[:effective_url]).scrubbed
|
60
|
+
scrubbed_options
|
61
|
+
end
|
62
|
+
|
57
63
|
private
|
58
64
|
|
59
65
|
attr_accessor :raw
|
data/lib/lhc/scrubber.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::Scrubber
|
4
|
+
attr_accessor :scrubbed
|
5
|
+
|
6
|
+
SCRUB_DISPLAY = '[FILTERED]'
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
@scrubbed = data
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def scrub_auth_elements
|
15
|
+
LHC.config.scrubs.dig(:auth)
|
16
|
+
end
|
17
|
+
|
18
|
+
def scrub!
|
19
|
+
return if scrub_elements.blank?
|
20
|
+
return if scrubbed.blank?
|
21
|
+
|
22
|
+
LHC::Scrubber.scrub_hash!(scrub_elements, scrubbed) if scrubbed.is_a?(Hash)
|
23
|
+
LHC::Scrubber.scrub_array!(scrub_elements, scrubbed) if scrubbed.is_a?(Array)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.scrub_array!(scrub_elements, scrubbed)
|
27
|
+
scrubbed.each do |scrubbed_hash|
|
28
|
+
LHC::Scrubber.scrub_hash!(scrub_elements, scrubbed_hash)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.scrub_hash!(scrub_elements, scrubbed)
|
33
|
+
scrub_elements.each do |scrub_element|
|
34
|
+
if scrubbed.key?(scrub_element.to_s)
|
35
|
+
key = scrub_element.to_s
|
36
|
+
elsif scrubbed.key?(scrub_element.to_sym)
|
37
|
+
key = scrub_element.to_sym
|
38
|
+
end
|
39
|
+
next if key.blank? || scrubbed[key].blank?
|
40
|
+
|
41
|
+
scrubbed[key] = SCRUB_DISPLAY
|
42
|
+
end
|
43
|
+
scrubbed.values.each { |v| LHC::Scrubber.scrub_hash!(scrub_elements, v) if v.instance_of?(Hash) }
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::AuthScrubber < LHC::Scrubber
|
4
|
+
def initialize(data)
|
5
|
+
super(data)
|
6
|
+
scrub_auth_options!
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def scrub_auth_options!
|
12
|
+
return if scrubbed.blank?
|
13
|
+
return if scrub_auth_elements.blank?
|
14
|
+
|
15
|
+
scrub_basic_auth_options! if scrub_auth_elements.include?(:basic)
|
16
|
+
scrub_bearer_auth_options! if scrub_auth_elements.include?(:bearer)
|
17
|
+
end
|
18
|
+
|
19
|
+
def scrub_basic_auth_options!
|
20
|
+
return if scrubbed[:basic].blank?
|
21
|
+
|
22
|
+
scrubbed[:basic][:username] = SCRUB_DISPLAY
|
23
|
+
scrubbed[:basic][:password] = SCRUB_DISPLAY
|
24
|
+
scrubbed[:basic][:base_64_encoded_credentials] = SCRUB_DISPLAY
|
25
|
+
end
|
26
|
+
|
27
|
+
def scrub_bearer_auth_options!
|
28
|
+
return if scrubbed[:bearer].blank?
|
29
|
+
|
30
|
+
scrubbed[:bearer] = SCRUB_DISPLAY if scrubbed[:bearer].is_a?(String)
|
31
|
+
scrubbed[:bearer_token] = SCRUB_DISPLAY
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::BodyScrubber < LHC::Scrubber
|
4
|
+
def initialize(data)
|
5
|
+
super(data)
|
6
|
+
parse!
|
7
|
+
scrub!
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def scrub_elements
|
13
|
+
LHC.config.scrubs[:body]
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse!
|
17
|
+
return if scrubbed.nil? || scrubbed.is_a?(Hash) || scrubbed.is_a?(Array)
|
18
|
+
|
19
|
+
if scrubbed.is_a?(String)
|
20
|
+
json = scrubbed
|
21
|
+
else
|
22
|
+
json = scrubbed.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
parsed = JSON.parse(json)
|
26
|
+
self.scrubbed = parsed if parsed.is_a?(Hash) || parsed.is_a?(Array)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::CacheScrubber < LHC::Scrubber
|
4
|
+
def initialize(data)
|
5
|
+
super(data)
|
6
|
+
scrub_cache_options!
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def scrub_cache_options!
|
12
|
+
return if scrubbed.blank?
|
13
|
+
return if scrub_elements.blank?
|
14
|
+
|
15
|
+
scrub_cache_key!
|
16
|
+
end
|
17
|
+
|
18
|
+
def scrub_cache_key!
|
19
|
+
return if scrubbed[:key].blank?
|
20
|
+
|
21
|
+
scrub_elements.each do |scrub_element|
|
22
|
+
matches = scrubbed[:key].match(/:#{scrub_element}=>"(.*?)"/)
|
23
|
+
next if matches.nil?
|
24
|
+
|
25
|
+
value = matches[-1]
|
26
|
+
scrubbed[:key].gsub!(value, SCRUB_DISPLAY)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def scrub_elements
|
31
|
+
# The cache key includes the whole request url inklusive params.
|
32
|
+
# We need to scrub those params from the cache key.
|
33
|
+
LHC.config.scrubs[:params]
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::EffectiveUrlScrubber < LHC::Scrubber
|
4
|
+
def initialize(data)
|
5
|
+
super(data)
|
6
|
+
scrub_effective_url_options!
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def scrub_effective_url_options!
|
12
|
+
return if scrubbed.blank?
|
13
|
+
return if scrub_elements.blank?
|
14
|
+
|
15
|
+
scrub_effective_url!
|
16
|
+
end
|
17
|
+
|
18
|
+
def scrub_effective_url!
|
19
|
+
return if scrubbed.blank?
|
20
|
+
|
21
|
+
scrub_elements.each do |scrub_element|
|
22
|
+
uri = LocalUri::URI.new(scrubbed)
|
23
|
+
self.scrubbed = CGI.unescape(uri.query.merge(scrub_element => SCRUB_DISPLAY).to_s)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def scrub_elements
|
28
|
+
# The effective url includes the params of the request
|
29
|
+
# so we need to scrub those params from the effective url.
|
30
|
+
LHC.config.scrubs[:params]
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class LHC::HeadersScrubber < LHC::Scrubber
|
4
|
+
def initialize(data, auth_options)
|
5
|
+
super(data)
|
6
|
+
@auth_options = auth_options
|
7
|
+
scrub!
|
8
|
+
scrub_auth_headers!
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :auth_options
|
14
|
+
|
15
|
+
def scrub_elements
|
16
|
+
LHC.config.scrubs[:headers]
|
17
|
+
end
|
18
|
+
|
19
|
+
def scrub_auth_headers!
|
20
|
+
return if scrub_auth_elements.blank?
|
21
|
+
return if auth_options.blank?
|
22
|
+
|
23
|
+
scrub_basic_authentication_headers! if scrub_auth_elements.include?(:basic)
|
24
|
+
scrub_bearer_authentication_headers! if scrub_auth_elements.include?(:bearer)
|
25
|
+
end
|
26
|
+
|
27
|
+
def scrub_basic_authentication_headers!
|
28
|
+
return if !scrub_basic_authentication_headers?
|
29
|
+
|
30
|
+
scrubbed['Authorization'].gsub!(auth_options[:basic][:base_64_encoded_credentials], SCRUB_DISPLAY)
|
31
|
+
end
|
32
|
+
|
33
|
+
def scrub_bearer_authentication_headers!
|
34
|
+
return if !scrub_bearer_authentication_headers?
|
35
|
+
|
36
|
+
scrubbed['Authorization'].gsub!(auth_options[:bearer_token], SCRUB_DISPLAY)
|
37
|
+
end
|
38
|
+
|
39
|
+
def scrub_basic_authentication_headers?
|
40
|
+
auth_options[:basic].present? &&
|
41
|
+
scrubbed['Authorization'].present? &&
|
42
|
+
scrubbed['Authorization'].include?(auth_options[:basic][:base_64_encoded_credentials])
|
43
|
+
end
|
44
|
+
|
45
|
+
def scrub_bearer_authentication_headers?
|
46
|
+
auth_options[:bearer].present? &&
|
47
|
+
scrubbed['Authorization'].present? &&
|
48
|
+
scrubbed['Authorization'].include?(auth_options[:bearer_token])
|
49
|
+
end
|
50
|
+
end
|
data/lib/lhc/version.rb
CHANGED
data/lib/lhc.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'local_uri'
|
3
4
|
require 'typhoeus'
|
4
5
|
require 'active_support/core_ext/object/blank'
|
5
6
|
require 'active_support/core_ext/hash/keys'
|
@@ -113,6 +114,21 @@ module LHC
|
|
113
114
|
autoload :UnknownError,
|
114
115
|
'lhc/errors/unknown_error'
|
115
116
|
|
117
|
+
autoload :Scrubber,
|
118
|
+
'lhc/scrubber'
|
119
|
+
autoload :AuthScrubber,
|
120
|
+
'lhc/scrubbers/auth_scrubber'
|
121
|
+
autoload :BodyScrubber,
|
122
|
+
'lhc/scrubbers/body_scrubber'
|
123
|
+
autoload :CacheScrubber,
|
124
|
+
'lhc/scrubbers/cache_scrubber'
|
125
|
+
autoload :EffectiveUrlScrubber,
|
126
|
+
'lhc/scrubbers/effective_url_scrubber'
|
127
|
+
autoload :HeadersScrubber,
|
128
|
+
'lhc/scrubbers/headers_scrubber'
|
129
|
+
autoload :ParamsScrubber,
|
130
|
+
'lhc/scrubbers/params_scrubber'
|
131
|
+
|
116
132
|
autoload :Interceptor,
|
117
133
|
'lhc/interceptor'
|
118
134
|
autoload :Interceptors,
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC do
|
6
|
+
it 'has a default value for scrubs' do
|
7
|
+
expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
|
8
|
+
expect(LHC.config.scrubs[:params]).to eq []
|
9
|
+
expect(LHC.config.scrubs[:headers]).to eq []
|
10
|
+
expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'auth' do
|
14
|
+
context 'when only bearer auth should get scrubbed' do
|
15
|
+
before(:each) do
|
16
|
+
LHC.configure do |c|
|
17
|
+
c.scrubs[:auth] = [:bearer]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has only bearer auth in scrubs' do
|
22
|
+
expect(LHC.config.scrubs[:auth]).to eq([:bearer])
|
23
|
+
expect(LHC.config.scrubs[:params]).to eq []
|
24
|
+
expect(LHC.config.scrubs[:headers]).to eq []
|
25
|
+
expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'params' do
|
31
|
+
context 'when additional param "api_key" should be scrubbed' do
|
32
|
+
before(:each) do
|
33
|
+
LHC.configure do |c|
|
34
|
+
c.scrubs[:params] << 'api_key'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'has "api_key" in scrubs' do
|
39
|
+
expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
|
40
|
+
expect(LHC.config.scrubs[:params]).to eq ['api_key']
|
41
|
+
expect(LHC.config.scrubs[:headers]).to eq []
|
42
|
+
expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'headers' do
|
48
|
+
context 'when additional header "private_key" should be scrubbed' do
|
49
|
+
before(:each) do
|
50
|
+
LHC.configure do |c|
|
51
|
+
c.scrubs[:headers] << 'private_key'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'has "private_key" in scrubs' do
|
56
|
+
expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
|
57
|
+
expect(LHC.config.scrubs[:params]).to eq []
|
58
|
+
expect(LHC.config.scrubs[:headers]).to eq ['private_key']
|
59
|
+
expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'body' do
|
65
|
+
context 'when only password should get scrubbed' do
|
66
|
+
before(:each) do
|
67
|
+
LHC.configure do |c|
|
68
|
+
c.scrubs[:body] = ['password']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'has password in scrubs' do
|
73
|
+
expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
|
74
|
+
expect(LHC.config.scrubs[:params]).to eq []
|
75
|
+
expect(LHC.config.scrubs[:headers]).to eq []
|
76
|
+
expect(LHC.config.scrubs[:body]).to eq(['password'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when "user_token" should be scrubbed' do
|
81
|
+
before(:each) do
|
82
|
+
LHC.configure do |c|
|
83
|
+
c.scrubs[:body] << 'user_token'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'has user_token in scrubs' do
|
88
|
+
expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
|
89
|
+
expect(LHC.config.scrubs[:params]).to eq []
|
90
|
+
expect(LHC.config.scrubs[:headers]).to eq []
|
91
|
+
expect(LHC.config.scrubs[:body]).to eq(['password', 'password_confirmation', 'user_token'])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when nothing should be scrubbed' do
|
97
|
+
before(:each) do
|
98
|
+
LHC.configure do |c|
|
99
|
+
c.scrubs = {}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'does not have scrubs' do
|
104
|
+
expect(LHC.config.scrubs.blank?).to be true
|
105
|
+
expect(LHC.config.scrubs[:auth]).to be nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/spec/error/to_s_spec.rb
CHANGED
@@ -48,17 +48,19 @@ describe LHC::Error do
|
|
48
48
|
double('LHC::Request',
|
49
49
|
method: 'GET',
|
50
50
|
url: 'http://example.com/sessions',
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
scrubbed_headers: { 'Bearer Token' => LHC::Scrubber::SCRUB_DISPLAY },
|
52
|
+
scrubbed_options: { followlocation: true,
|
53
|
+
auth: { bearer: LHC::Scrubber::SCRUB_DISPLAY },
|
54
|
+
params: { limit: 20 }, url: "http://example.com/sessions" })
|
55
55
|
end
|
56
56
|
|
57
57
|
let(:response) do
|
58
|
+
options = { return_code: :internal_error, response_headers: "" }
|
58
59
|
double('LHC::Response',
|
59
60
|
request: request,
|
60
61
|
code: 500,
|
61
|
-
options:
|
62
|
+
options: options,
|
63
|
+
scrubbed_options: options,
|
62
64
|
body: '{"status":500,"message":"undefined"}')
|
63
65
|
end
|
64
66
|
|
@@ -72,8 +74,8 @@ describe LHC::Error do
|
|
72
74
|
it 'produces correct debug output' do
|
73
75
|
expect(subject.to_s.split("\n")).to eq(<<-MSG.strip_heredoc.split("\n"))
|
74
76
|
GET http://example.com/sessions
|
75
|
-
Options: {:followlocation=>true, :auth=>{:bearer=>"
|
76
|
-
Headers: {"Bearer Token"=>"
|
77
|
+
Options: {:followlocation=>true, :auth=>{:bearer=>"#{LHC::Scrubber::SCRUB_DISPLAY}"}, :params=>{:limit=>20}, :url=>"http://example.com/sessions"}
|
78
|
+
Headers: {"Bearer Token"=>"#{LHC::Scrubber::SCRUB_DISPLAY}"}
|
77
79
|
Response Code: 500 (internal_error)
|
78
80
|
Response Options: {:return_code=>:internal_error, :response_headers=>""}
|
79
81
|
{"status":500,"message":"undefined"}
|
@@ -8,7 +8,7 @@ describe LHC::Logging do
|
|
8
8
|
before(:each) do
|
9
9
|
LHC.config.interceptors = [LHC::Logging]
|
10
10
|
LHC::Logging.logger = logger
|
11
|
-
stub_request(:get,
|
11
|
+
stub_request(:get, /http:\/\/local.ch.*/).to_return(status: 200)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'does log information before and after every request made with LHC' do
|
@@ -34,4 +34,24 @@ describe LHC::Logging do
|
|
34
34
|
)
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
context 'sensitive data' do
|
39
|
+
before :each do
|
40
|
+
LHC.config.scrubs[:params] << 'api_key'
|
41
|
+
LHC.config.scrubs[:headers] << 'private_key'
|
42
|
+
LHC.get('http://local.ch', params: { api_key: '123-abc' }, headers: { private_key: 'abc-123' })
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not log sensitive params information' do
|
46
|
+
expect(logger).to have_received(:info).once.with(
|
47
|
+
a_string_including("Params={:api_key=>\"#{LHC::Scrubber::SCRUB_DISPLAY}\"}")
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'does not log sensitive header information' do
|
52
|
+
expect(logger).to have_received(:info).once.with(
|
53
|
+
a_string_including(":private_key=>\"#{LHC::Scrubber::SCRUB_DISPLAY}\"")
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
37
57
|
end
|
@@ -36,22 +36,34 @@ describe LHC::Rollbar do
|
|
36
36
|
)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
additional: 'data'
|
52
|
-
)
|
39
|
+
it 'does report errors to rollbar with additional data' do
|
40
|
+
stub_request(:get, 'http://local.ch')
|
41
|
+
.to_return(status: 400)
|
42
|
+
expect(-> { LHC.get('http://local.ch', rollbar: { additional: 'data' }) })
|
43
|
+
.to raise_error LHC::BadRequest
|
44
|
+
expect(::Rollbar).to have_received(:warning)
|
45
|
+
.with(
|
46
|
+
'Status: 400 URL: http://local.ch',
|
47
|
+
hash_including(
|
48
|
+
response: anything,
|
49
|
+
request: anything,
|
50
|
+
additional: 'data'
|
53
51
|
)
|
54
|
-
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'scrubs sensitive data' do
|
56
|
+
LHC.config.scrubs[:params] << 'api_key'
|
57
|
+
LHC.config.scrubs[:headers] << 'private_key'
|
58
|
+
stub_request(:get, 'http://local.ch?api_key=123-abc').to_return(status: 400)
|
59
|
+
expect(-> { LHC.get('http://local.ch', params: { api_key: '123-abc' }, headers: { private_key: 'abc-123' }) })
|
60
|
+
.to raise_error LHC::BadRequest
|
61
|
+
expect(::Rollbar).to have_received(:warning)
|
62
|
+
.with(
|
63
|
+
'Status: 400 URL: http://local.ch',
|
64
|
+
response: hash_including(body: anything, code: anything, headers: anything, time: anything, timeout?: anything),
|
65
|
+
request: hash_including(url: anything, method: anything, headers: hash_including(private_key: LHC::Scrubber::SCRUB_DISPLAY), params: { api_key: LHC::Scrubber::SCRUB_DISPLAY })
|
66
|
+
)
|
55
67
|
end
|
56
68
|
end
|
57
69
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Request do
|
6
|
+
let(:headers) { { private_key: 'xyz-123' } }
|
7
|
+
let(:response) { LHC.get(:local, headers: headers) }
|
8
|
+
let(:auth) { {} }
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
LHC.config.endpoint(:local, 'http://local.ch', auth: auth)
|
12
|
+
stub_request(:get, 'http://local.ch').with(headers: headers)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'scrubs "private_key"' do
|
16
|
+
LHC.config.scrubs[:headers] << 'private_key'
|
17
|
+
expect(response.request.scrubbed_headers).to include(private_key: LHC::Scrubber::SCRUB_DISPLAY)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'does not add a new attribute when a non existing header should be scrubbed' do
|
21
|
+
LHC.config.scrubs[:headers] << 'anything'
|
22
|
+
expect(response.request.scrubbed_headers).not_to include('anything' => LHC::Scrubber::SCRUB_DISPLAY)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when strings instead of symbols are provided' do
|
26
|
+
let(:headers) { { 'private_key' => 'xyz-123' } }
|
27
|
+
|
28
|
+
it 'scrubs "private_key"' do
|
29
|
+
LHC.config.scrubs[:headers] << 'private_key'
|
30
|
+
expect(response.request.scrubbed_headers).to include('private_key' => LHC::Scrubber::SCRUB_DISPLAY)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'other authentication strategy' do
|
35
|
+
let(:api_key) { '123456' }
|
36
|
+
let(:authorization_header) { { 'Authorization' => "Apikey #{api_key}" } }
|
37
|
+
let(:headers) { authorization_header }
|
38
|
+
|
39
|
+
it 'provides srubbed Authorization header' do
|
40
|
+
LHC.config.scrubs[:headers] << 'Authorization'
|
41
|
+
expect(response.request.scrubbed_headers).to include('Authorization' => LHC::Scrubber::SCRUB_DISPLAY)
|
42
|
+
expect(response.request.headers).to include(authorization_header)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'auth' do
|
47
|
+
before :each do
|
48
|
+
LHC.config.interceptors = [LHC::Auth]
|
49
|
+
stub_request(:get, 'http://local.ch').with(headers: authorization_header)
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:request) do
|
53
|
+
response = LHC.get(:local)
|
54
|
+
response.request
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'bearer authentication' do
|
58
|
+
let(:bearer_token) { '123456' }
|
59
|
+
let(:authorization_header) { { 'Authorization' => "Bearer #{bearer_token}" } }
|
60
|
+
let(:auth) { { bearer: -> { bearer_token } } }
|
61
|
+
|
62
|
+
it 'scrubs only the bearer token' do
|
63
|
+
expect(request.scrubbed_headers).to include('Authorization' => "Bearer #{LHC::Scrubber::SCRUB_DISPLAY}")
|
64
|
+
expect(request.headers).to include(authorization_header)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'scrubs whole "Authorization" header' do
|
68
|
+
LHC.config.scrubs[:headers] << 'Authorization'
|
69
|
+
expect(request.scrubbed_headers).to include('Authorization' => LHC::Scrubber::SCRUB_DISPLAY)
|
70
|
+
expect(request.headers).to include(authorization_header)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'scrubs nothing' do
|
74
|
+
LHC.config.scrubs = {}
|
75
|
+
expect(request.scrubbed_headers).to include(authorization_header)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'basic authentication' do
|
80
|
+
let(:username) { 'steve' }
|
81
|
+
let(:password) { 'abcdefg' }
|
82
|
+
let(:credentials_base_64_codiert) { Base64.strict_encode64("#{username}:#{password}").chomp }
|
83
|
+
let(:authorization_header) { { 'Authorization' => "Basic #{credentials_base_64_codiert}" } }
|
84
|
+
let(:auth) { { basic: { username: username, password: password } } }
|
85
|
+
|
86
|
+
it 'scrubs only credentials' do
|
87
|
+
expect(request.scrubbed_headers).to include('Authorization' => "Basic #{LHC::Scrubber::SCRUB_DISPLAY}")
|
88
|
+
expect(request.headers).to include(authorization_header)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'scrubs whole "Authorization" header' do
|
92
|
+
LHC.config.scrubs[:headers] << 'Authorization'
|
93
|
+
expect(request.scrubbed_headers).to include('Authorization' => LHC::Scrubber::SCRUB_DISPLAY)
|
94
|
+
expect(request.headers).to include(authorization_header)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'scrubs nothing' do
|
98
|
+
LHC.config.scrubs = {}
|
99
|
+
expect(request.scrubbed_headers).to include(authorization_header)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Request do
|
6
|
+
before :each do
|
7
|
+
LHC.config.interceptors = [LHC::Auth]
|
8
|
+
LHC.config.endpoint(:local, 'http://local.ch', auth: auth)
|
9
|
+
LHC.config.scrubs[:params] << 'api_key'
|
10
|
+
LHC.config.scrubs[:headers] << 'private_key'
|
11
|
+
LHC.config.scrubs[:body] << 'user_token'
|
12
|
+
stub_request(:post, "http://local.ch?#{params.to_query}").with(headers: authorization_header.merge(headers), body: body.to_json)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:bearer_token) { '123456' }
|
16
|
+
let(:authorization_header) { { 'Authorization' => "Bearer #{bearer_token}" } }
|
17
|
+
let(:auth) { { bearer: -> { bearer_token } } }
|
18
|
+
let(:params) { { api_key: 'api-key-params' } }
|
19
|
+
let(:headers) { { private_key: 'private-key-header' } }
|
20
|
+
let(:body) { { user_token: 'user-token-body' } }
|
21
|
+
let(:cache) do
|
22
|
+
{ key: "LHS_REQUEST_CYCLE_CACHE(v1) POST http://local.ch?#{params}" }
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:request) do
|
26
|
+
response = LHC.post(:local, params: params, headers: headers, body: body, cache: cache)
|
27
|
+
response.request
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'provides srubbed request options' do
|
31
|
+
expect(request.scrubbed_options[:params]).to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
32
|
+
expect(request.scrubbed_options[:headers]).to include(private_key: LHC::Scrubber::SCRUB_DISPLAY)
|
33
|
+
expect(request.scrubbed_options[:body]).to include(user_token: LHC::Scrubber::SCRUB_DISPLAY)
|
34
|
+
expect(request.scrubbed_options[:auth][:bearer_token]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
35
|
+
expect(request.scrubbed_options[:auth][:basic]).to be nil
|
36
|
+
expect(request.scrubbed_options[:cache])
|
37
|
+
.to include(key: "LHS_REQUEST_CYCLE_CACHE(v1) POST http://local.ch?{:api_key=>\"[FILTERED]\"}")
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when bearer auth is not a proc' do
|
41
|
+
let(:auth) { { bearer: bearer_token } }
|
42
|
+
|
43
|
+
it 'also scrubbes the bearer' do
|
44
|
+
expect(request.scrubbed_options[:auth][:bearer]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
45
|
+
expect(request.scrubbed_options[:auth][:bearer_token]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when options do not have auth' do
|
50
|
+
let(:authorization_header) { {} }
|
51
|
+
let(:auth) { nil }
|
52
|
+
|
53
|
+
it 'provides srubbed request options' do
|
54
|
+
expect(request.scrubbed_options[:params]).to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
55
|
+
expect(request.scrubbed_options[:headers]).to include(private_key: LHC::Scrubber::SCRUB_DISPLAY)
|
56
|
+
expect(request.scrubbed_options[:body]).to include(user_token: LHC::Scrubber::SCRUB_DISPLAY)
|
57
|
+
expect(request.scrubbed_options[:auth]).to be nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when parameter should not get scrubbed' do
|
62
|
+
let(:params) { { any_parameter: 'any-parameter' } }
|
63
|
+
|
64
|
+
let(:cache) do
|
65
|
+
{ key: "LHS_REQUEST_CYCLE_CACHE(v1) POST http://local.ch?#{params}" }
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not scrubb the parameter' do
|
69
|
+
expect(request.scrubbed_options[:cache])
|
70
|
+
.to include(key: "LHS_REQUEST_CYCLE_CACHE(v1) POST http://local.ch?#{params}")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when body data is nested' do
|
75
|
+
let(:body) do
|
76
|
+
{
|
77
|
+
data: {
|
78
|
+
attributes: {
|
79
|
+
employee: {
|
80
|
+
name: 'Muster',
|
81
|
+
surname: 'Hans',
|
82
|
+
password: 'test-1234',
|
83
|
+
password_confirmation: 'test-1234'
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'srubbes nested attributes' do
|
91
|
+
expect(request.scrubbed_options[:params]).to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
92
|
+
expect(request.scrubbed_options[:headers]).to include(private_key: LHC::Scrubber::SCRUB_DISPLAY)
|
93
|
+
expect(request.scrubbed_options[:body][:data][:attributes][:employee]).to include(password: LHC::Scrubber::SCRUB_DISPLAY)
|
94
|
+
expect(request.scrubbed_options[:body][:data][:attributes][:employee]).to include(password_confirmation: LHC::Scrubber::SCRUB_DISPLAY)
|
95
|
+
expect(request.scrubbed_options[:auth][:bearer_token]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
96
|
+
expect(request.scrubbed_options[:auth][:basic]).to be nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'basic authentication' do
|
101
|
+
let(:username) { 'steve' }
|
102
|
+
let(:password) { 'abcdefg' }
|
103
|
+
let(:credentials_base_64_codiert) { Base64.strict_encode64("#{username}:#{password}").chomp }
|
104
|
+
let(:authorization_header) { { 'Authorization' => "Basic #{credentials_base_64_codiert}" } }
|
105
|
+
let(:auth) { { basic: { username: username, password: password } } }
|
106
|
+
|
107
|
+
it 'provides srubbed request headers' do
|
108
|
+
expect(request.scrubbed_options[:auth][:basic][:username]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
109
|
+
expect(request.scrubbed_options[:auth][:basic][:password]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
110
|
+
expect(request.scrubbed_options[:auth][:basic][:base_64_encoded_credentials]).to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
111
|
+
expect(request.scrubbed_options[:auth][:bearer]).to be nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when nothing should get scrubbed' do
|
116
|
+
before :each do
|
117
|
+
LHC.config.scrubs = {}
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'does not filter anything' do
|
121
|
+
expect(request.scrubbed_options[:params]).not_to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
122
|
+
expect(request.scrubbed_options[:headers]).not_to include(private_key: LHC::Scrubber::SCRUB_DISPLAY)
|
123
|
+
expect(request.scrubbed_options[:body]).not_to include(user_token: LHC::Scrubber::SCRUB_DISPLAY)
|
124
|
+
expect(request.scrubbed_options[:auth][:bearer_token]).not_to eq(LHC::Scrubber::SCRUB_DISPLAY)
|
125
|
+
expect(request.scrubbed_options[:cache])
|
126
|
+
.not_to include(key: "LHS_REQUEST_CYCLE_CACHE(v1) POST http://local.ch?{:api_key=>\"[FILTERED]\"}")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'custom data structures that respond to as_json (like LHS data or record)' do
|
131
|
+
before do
|
132
|
+
class CustomStructure
|
133
|
+
|
134
|
+
def initialize(data)
|
135
|
+
@data = data
|
136
|
+
end
|
137
|
+
|
138
|
+
def as_json
|
139
|
+
@data.as_json
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_json
|
143
|
+
as_json.to_json
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
stub_request(:post, 'http://local.ch').with(body: custom_structure.to_json)
|
148
|
+
end
|
149
|
+
|
150
|
+
let(:custom_structure) do
|
151
|
+
CustomStructure.new(user_token: '12345')
|
152
|
+
end
|
153
|
+
|
154
|
+
let(:request) do
|
155
|
+
response = LHC.post(:local, body: custom_structure)
|
156
|
+
response.request
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'provides srubbed request options' do
|
160
|
+
expect(request.scrubbed_options[:body]).to include('user_token' => LHC::Scrubber::SCRUB_DISPLAY)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'encoded data hash' do
|
165
|
+
let(:body) { { user_token: 'user-token-body' } }
|
166
|
+
|
167
|
+
let(:request) do
|
168
|
+
response = LHC.post(:local, body: body.to_json)
|
169
|
+
response.request
|
170
|
+
end
|
171
|
+
|
172
|
+
before :each do
|
173
|
+
stub_request(:post, 'http://local.ch').with(body: body.to_json)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'provides srubbed request options' do
|
177
|
+
expect(request.scrubbed_options[:body]).to include('user_token' => LHC::Scrubber::SCRUB_DISPLAY)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'array' do
|
182
|
+
let(:body) { [{ user_token: 'user-token-body' }] }
|
183
|
+
|
184
|
+
let(:request) do
|
185
|
+
response = LHC.post(:local, body: body)
|
186
|
+
response.request
|
187
|
+
end
|
188
|
+
|
189
|
+
before :each do
|
190
|
+
stub_request(:post, 'http://local.ch').with(body: body.to_json)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'provides srubbed request options' do
|
194
|
+
expect(request.scrubbed_options[:body]).to eq([user_token: LHC::Scrubber::SCRUB_DISPLAY])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'encoded array' do
|
199
|
+
let(:body) { [{ user_token: 'user-token-body' }] }
|
200
|
+
|
201
|
+
let(:request) do
|
202
|
+
response = LHC.post(:local, body: body.to_json)
|
203
|
+
response.request
|
204
|
+
end
|
205
|
+
|
206
|
+
before :each do
|
207
|
+
stub_request(:post, 'http://local.ch').with(body: body.to_json)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'provides srubbed request options' do
|
211
|
+
expect(request.scrubbed_options[:body]).to eq(['user_token' => LHC::Scrubber::SCRUB_DISPLAY])
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Request do
|
6
|
+
let(:params) { { api_key: 'xyz-123', secret_key: '123-xyz' } }
|
7
|
+
let(:response) { LHC.get(:local, params: params) }
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
LHC.config.endpoint(:local, 'http://local.ch')
|
11
|
+
stub_request(:get, "http://local.ch?#{params.to_query}")
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'scrubs "api_key"' do
|
15
|
+
LHC.config.scrubs[:params] << 'api_key'
|
16
|
+
expect(response.request.scrubbed_params).to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
17
|
+
expect(response.request.scrubbed_params).to include(secret_key: '123-xyz')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'scrubs "api_key" and "secret_key"' do
|
21
|
+
LHC.config.scrubs[:params].push('api_key', 'secret_key')
|
22
|
+
expect(response.request.scrubbed_params).to include(api_key: LHC::Scrubber::SCRUB_DISPLAY)
|
23
|
+
expect(response.request.scrubbed_params).to include(secret_key: LHC::Scrubber::SCRUB_DISPLAY)
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when value is empty' do
|
27
|
+
let(:params) { { api_key: nil, secret_key: '' } }
|
28
|
+
|
29
|
+
it 'does not filter the value' do
|
30
|
+
LHC.config.scrubs[:params].push('api_key', 'secret_key')
|
31
|
+
expect(response.request.scrubbed_params).to include(api_key: nil)
|
32
|
+
expect(response.request.scrubbed_params).to include(secret_key: '')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe LHC::Response do
|
6
|
+
let(:options) do
|
7
|
+
{ effective_url: 'http://local.ch?api_key=api-key' }
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:raw_response) { OpenStruct.new(options: options) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
LHC.config.scrubs[:params] << 'api_key'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'scrubbes effective url' do
|
17
|
+
response = LHC::Response.new(raw_response, nil)
|
18
|
+
expect(response.scrubbed_options[:effective_url]).to eq "http://local.ch?api_key=#{LHC::Scrubber::SCRUB_DISPLAY}"
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lhc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 15.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/local-ch/lhc/contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: local_uri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: typhoeus
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -270,6 +284,13 @@ files:
|
|
270
284
|
- lib/lhc/response/data/collection.rb
|
271
285
|
- lib/lhc/response/data/item.rb
|
272
286
|
- lib/lhc/rspec.rb
|
287
|
+
- lib/lhc/scrubber.rb
|
288
|
+
- lib/lhc/scrubbers/auth_scrubber.rb
|
289
|
+
- lib/lhc/scrubbers/body_scrubber.rb
|
290
|
+
- lib/lhc/scrubbers/cache_scrubber.rb
|
291
|
+
- lib/lhc/scrubbers/effective_url_scrubber.rb
|
292
|
+
- lib/lhc/scrubbers/headers_scrubber.rb
|
293
|
+
- lib/lhc/scrubbers/params_scrubber.rb
|
273
294
|
- lib/lhc/test/cache_helper.rb
|
274
295
|
- lib/lhc/version.rb
|
275
296
|
- script/ci/build.sh
|
@@ -281,6 +302,7 @@ files:
|
|
281
302
|
- spec/basic_methods/request_without_rails_spec.rb
|
282
303
|
- spec/config/endpoints_spec.rb
|
283
304
|
- spec/config/placeholders_spec.rb
|
305
|
+
- spec/config/scrubs_spec.rb
|
284
306
|
- spec/core_ext/hash/deep_transform_values_spec.rb
|
285
307
|
- spec/dummy/README.rdoc
|
286
308
|
- spec/dummy/Rakefile
|
@@ -382,6 +404,9 @@ files:
|
|
382
404
|
- spec/request/parallel_requests_spec.rb
|
383
405
|
- spec/request/params_encoding_spec.rb
|
384
406
|
- spec/request/request_without_rails_spec.rb
|
407
|
+
- spec/request/scrubbed_headers_spec.rb
|
408
|
+
- spec/request/scrubbed_options_spec.rb
|
409
|
+
- spec/request/scrubbed_params_spec.rb
|
385
410
|
- spec/request/url_patterns_spec.rb
|
386
411
|
- spec/request/user_agent_spec.rb
|
387
412
|
- spec/request/user_agent_without_rails_spec.rb
|
@@ -392,6 +417,7 @@ files:
|
|
392
417
|
- spec/response/effective_url_spec.rb
|
393
418
|
- spec/response/headers_spec.rb
|
394
419
|
- spec/response/options_spec.rb
|
420
|
+
- spec/response/scrubbed_options_spec.rb
|
395
421
|
- spec/response/success_spec.rb
|
396
422
|
- spec/response/time_spec.rb
|
397
423
|
- spec/spec_helper.rb
|
@@ -436,6 +462,7 @@ test_files:
|
|
436
462
|
- spec/basic_methods/request_without_rails_spec.rb
|
437
463
|
- spec/config/endpoints_spec.rb
|
438
464
|
- spec/config/placeholders_spec.rb
|
465
|
+
- spec/config/scrubs_spec.rb
|
439
466
|
- spec/core_ext/hash/deep_transform_values_spec.rb
|
440
467
|
- spec/dummy/README.rdoc
|
441
468
|
- spec/dummy/Rakefile
|
@@ -537,6 +564,9 @@ test_files:
|
|
537
564
|
- spec/request/parallel_requests_spec.rb
|
538
565
|
- spec/request/params_encoding_spec.rb
|
539
566
|
- spec/request/request_without_rails_spec.rb
|
567
|
+
- spec/request/scrubbed_headers_spec.rb
|
568
|
+
- spec/request/scrubbed_options_spec.rb
|
569
|
+
- spec/request/scrubbed_params_spec.rb
|
540
570
|
- spec/request/url_patterns_spec.rb
|
541
571
|
- spec/request/user_agent_spec.rb
|
542
572
|
- spec/request/user_agent_without_rails_spec.rb
|
@@ -547,6 +577,7 @@ test_files:
|
|
547
577
|
- spec/response/effective_url_spec.rb
|
548
578
|
- spec/response/headers_spec.rb
|
549
579
|
- spec/response/options_spec.rb
|
580
|
+
- spec/response/scrubbed_options_spec.rb
|
550
581
|
- spec/response/success_spec.rb
|
551
582
|
- spec/response/time_spec.rb
|
552
583
|
- spec/spec_helper.rb
|