mauth-client 6.4.3 → 7.1.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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -3
- data/.ruby-version +1 -1
- data/.travis.yml +3 -11
- data/Appraisals +1 -5
- data/CHANGELOG.md +15 -0
- data/Gemfile +16 -0
- data/README.md +81 -44
- data/Rakefile +20 -12
- data/UPGRADE_GUIDE.md +21 -0
- data/doc/mauth-client_CLI.md +1 -11
- data/examples/Gemfile +0 -1
- data/examples/README.md +14 -13
- data/examples/get_country_info.rb +44 -0
- data/exe/mauth-client +1 -23
- data/gemfiles/faraday_1.x.gemfile +17 -1
- data/gemfiles/faraday_2.x.gemfile +16 -0
- data/lib/mauth/client/{local_authenticator.rb → authenticator.rb} +124 -3
- data/lib/mauth/client/security_token_cacher.rb +20 -13
- data/lib/mauth/client.rb +21 -101
- data/lib/mauth/config_env.rb +81 -0
- data/lib/mauth/private_key_helper.rb +30 -0
- data/lib/mauth/version.rb +1 -1
- data/mauth-client.gemspec +5 -17
- metadata +30 -198
- data/.fossa.yml +0 -14
- data/doc/mauth.yml.md +0 -84
- data/examples/Gemfile.lock +0 -69
- data/examples/config.yml +0 -12
- data/examples/get_user_info.rb +0 -58
- data/gemfiles/faraday_0.x.gemfile +0 -7
- data/lib/mauth/client/authenticator_base.rb +0 -133
- data/lib/mauth/client/remote_authenticator.rb +0 -85
- data/lib/mauth/dice_bag/mauth.rb.dice +0 -12
- data/lib/mauth/dice_bag/mauth.yml.dice +0 -18
- data/lib/mauth/dice_bag/mauth_key.dice +0 -1
- data/lib/mauth/dice_bag/mauth_templates.rb +0 -21
@@ -1,133 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# methods common to RemoteRequestAuthenticator and LocalAuthenticator
|
4
|
-
|
5
|
-
module MAuth
|
6
|
-
class Client
|
7
|
-
module AuthenticatorBase
|
8
|
-
ALLOWED_DRIFT_SECONDS = 300
|
9
|
-
|
10
|
-
# takes an incoming request or response object, and returns whether
|
11
|
-
# the object is authentic according to its signature.
|
12
|
-
def authentic?(object)
|
13
|
-
log_authentication_request(object)
|
14
|
-
begin
|
15
|
-
authenticate!(object)
|
16
|
-
true
|
17
|
-
rescue InauthenticError, MAuthNotPresent, MissingV2Error
|
18
|
-
false
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# raises InauthenticError unless the given object is authentic. Will only
|
23
|
-
# authenticate with v2 if the environment variable V2_ONLY_AUTHENTICATE
|
24
|
-
# is set. Otherwise will fall back to v1 when v2 authentication fails
|
25
|
-
def authenticate!(object)
|
26
|
-
case object.protocol_version
|
27
|
-
when 2
|
28
|
-
begin
|
29
|
-
authenticate_v2!(object)
|
30
|
-
rescue InauthenticError => e
|
31
|
-
raise e if v2_only_authenticate?
|
32
|
-
raise e if disable_fallback_to_v1_on_v2_failure?
|
33
|
-
|
34
|
-
object.fall_back_to_mws_signature_info
|
35
|
-
raise e unless object.signature
|
36
|
-
|
37
|
-
log_authentication_request(object)
|
38
|
-
authenticate_v1!(object)
|
39
|
-
logger.warn('Completed successful authentication attempt after fallback to v1')
|
40
|
-
end
|
41
|
-
when 1
|
42
|
-
if v2_only_authenticate?
|
43
|
-
# If v2 is required but not present and v1 is present we raise MissingV2Error
|
44
|
-
msg = 'This service requires mAuth v2 mcc-authentication header but only v1 x-mws-authentication is present'
|
45
|
-
logger.error(msg)
|
46
|
-
raise MissingV2Error, msg
|
47
|
-
end
|
48
|
-
|
49
|
-
authenticate_v1!(object)
|
50
|
-
else
|
51
|
-
sub_str = v2_only_authenticate? ? '' : 'X-MWS-Authentication header is blank, '
|
52
|
-
msg = "Authentication Failed. No mAuth signature present; #{sub_str}MCC-Authentication header is blank."
|
53
|
-
logger.warn("mAuth signature not present on #{object.class}. Exception: #{msg}")
|
54
|
-
raise MAuthNotPresent, msg
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# NOTE: This log is likely consumed downstream and the contents SHOULD NOT
|
61
|
-
# be changed without a thorough review of downstream consumers.
|
62
|
-
def log_authentication_request(object)
|
63
|
-
object_app_uuid = object.signature_app_uuid || '[none provided]'
|
64
|
-
object_token = object.signature_token || '[none provided]'
|
65
|
-
logger.info(
|
66
|
-
'Mauth-client attempting to authenticate request from app with mauth' \
|
67
|
-
" app uuid #{object_app_uuid} to app with mauth app uuid #{client_app_uuid}" \
|
68
|
-
" using version #{object_token}."
|
69
|
-
)
|
70
|
-
end
|
71
|
-
|
72
|
-
def log_inauthentic(object, message)
|
73
|
-
logger.error("mAuth signature authentication failed for #{object.class}. Exception: #{message}")
|
74
|
-
end
|
75
|
-
|
76
|
-
def time_within_valid_range!(object, time_signed, now = Time.now)
|
77
|
-
return if (-ALLOWED_DRIFT_SECONDS..ALLOWED_DRIFT_SECONDS).cover?(now.to_i - time_signed)
|
78
|
-
|
79
|
-
msg = "Time verification failed. #{time_signed} not within #{ALLOWED_DRIFT_SECONDS} of #{now}"
|
80
|
-
log_inauthentic(object, msg)
|
81
|
-
raise InauthenticError, msg
|
82
|
-
end
|
83
|
-
|
84
|
-
# V1 helpers
|
85
|
-
def authenticate_v1!(object)
|
86
|
-
time_valid_v1!(object)
|
87
|
-
token_valid_v1!(object)
|
88
|
-
signature_valid_v1!(object)
|
89
|
-
end
|
90
|
-
|
91
|
-
def time_valid_v1!(object)
|
92
|
-
if object.x_mws_time.nil?
|
93
|
-
msg = 'Time verification failed. No x-mws-time present.'
|
94
|
-
log_inauthentic(object, msg)
|
95
|
-
raise InauthenticError, msg
|
96
|
-
end
|
97
|
-
time_within_valid_range!(object, object.x_mws_time.to_i)
|
98
|
-
end
|
99
|
-
|
100
|
-
def token_valid_v1!(object)
|
101
|
-
return if object.signature_token == MWS_TOKEN
|
102
|
-
|
103
|
-
msg = "Token verification failed. Expected #{MWS_TOKEN}; token was #{object.signature_token}"
|
104
|
-
log_inauthentic(object, msg)
|
105
|
-
raise InauthenticError, msg
|
106
|
-
end
|
107
|
-
|
108
|
-
# V2 helpers
|
109
|
-
def authenticate_v2!(object)
|
110
|
-
time_valid_v2!(object)
|
111
|
-
token_valid_v2!(object)
|
112
|
-
signature_valid_v2!(object)
|
113
|
-
end
|
114
|
-
|
115
|
-
def time_valid_v2!(object)
|
116
|
-
if object.mcc_time.nil?
|
117
|
-
msg = 'Time verification failed. No MCC-Time present.'
|
118
|
-
log_inauthentic(object, msg)
|
119
|
-
raise InauthenticError, msg
|
120
|
-
end
|
121
|
-
time_within_valid_range!(object, object.mcc_time.to_i)
|
122
|
-
end
|
123
|
-
|
124
|
-
def token_valid_v2!(object)
|
125
|
-
return if object.signature_token == MWSV2_TOKEN
|
126
|
-
|
127
|
-
msg = "Token verification failed. Expected #{MWSV2_TOKEN}; token was #{object.signature_token}"
|
128
|
-
log_inauthentic(object, msg)
|
129
|
-
raise InauthenticError, msg
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# methods for remotely authenticating a request by sending it to the mauth service
|
4
|
-
|
5
|
-
module MAuth
|
6
|
-
class Client
|
7
|
-
module RemoteRequestAuthenticator
|
8
|
-
private
|
9
|
-
|
10
|
-
# takes an incoming request object (no support for responses currently), and errors if the
|
11
|
-
# object is not authentic according to its signature
|
12
|
-
def signature_valid_v1!(object)
|
13
|
-
unless object.is_a?(MAuth::Request)
|
14
|
-
raise ArgumentError,
|
15
|
-
"Remote Authenticator can only authenticate requests; received #{object.inspect}"
|
16
|
-
end
|
17
|
-
|
18
|
-
authentication_ticket = {
|
19
|
-
'verb' => object.attributes_for_signing[:verb],
|
20
|
-
'app_uuid' => object.signature_app_uuid,
|
21
|
-
'client_signature' => object.signature,
|
22
|
-
'request_url' => object.attributes_for_signing[:request_url],
|
23
|
-
'request_time' => object.x_mws_time,
|
24
|
-
'b64encoded_body' => Base64.encode64(object.attributes_for_signing[:body] || '')
|
25
|
-
}
|
26
|
-
make_mauth_request(authentication_ticket)
|
27
|
-
end
|
28
|
-
|
29
|
-
def signature_valid_v2!(object)
|
30
|
-
unless object.is_a?(MAuth::Request)
|
31
|
-
msg = "Remote Authenticator can only authenticate requests; received #{object.inspect}"
|
32
|
-
raise ArgumentError, msg
|
33
|
-
end
|
34
|
-
|
35
|
-
authentication_ticket = {
|
36
|
-
verb: object.attributes_for_signing[:verb],
|
37
|
-
app_uuid: object.signature_app_uuid,
|
38
|
-
client_signature: object.signature,
|
39
|
-
request_url: object.attributes_for_signing[:request_url],
|
40
|
-
request_time: object.mcc_time,
|
41
|
-
b64encoded_body: Base64.encode64(object.attributes_for_signing[:body] || ''),
|
42
|
-
query_string: object.attributes_for_signing[:query_string],
|
43
|
-
token: object.signature_token
|
44
|
-
}
|
45
|
-
make_mauth_request(authentication_ticket)
|
46
|
-
end
|
47
|
-
|
48
|
-
def make_mauth_request(authentication_ticket)
|
49
|
-
begin
|
50
|
-
request_body = JSON.generate(authentication_ticket: authentication_ticket)
|
51
|
-
response = mauth_connection.post("/mauth/#{mauth_api_version}/authentication_tickets.json", request_body)
|
52
|
-
rescue ::Faraday::ConnectionFailed, ::Faraday::TimeoutError => e
|
53
|
-
msg = "mAuth service did not respond; received #{e.class}: #{e.message}"
|
54
|
-
logger.error("Unable to authenticate with MAuth. Exception #{msg}")
|
55
|
-
raise UnableToAuthenticateError, msg
|
56
|
-
end
|
57
|
-
case response.status
|
58
|
-
when 200..299
|
59
|
-
nil
|
60
|
-
when 412, 404
|
61
|
-
# the mAuth service responds with 412 when the given request is not authentically signed.
|
62
|
-
# older versions of the mAuth service respond with 404 when the given app_uuid
|
63
|
-
# does not exist, which is also considered to not be authentically signed. newer
|
64
|
-
# versions of the service respond 412 in all cases, so the 404 check may be removed
|
65
|
-
# when the old version of the mAuth service is out of service.
|
66
|
-
raise InauthenticError, "The mAuth service responded with #{response.status}: #{response.body}"
|
67
|
-
else
|
68
|
-
mauth_service_response_error(response)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def mauth_connection
|
73
|
-
@mauth_connection ||= begin
|
74
|
-
require 'faraday'
|
75
|
-
|
76
|
-
::Faraday.new(mauth_baseurl,
|
77
|
-
faraday_options.merge(headers: { 'Content-Type' => 'application/json' })) do |builder|
|
78
|
-
builder.use MAuth::Faraday::MAuthClientUserAgent
|
79
|
-
builder.adapter ::Faraday.default_adapter
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
<%= warning.as_yaml_comment %>
|
2
|
-
|
3
|
-
MAUTH_CONF = MAuth::Client.default_config
|
4
|
-
require 'mauth/rack'
|
5
|
-
# ResponseSigner OPTIONAL; only use if you are registered in mauth service
|
6
|
-
Rails.application.config.middleware.insert_after Rack::Runtime, MAuth::Rack::ResponseSigner, MAUTH_CONF
|
7
|
-
if Rails.env.test? || Rails.env.development?
|
8
|
-
require 'mauth/fake/rack'
|
9
|
-
Rails.application.config.middleware.insert_after MAuth::Rack::ResponseSigner, MAuth::Rack::RequestAuthenticationFaker, MAUTH_CONF
|
10
|
-
else
|
11
|
-
Rails.application.config.middleware.insert_after MAuth::Rack::ResponseSigner, MAuth::Rack::RequestAuthenticatorNoAppStatus, MAUTH_CONF
|
12
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
<%= warning.as_yaml_comment %>
|
2
|
-
|
3
|
-
common: &common
|
4
|
-
mauth_baseurl: <%= configured.mauth_url! || 'http://localhost:7000' %>
|
5
|
-
mauth_api_version: v1
|
6
|
-
app_uuid: <%= configured.mauth_app_uuid! || 'fb17460e-9868-11e1-8399-0090f5ccb4d3' %>
|
7
|
-
private_key_file: config/mauth_key
|
8
|
-
v2_only_authenticate: <%= configured.v2_only_authenticate || 'false' %>
|
9
|
-
v2_only_sign_requests: <%= configured.v2_only_sign_requests || 'false' %>
|
10
|
-
disable_fallback_to_v1_on_v2_failure: <%= configured.disable_fallback_to_v1_on_v2_failure || 'false' %>
|
11
|
-
v1_only_sign_requests: <%= configured.v1_only_sign_requests || 'true' %>
|
12
|
-
|
13
|
-
production:
|
14
|
-
<<: *common
|
15
|
-
development:
|
16
|
-
<<: *common
|
17
|
-
test:
|
18
|
-
<<: *common
|
@@ -1 +0,0 @@
|
|
1
|
-
<%= ensure_is_private_key(configured.mauth_private_key! || generate_private_key.to_s) %>
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dice_bag'
|
4
|
-
|
5
|
-
class MauthTemplate < DiceBag::AvailableTemplates
|
6
|
-
def templates
|
7
|
-
['mauth.yml.dice', 'mauth_key.dice'].map do |template|
|
8
|
-
File.join(File.dirname(__FILE__), template)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class MauthInitializerTemplate < DiceBag::AvailableTemplates
|
14
|
-
def templates_location
|
15
|
-
'config/initializers'
|
16
|
-
end
|
17
|
-
|
18
|
-
def templates
|
19
|
-
[File.join(File.dirname(__FILE__), 'mauth.rb.dice')] if Object.const_defined?(:Rails)
|
20
|
-
end
|
21
|
-
end
|