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.
@@ -4,14 +4,135 @@ require 'mauth/client/security_token_cacher'
4
4
  require 'mauth/client/signer'
5
5
  require 'openssl'
6
6
 
7
- # methods to verify the authenticity of signed requests and responses locally, retrieving
8
- # public keys from the mAuth service as needed
7
+ # methods to verify the authenticity of signed requests and responses
9
8
 
10
9
  module MAuth
11
10
  class Client
12
- module LocalAuthenticator
11
+ module Authenticator
12
+ ALLOWED_DRIFT_SECONDS = 300
13
+
14
+ # takes an incoming request or response object, and returns whether
15
+ # the object is authentic according to its signature.
16
+ def authentic?(object)
17
+ log_authentication_request(object)
18
+ begin
19
+ authenticate!(object)
20
+ true
21
+ rescue InauthenticError, MAuthNotPresent, MissingV2Error
22
+ false
23
+ end
24
+ end
25
+
26
+ # raises InauthenticError unless the given object is authentic. Will only
27
+ # authenticate with v2 if the environment variable V2_ONLY_AUTHENTICATE
28
+ # is set. Otherwise will fall back to v1 when v2 authentication fails
29
+ def authenticate!(object)
30
+ case object.protocol_version
31
+ when 2
32
+ begin
33
+ authenticate_v2!(object)
34
+ rescue InauthenticError => e
35
+ raise e if v2_only_authenticate?
36
+ raise e if disable_fallback_to_v1_on_v2_failure?
37
+
38
+ object.fall_back_to_mws_signature_info
39
+ raise e unless object.signature
40
+
41
+ log_authentication_request(object)
42
+ authenticate_v1!(object)
43
+ logger.warn('Completed successful authentication attempt after fallback to v1')
44
+ end
45
+ when 1
46
+ if v2_only_authenticate?
47
+ # If v2 is required but not present and v1 is present we raise MissingV2Error
48
+ msg = 'This service requires mAuth v2 mcc-authentication header but only v1 x-mws-authentication is present'
49
+ logger.error(msg)
50
+ raise MissingV2Error, msg
51
+ end
52
+
53
+ authenticate_v1!(object)
54
+ else
55
+ sub_str = v2_only_authenticate? ? '' : 'X-MWS-Authentication header is blank, '
56
+ msg = "Authentication Failed. No mAuth signature present; #{sub_str}MCC-Authentication header is blank."
57
+ logger.warn("mAuth signature not present on #{object.class}. Exception: #{msg}")
58
+ raise MAuthNotPresent, msg
59
+ end
60
+ end
61
+
13
62
  private
14
63
 
64
+ # NOTE: This log is likely consumed downstream and the contents SHOULD NOT
65
+ # be changed without a thorough review of downstream consumers.
66
+ def log_authentication_request(object)
67
+ object_app_uuid = object.signature_app_uuid || '[none provided]'
68
+ object_token = object.signature_token || '[none provided]'
69
+ logger.info(
70
+ 'Mauth-client attempting to authenticate request from app with mauth ' \
71
+ "app uuid #{object_app_uuid} to app with mauth app uuid #{client_app_uuid} " \
72
+ "using version #{object_token}."
73
+ )
74
+ end
75
+
76
+ def log_inauthentic(object, message)
77
+ logger.error("mAuth signature authentication failed for #{object.class}. Exception: #{message}")
78
+ end
79
+
80
+ def time_within_valid_range!(object, time_signed, now = Time.now)
81
+ return if (-ALLOWED_DRIFT_SECONDS..ALLOWED_DRIFT_SECONDS).cover?(now.to_i - time_signed)
82
+
83
+ msg = "Time verification failed. #{time_signed} not within #{ALLOWED_DRIFT_SECONDS} of #{now}"
84
+ log_inauthentic(object, msg)
85
+ raise InauthenticError, msg
86
+ end
87
+
88
+ # V1 helpers
89
+ def authenticate_v1!(object)
90
+ time_valid_v1!(object)
91
+ token_valid_v1!(object)
92
+ signature_valid_v1!(object)
93
+ end
94
+
95
+ def time_valid_v1!(object)
96
+ if object.x_mws_time.nil?
97
+ msg = 'Time verification failed. No x-mws-time present.'
98
+ log_inauthentic(object, msg)
99
+ raise InauthenticError, msg
100
+ end
101
+ time_within_valid_range!(object, object.x_mws_time.to_i)
102
+ end
103
+
104
+ def token_valid_v1!(object)
105
+ return if object.signature_token == MWS_TOKEN
106
+
107
+ msg = "Token verification failed. Expected #{MWS_TOKEN}; token was #{object.signature_token}"
108
+ log_inauthentic(object, msg)
109
+ raise InauthenticError, msg
110
+ end
111
+
112
+ # V2 helpers
113
+ def authenticate_v2!(object)
114
+ time_valid_v2!(object)
115
+ token_valid_v2!(object)
116
+ signature_valid_v2!(object)
117
+ end
118
+
119
+ def time_valid_v2!(object)
120
+ if object.mcc_time.nil?
121
+ msg = 'Time verification failed. No MCC-Time present.'
122
+ log_inauthentic(object, msg)
123
+ raise InauthenticError, msg
124
+ end
125
+ time_within_valid_range!(object, object.mcc_time.to_i)
126
+ end
127
+
128
+ def token_valid_v2!(object)
129
+ return if object.signature_token == MWSV2_TOKEN
130
+
131
+ msg = "Token verification failed. Expected #{MWSV2_TOKEN}; token was #{object.signature_token}"
132
+ log_inauthentic(object, msg)
133
+ raise InauthenticError, msg
134
+ end
135
+
15
136
  def signature_valid_v1!(object)
16
137
  # We are in an unfortunate situation in which Euresource is percent-encoding parts of paths, but not
17
138
  # all of them. In particular, Euresource is percent-encoding all special characters save for '/'.
@@ -1,16 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'faraday-http-cache'
4
+ require 'faraday/retry'
5
+ if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.0')
6
+ require 'faraday/net_http_persistent'
7
+ else
8
+ require 'net/http/persistent'
9
+ end
4
10
  require 'mauth/faraday'
5
11
 
6
12
  module MAuth
7
13
  class Client
8
- module LocalAuthenticator
14
+ module Authenticator
9
15
  class SecurityTokenCacher
16
+ attr_reader :mauth_client
17
+
10
18
  def initialize(mauth_client)
11
19
  @mauth_client = mauth_client
12
20
  # TODO: should this be UnableToSignError?
13
- @mauth_client.assert_private_key(
21
+ mauth_client.assert_private_key(
14
22
  UnableToAuthenticateError.new('Cannot fetch public keys from mAuth service without a private key!')
15
23
  )
16
24
  end
@@ -19,7 +27,7 @@ module MAuth
19
27
  # url-encode the app_uuid to prevent trickery like escaping upward with ../../ in a malicious
20
28
  # app_uuid - probably not exploitable, but this is the right way to do it anyway.
21
29
  url_encoded_app_uuid = CGI.escape(app_uuid)
22
- path = "/mauth/#{@mauth_client.mauth_api_version}/security_tokens/#{url_encoded_app_uuid}.json"
30
+ path = "/mauth/#{mauth_client.mauth_api_version}/security_tokens/#{url_encoded_app_uuid}.json"
23
31
  response = signed_mauth_connection.get(path)
24
32
 
25
33
  case response.status
@@ -29,11 +37,11 @@ module MAuth
29
37
  # signing with a key mAuth doesn't know about is considered inauthentic
30
38
  raise InauthenticError, "mAuth service responded with 404 looking up public key for #{app_uuid}"
31
39
  else
32
- @mauth_client.send(:mauth_service_response_error, response)
40
+ mauth_client.send(:mauth_service_response_error, response)
33
41
  end
34
42
  rescue ::Faraday::ConnectionFailed, ::Faraday::TimeoutError => e
35
43
  msg = "mAuth service did not respond; received #{e.class}: #{e.message}"
36
- @mauth_client.logger.error("Unable to authenticate with MAuth. Exception #{msg}")
44
+ mauth_client.logger.error("Unable to authenticate with MAuth. Exception #{msg}")
37
45
  raise UnableToAuthenticateError, msg
38
46
  end
39
47
 
@@ -43,21 +51,20 @@ module MAuth
43
51
  JSON.parse response_body
44
52
  rescue JSON::ParserError => e
45
53
  msg = "mAuth service responded with unparseable json: #{response_body}\n#{e.class}: #{e.message}"
46
- @mauth_client.logger.error("Unable to authenticate with MAuth. Exception #{msg}")
54
+ mauth_client.logger.error("Unable to authenticate with MAuth. Exception #{msg}")
47
55
  raise UnableToAuthenticateError, msg
48
56
  end
49
57
 
50
58
  def signed_mauth_connection
51
59
  @signed_mauth_connection ||= begin
52
- if @mauth_client.ssl_certs_path
53
- @mauth_client.faraday_options[:ssl] = { ca_path: @mauth_client.ssl_certs_path }
54
- end
60
+ mauth_client.faraday_options[:ssl] = { ca_path: mauth_client.ssl_certs_path } if mauth_client.ssl_certs_path
55
61
 
56
- ::Faraday.new(@mauth_client.mauth_baseurl, @mauth_client.faraday_options) do |builder|
62
+ ::Faraday.new(mauth_client.mauth_baseurl, mauth_client.faraday_options) do |builder|
57
63
  builder.use MAuth::Faraday::MAuthClientUserAgent
58
- builder.use MAuth::Faraday::RequestSigner, 'mauth_client' => @mauth_client
59
- builder.use :http_cache, logger: MAuth::Client.new.logger, shared_cache: false
60
- builder.adapter ::Faraday.default_adapter
64
+ builder.use MAuth::Faraday::RequestSigner, 'mauth_client' => mauth_client
65
+ builder.use :http_cache, store: mauth_client.cache_store, logger: mauth_client.logger, shared_cache: false
66
+ builder.request :retry, max: 2
67
+ builder.adapter :net_http_persistent
61
68
  end
62
69
  end
63
70
  end
data/lib/mauth/client.rb CHANGED
@@ -7,13 +7,12 @@ require 'json'
7
7
  require 'yaml'
8
8
  require 'mauth/core_ext'
9
9
  require 'mauth/autoload'
10
- require 'mauth/dice_bag/mauth_templates'
11
10
  require 'mauth/version'
12
- require 'mauth/client/authenticator_base'
13
- require 'mauth/client/local_authenticator'
14
- require 'mauth/client/remote_authenticator'
11
+ require 'mauth/client/authenticator'
15
12
  require 'mauth/client/signer'
13
+ require 'mauth/config_env'
16
14
  require 'mauth/errors'
15
+ require 'mauth/private_key_helper'
17
16
 
18
17
  module MAuth
19
18
  # does operations which require a private key and corresponding app uuid. this is primarily:
@@ -31,66 +30,22 @@ module MAuth
31
30
  AUTH_HEADER_DELIMITER = ';'
32
31
  RACK_ENV_APP_UUID_KEY = 'mauth.app_uuid'
33
32
 
34
- include AuthenticatorBase
33
+ include Authenticator
35
34
  include Signer
36
35
 
37
36
  # returns a configuration (to be passed to MAuth::Client.new) which is configured from information stored in
38
37
  # standard places. all of which is overridable by options in case some defaults do not apply.
39
38
  #
40
39
  # options (may be symbols or strings) - any or all may be omitted where your usage conforms to the defaults.
41
- # - root: the path relative to which this method looks for configuration yaml files. defaults to Rails.root
42
- # if ::Rails is defined, otherwise ENV['RAILS_ROOT'], ENV['RACK_ROOT'], ENV['APP_ROOT'], or '.'
43
- # - environment: the environment, pertaining to top-level keys of the configuration yaml files. by default,
44
- # tries Rails.environment, ENV['RAILS_ENV'], and ENV['RACK_ENV'], and falls back to 'development' if none
45
- # of these are set.
46
- # - mauth_config - MAuth configuration. defaults to load this from a yaml file (see mauth_config_yml option)
47
- # which is assumed to be keyed with the environment at the root. if this is specified, no yaml file is
48
- # loaded, and the given config is passed through with any other defaults applied. at the moment, the only
49
- # other default is to set the logger.
50
- # - mauth_config_yml - specifies where a mauth configuration yaml file can be found. by default checks
51
- # ENV['MAUTH_CONFIG_YML'] or a file 'config/mauth.yml' relative to the root.
40
+ # - mauth_config - MAuth configuration. defaults to load this from environment variables. if this is specified,
41
+ # no environment variable is loaded, and the given config is passed through with any other defaults applied.
42
+ # at the moment, the only other default is to set the logger.
52
43
  # - logger - by default checks ::Rails.logger
53
44
  def self.default_config(options = {})
54
45
  options = options.stringify_symbol_keys
55
46
 
56
- # find the app_root (relative to which we look for yaml files). note that this
57
- # is different than MAuth::Client.root, the root of the mauth-client library.
58
- app_root = options['root'] || begin
59
- if Object.const_defined?(:Rails) && ::Rails.respond_to?(:root) && ::Rails.root
60
- Rails.root
61
- else
62
- ENV['RAILS_ROOT'] || ENV['RACK_ROOT'] || ENV['APP_ROOT'] || '.'
63
- end
64
- end
65
-
66
- # find the environment (with which yaml files are keyed)
67
- env = options['environment'] || begin
68
- if Object.const_defined?(:Rails) && ::Rails.respond_to?(:environment)
69
- Rails.environment
70
- else
71
- ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
72
- end
73
- end
74
-
75
- # find mauth config, given on options, or in a file at
76
- # ENV['MAUTH_CONFIG_YML'] or config/mauth.yml in the app_root
77
- mauth_config = options['mauth_config'] || begin
78
- mauth_config_yml = options['mauth_config_yml']
79
- mauth_config_yml ||= ENV['MAUTH_CONFIG_YML']
80
- default_loc = 'config/mauth.yml'
81
- default_yml = File.join(app_root, default_loc)
82
- mauth_config_yml ||= default_yml if File.exist?(default_yml)
83
- if mauth_config_yml && File.exist?(mauth_config_yml)
84
- whole_config = ConfigFile.load(mauth_config_yml)
85
- errmessage = "#{mauth_config_yml} config has no key #{env} - it has keys #{whole_config.keys.inspect}"
86
- whole_config[env] || raise(MAuth::Client::ConfigurationError, errmessage)
87
- else
88
- raise MAuth::Client::ConfigurationError,
89
- 'could not find mauth config yaml file. this file may be ' \
90
- "placed in #{default_loc}, specified with the mauth_config_yml option, or specified with the " \
91
- 'MAUTH_CONFIG_YML environment variable.'
92
- end
93
- end
47
+ # find mauth config
48
+ mauth_config = options['mauth_config'] || ConfigEnv.load
94
49
 
95
50
  unless mauth_config.key?('logger')
96
51
  # the logger. Rails.logger if it exists, otherwise, no logger
@@ -106,18 +61,13 @@ module MAuth
106
61
 
107
62
  # new client with the given App UUID and public key. config may include the following (all
108
63
  # config keys may be strings or symbols):
109
- # - private_key - required for signing and for authenticating responses. may be omitted if
110
- # only remote authentication of requests is being performed (with
111
- # MAuth::Rack::RequestAuthenticator). may be given as a string or a OpenSSL::PKey::RSA
112
- # instance.
64
+ # - private_key - required for signing and for authentication.
65
+ # may be given as a string or a OpenSSL::PKey::RSA instance.
113
66
  # - app_uuid - required in the same circumstances where a private_key is required
114
- # - mauth_baseurl - required. needed for local authentication to retrieve public keys; needed
115
- # for remote authentication for hopefully obvious reasons.
67
+ # - mauth_baseurl - required. needed to retrieve public keys.
116
68
  # - mauth_api_version - required. only 'v1' exists / is supported as of this writing.
117
69
  # - logger - a Logger to which any useful information will be written. if this is omitted and
118
70
  # Rails.logger exists, that will be used.
119
- # - authenticator - this pretty much never needs to be specified. LocalAuthenticator or
120
- # RemoteRequestAuthenticator will be used as appropriate.
121
71
  def initialize(config = {})
122
72
  # stringify symbol keys
123
73
  given_config = config.stringify_symbol_keys
@@ -131,7 +81,7 @@ module MAuth
131
81
  when nil
132
82
  nil
133
83
  when String
134
- OpenSSL::PKey::RSA.new(given_config['private_key'])
84
+ PrivateKeyHelper.load(given_config['private_key'])
135
85
  when OpenSSL::PKey::RSA
136
86
  given_config['private_key']
137
87
  else
@@ -153,31 +103,20 @@ module MAuth
153
103
  end
154
104
  end
155
105
 
156
- request_config = { timeout: 10, open_timeout: 10 }
106
+ request_config = { timeout: 10, open_timeout: 3 }
157
107
  request_config.merge!(symbolize_keys(given_config['faraday_options'])) if given_config['faraday_options']
158
108
  @config['faraday_options'] = { request: request_config } || {}
159
109
  @config['ssl_certs_path'] = given_config['ssl_certs_path'] if given_config['ssl_certs_path']
160
110
  @config['v2_only_authenticate'] = given_config['v2_only_authenticate'].to_s.casecmp('true').zero?
161
111
  @config['v2_only_sign_requests'] = given_config['v2_only_sign_requests'].to_s.casecmp('true').zero?
162
- @config['disable_fallback_to_v1_on_v2_failure'] =
163
- given_config['disable_fallback_to_v1_on_v2_failure'].to_s.casecmp('true').zero?
164
112
  @config['v1_only_sign_requests'] = given_config['v1_only_sign_requests'].to_s.casecmp('true').zero?
165
-
166
113
  if @config['v2_only_sign_requests'] && @config['v1_only_sign_requests']
167
114
  raise MAuth::Client::ConfigurationError, 'v2_only_sign_requests and v1_only_sign_requests may not both be true'
168
115
  end
169
116
 
170
- # if 'authenticator' was given, don't override that - including if it was given as nil / false
171
- if given_config.key?('authenticator')
172
- @config['authenticator'] = given_config['authenticator']
173
- elsif client_app_uuid && private_key
174
- @config['authenticator'] = LocalAuthenticator
175
- # MAuth::Client can authenticate locally if it's provided a client_app_uuid and private_key
176
- else
177
- # otherwise, it will authenticate remotely (requests only)
178
- @config['authenticator'] = RemoteRequestAuthenticator
179
- end
180
- extend @config['authenticator'] if @config['authenticator']
117
+ @config['disable_fallback_to_v1_on_v2_failure'] =
118
+ given_config['disable_fallback_to_v1_on_v2_failure'].to_s.casecmp('true').zero?
119
+ @config['use_rails_cache'] = given_config['use_rails_cache']
181
120
  end
182
121
 
183
122
  def logger
@@ -228,6 +167,10 @@ module MAuth
228
167
  raise err unless private_key
229
168
  end
230
169
 
170
+ def cache_store
171
+ Rails.cache if @config['use_rails_cache'] && Object.const_defined?(:Rails) && ::Rails.respond_to?(:cache)
172
+ end
173
+
231
174
  private
232
175
 
233
176
  def mauth_service_response_error(response)
@@ -246,27 +189,4 @@ module MAuth
246
189
  hash
247
190
  end
248
191
  end
249
-
250
- module ConfigFile
251
- GITHUB_URL = 'https://github.com/mdsol/mauth-client-ruby'
252
- @config = {}
253
-
254
- def self.load(path)
255
- unless File.exist?(path)
256
- raise "File #{path} not found. Please visit #{GITHUB_URL} for details."
257
- end
258
-
259
- @config[path] ||= yaml_safe_load_file(path)
260
- unless @config[path]
261
- raise "File #{path} does not contain proper YAML information. Visit #{GITHUB_URL} for details."
262
- end
263
-
264
- @config[path]
265
- end
266
-
267
- def self.yaml_safe_load_file(path)
268
- yml_data = File.read(path)
269
- YAML.safe_load(yml_data, aliases: true)
270
- end
271
- end
272
192
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MAuth
4
+ class ConfigEnv
5
+ GITHUB_URL = 'https://github.com/mdsol/mauth-client-ruby'
6
+
7
+ ENV_STUFF = {
8
+ 'MAUTH_URL' => nil,
9
+ 'MAUTH_API_VERSION' => 'v1',
10
+ 'MAUTH_APP_UUID' => nil,
11
+ 'MAUTH_PRIVATE_KEY' => nil,
12
+ 'MAUTH_PRIVATE_KEY_FILE' => 'config/mauth_key',
13
+ 'MAUTH_V2_ONLY_AUTHENTICATE' => false,
14
+ 'MAUTH_V2_ONLY_SIGN_REQUESTS' => false,
15
+ 'MAUTH_DISABLE_FALLBACK_TO_V1_ON_V2_FAILURE' => false,
16
+ 'MAUTH_V1_ONLY_SIGN_REQUESTS' => true,
17
+ 'MAUTH_USE_RAILS_CACHE' => false
18
+ }.freeze
19
+
20
+ class << self
21
+ def load
22
+ validate! if production?
23
+
24
+ {
25
+ 'mauth_baseurl' => env[:mauth_url] || 'http://localhost:7000',
26
+ 'mauth_api_version' => env[:mauth_api_version],
27
+ 'app_uuid' => env[:mauth_app_uuid] || 'fb17460e-9868-11e1-8399-0090f5ccb4d3',
28
+ 'private_key' => private_key || PrivateKeyHelper.generate.to_s,
29
+ 'v2_only_authenticate' => env[:mauth_v2_only_authenticate],
30
+ 'v2_only_sign_requests' => env[:mauth_v2_only_sign_requests],
31
+ 'disable_fallback_to_v1_on_v2_failure' => env[:mauth_disable_fallback_to_v1_on_v2_failure],
32
+ 'v1_only_sign_requests' => env[:mauth_v1_only_sign_requests],
33
+ 'use_rails_cache' => env[:mauth_use_rails_cache]
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ def validate!
40
+ errors = []
41
+ errors << 'The MAUTH_URL environment variable must be set' if env[:mauth_url].nil?
42
+ errors << 'The MAUTH_APP_UUID environment variable must be set' if env[:mauth_app_uuid].nil?
43
+ errors << 'The MAUTH_PRIVATE_KEY environment variable must be set' if env[:mauth_private_key].nil?
44
+ return if errors.empty?
45
+
46
+ errors.map! { |err| "#{err} => See #{GITHUB_URL}" }
47
+ errors.unshift('Invalid MAuth Client configuration:')
48
+ raise errors.join("\n")
49
+ end
50
+
51
+ def env
52
+ @env ||= ENV_STUFF.each_with_object({}) do |(key, default), hsh|
53
+ env_key = key.downcase.to_sym
54
+ hsh[env_key] = ENV.fetch(key, default)
55
+
56
+ case default
57
+ when TrueClass, FalseClass
58
+ hsh[env_key] = hsh[env_key].to_s.casecmp('true').zero?
59
+ end
60
+ end
61
+ end
62
+
63
+ def production?
64
+ environment.to_s.casecmp('production').zero?
65
+ end
66
+
67
+ def environment
68
+ return Rails.environment if Object.const_defined?(:Rails) && ::Rails.respond_to?(:environment)
69
+
70
+ ENV.fetch('RAILS_ENV') { ENV.fetch('RACK_ENV', 'development') }
71
+ end
72
+
73
+ def private_key
74
+ return env[:mauth_private_key] if env[:mauth_private_key]
75
+ return nil unless env[:mauth_private_key_file] && File.readable?(env[:mauth_private_key_file])
76
+
77
+ File.read(env[:mauth_private_key_file])
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module MAuth
6
+ module PrivateKeyHelper
7
+ HEADER = '-----BEGIN RSA PRIVATE KEY-----'
8
+ FOOTER = '-----END RSA PRIVATE KEY-----'
9
+
10
+ module_function
11
+
12
+ def generate
13
+ OpenSSL::PKey::RSA.generate(2048)
14
+ end
15
+
16
+ def load(key)
17
+ OpenSSL::PKey::RSA.new(to_rsa_format(key))
18
+ rescue OpenSSL::PKey::RSAError
19
+ raise 'The private key provided is invalid'
20
+ end
21
+
22
+ def to_rsa_format(key)
23
+ return key if key.include?("\n")
24
+
25
+ body = key.strip.delete_prefix(HEADER).delete_suffix(FOOTER).strip
26
+ body = body.include?("\s") ? body.tr("\s", "\n") : body.scan(/.{1,64}/).join("\n")
27
+ "#{HEADER}\n#{body}\n#{FOOTER}"
28
+ end
29
+ end
30
+ end
data/lib/mauth/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MAuth
4
- VERSION = '6.4.3'
4
+ VERSION = '7.1.0'
5
5
  end
data/mauth-client.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  'Includes middleware for Rack and Faraday for incoming and outgoing requests and responses.'
15
15
  spec.homepage = 'https://github.com/mdsol/mauth-client-ruby'
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '>= 2.6.0'
17
+ spec.required_ruby_version = '>= 2.7.0'
18
18
 
19
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
20
  spec.bindir = 'exe'
@@ -23,23 +23,11 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'addressable', '~> 2.0'
25
25
  spec.add_dependency 'coderay', '~> 1.0'
26
- spec.add_dependency 'dice_bag', '>= 0.9', '< 2.0'
27
- spec.add_dependency 'faraday', '>= 0.9', '< 3.0'
26
+ spec.add_dependency 'faraday', '>= 1.9', '< 3.0'
28
27
  spec.add_dependency 'faraday-http-cache', '>= 2.0', '< 3.0'
28
+ spec.add_dependency 'faraday-net_http_persistent'
29
+ spec.add_dependency 'faraday-retry'
30
+ spec.add_dependency 'net-http-persistent', '>= 3.1'
29
31
  spec.add_dependency 'rack', '> 2.2.3'
30
32
  spec.add_dependency 'term-ansicolor', '~> 1.0'
31
-
32
- spec.add_development_dependency 'appraisal'
33
- spec.add_development_dependency 'benchmark-ips', '~> 2.7'
34
- spec.add_development_dependency 'bundler', '>= 1.17'
35
- spec.add_development_dependency 'byebug'
36
- spec.add_development_dependency 'rack-test', '~> 1.1.0'
37
- spec.add_development_dependency 'rake', '~> 12.0'
38
- spec.add_development_dependency 'rspec', '~> 3.8'
39
- spec.add_development_dependency 'rubocop', '= 1.25.1'
40
- spec.add_development_dependency 'rubocop-mdsol', '~> 0.1'
41
- spec.add_development_dependency 'rubocop-performance', '= 1.13.2'
42
- spec.add_development_dependency 'simplecov', '~> 0.16'
43
- spec.add_development_dependency 'timecop', '~> 0.9'
44
- spec.add_development_dependency 'webmock', '~> 3.0'
45
33
  end