class Ingenico::Connect::SDK::DefaultImpl::DefaultAuthenticator

Authenticates requests made to the Ingenico ePayments platform using the HMAC algorithm.

Constants

CONTENT_TYPE
DATE
HMAC_ALGOR

HMAC algorithm used to generate the signature

XGCS

Public Class Methods

new(authorization_type, api_key_id, secret_api_key) click to toggle source

Construct a new DefaultAuthenticator instance that can sign requests with the provided api_key_id and secret_api_key.

@param authorization_type [String] the authorization protocol to use for authentication. @param api_key_id [String] identifier for the secret key used in authentication. @param secret_api_key [String] the secret key that is used to generate the authentication signature.

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 22
def initialize(authorization_type, api_key_id, secret_api_key)
  raise ArgumentError unless authorization_type
  raise ArgumentError unless api_key_id and not api_key_id.strip.empty?
  raise ArgumentError unless secret_api_key and not secret_api_key.strip.empty?

  @authorization_type = authorization_type
  @api_key_id = api_key_id
  @secret_api_key = secret_api_key
end

Public Instance Methods

create_simple_authentication_signature(http_method, resource_uri, http_headers) click to toggle source

Creates a signature to authenticate a request.

@param http_method [String] 'GET', 'PUT', 'POST' or 'DELETE' indicating which HTTP method will be used with the request @param resource_uri [URI::HTTP] URI object that includes path and query of the URL that will be used, query may be nil @param http_headers [Array<Ingenico::Connect::SDK::RequestHeader>] list that contains all headers used by the request @return [String] the created signature

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 38
def create_simple_authentication_signature(http_method, resource_uri, http_headers)
  raise ArgumentError unless http_method and not http_method.strip.empty?
  raise ArgumentError unless resource_uri

  data_to_sign = to_data_to_sign(http_method, resource_uri, http_headers)
  "GCS #{@authorization_type}:#{@api_key_id}:#{create_auth_signature(data_to_sign)}"
end

Protected Instance Methods

create_auth_signature(data_to_sign) click to toggle source

Applies the HMAC algorithm to the canonicalized data to obtain an HMAC digest. Afterwards the HMAC digest is encoded using base64 encoding.

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 82
def create_auth_signature(data_to_sign)
  digest = OpenSSL::Digest.new(HMAC_ALGOR)
  hmac = OpenSSL::HMAC.digest(digest, @secret_api_key, data_to_sign)
  Base64.strict_encode64(hmac).strip
end
to_data_to_sign(http_method, resource_uri, http_headers) click to toggle source

Canonizes the http_method, resource_uri and http_headers so a unique signature can be generated. Canonical form is as follows:

  • http_method in upper case

  • Content-Type

  • Date header

  • X-GCS headers sorted alphabetically. Names are in lowercase and values are stripped of excess whitespace

  • path and query portion of the uri, separated by a question mark

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 55
def to_data_to_sign(http_method, resource_uri, http_headers)
  content_type = ''
  date = ''
  canonical_resource = to_canonical_resource(resource_uri)
  xgc_http_headers = []

  http_headers.each do |header|
    name, value = header.name, header.value
    case
    when name.casecmp(CONTENT_TYPE) == 0
      content_type = value
    when name.casecmp(DATE) == 0
      date = value
    when to_canonical_header_name(name).start_with?(XGCS)
      xgc_http_headers << [ to_canonical_header_name(name), to_canonical_header_value(value) ]
    end
  end if http_headers

  xgc_http_headers.sort! { |(h1, v1), (h2, v2)| h1 <=> h2 } unless xgc_http_headers.empty?

  data = "#{http_method.upcase}\n#{content_type}\n#{date}\n"
  data << xgc_http_headers.inject('') { |s, (k, v)| "#{s}#{k}:#{v}\n" } unless xgc_http_headers.empty?
  data << "#{canonical_resource}\n" unless canonical_resource.nil?
end

Private Instance Methods

to_canonical_header_name(original_name) click to toggle source
# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 96
def to_canonical_header_name(original_name)
  original_name ? original_name.downcase : original_name
end
to_canonical_header_value(original_value) click to toggle source

Strips a header value of excess whitespace to produce a canonical value

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 101
def to_canonical_header_value(original_value)
  return '' unless original_value
  original_value.gsub(/\r?\n[\s&&[^\r\n]]*/, ' ').strip
end
to_canonical_resource(resource_uri) click to toggle source

Returns the encoded URI path without the HTTP method and including all decoded query parameters.

# File lib/ingenico/connect/sdk/defaultimpl/default_authenticator.rb, line 91
def to_canonical_resource(resource_uri)
  return "#{resource_uri.path}?#{resource_uri.query}" if resource_uri.query
  return resource_uri.path
end