Class: ShippingEasy::Authenticator

Inherits:
Object
  • Object
show all
Defined in:
lib/shipping_easy/authenticator.rb

Overview

Authenticates a signed ShippingEasy API request by matching the supplied signature with a freshly calculated one using the API shared secret. Requests may not be more than 10 minutes old in order to prevent playback attacks.

Constant Summary collapse

EXPIRATION_INTERVAL =
10 * 60

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Authenticator

Creates a new API authenticator object.

options - The Hash options used to authenticate the request:

:api_secret - A ShippingEasy-supplied API secret
:method - The HTTP method used in the request. Either :get or :post. Default is :get.
:path - The URI path of the request. E.g. "/api/orders"
:params - The query params passed in as part of the request.
:body - The body of the request which should normally be a JSON payload.


26
27
28
29
30
31
32
33
34
35
# File 'lib/shipping_easy/authenticator.rb', line 26

def initialize(options = {})
  @api_secret = options.fetch(:api_secret, ShippingEasy.api_secret)
  @method = options.fetch(:method, :get)
  @path = options.fetch(:path)
  @body = options.fetch(:body, nil)
  @params = options.fetch(:params, {})
  @api_signature = params.delete(:api_signature)
  @api_timestamp = params.fetch(:api_timestamp, nil).to_i
  @expected_signature = ShippingEasy::Signature.new(api_secret: @api_secret, method: @method, path: @path, params: @params, body: @body)
end

Instance Attribute Details

#api_secretObject (readonly)

Returns the value of attribute api_secret.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def api_secret
  @api_secret
end

#api_signatureObject (readonly)

Returns the value of attribute api_signature.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def api_signature
  @api_signature
end

#api_timestampObject (readonly)

Returns the value of attribute api_timestamp.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def api_timestamp
  @api_timestamp
end

#bodyObject (readonly)

Returns the value of attribute body.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def body
  @body
end

#expected_signatureObject (readonly)

Returns the value of attribute expected_signature.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def expected_signature
  @expected_signature
end

#methodObject (readonly)

Returns the value of attribute method.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def method
  @method
end

#paramsObject (readonly)

Returns the value of attribute params.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def params
  @params
end

#pathObject (readonly)

Returns the value of attribute path.



9
10
11
# File 'lib/shipping_easy/authenticator.rb', line 9

def path
  @path
end

Class Method Details

.authenticate(options = {}) ⇒ Object

Convenience method to instantiate an authenticator and authenticate a signed request.

options - The Hash options used to authenticate the request:

:api_secret - A ShippingEasy-supplied API secret
:method - The HTTP method used in the request. Either :get or :post. Default is :get.
:path - The URI path of the request. E.g. "/api/orders"
:params - The query params passed in as part of the request.
:body - The body of the request which should normally be a JSON payload.

See #authenticate for more detail.



47
48
49
# File 'lib/shipping_easy/authenticator.rb', line 47

def self.authenticate(options = {})
  new(options).authenticate
end

Instance Method Details

#authenticateObject

Authenticates the signed request.

Example:

authenticator = ShippingEasyShippingEasy::Authenticator.new(api_secret: “XXX”,

method: :post,
path: "/api/orders",
params: { test_param: "ABCDE", api_key: "123", api_timestamp: "2014-01-03 10:41:21 -0600" },
body: "{\"orders\":{\"name\":\"Flip flops\",\"cost\":\"10.00\",\"shipping_cost\":\"2.00\"}}")

Throws ShippingEasyShippingEasy::RequestExpiredError if the API timestamp is expired. Throws ShippingEasyShippingEasy::AccessDeniedError if the signature cannot be verified. Throws ShippingEasyShippingEasy::TimestampFormatError if the timestamp format is invalid

Returns true if authentication passes.



66
67
68
69
70
# File 'lib/shipping_easy/authenticator.rb', line 66

def authenticate
  raise ShippingEasy::RequestExpiredError if request_expired?
  raise ShippingEasy::AccessDeniedError unless signatures_match?
  true
end

#parsed_timestampObject

Parses the supplied API timestamp string into a Time object.

Raises ShippingEasyShippingEasy::TimestampFormatError if the string cannot be converted into a Time object. Returns a Time object.



93
94
95
96
97
98
# File 'lib/shipping_easy/authenticator.rb', line 93

def parsed_timestamp
  raise ArgumentError if api_timestamp == 0
  Time.at(api_timestamp)
rescue ArgumentError, TypeError
  raise ShippingEasy::TimestampFormatError
end

#request_expired?Boolean

Returns true if the supplied API timestamp has expired.

Returns:

  • (Boolean)


78
79
80
# File 'lib/shipping_easy/authenticator.rb', line 78

def request_expired?
  parsed_timestamp < request_expires_at
end

#request_expires_atObject

Returns the time that the request expires, given the supplied API timestamp.

Returns a Time object.



85
86
87
# File 'lib/shipping_easy/authenticator.rb', line 85

def request_expires_at
  Time.now - EXPIRATION_INTERVAL
end

#signatures_match?Boolean

Returns true if the signature included in the request matches our calculated signature.

Returns:

  • (Boolean)


73
74
75
# File 'lib/shipping_easy/authenticator.rb', line 73

def signatures_match?
  expected_signature == api_signature
end