Class: Cerner::OAuth1a::AccessTokenAgent

Inherits:
Object
  • Object
show all
Defined in:
lib/cerner/oauth1a/access_token_agent.rb

Overview

Public: A user agent (client) for interacting with the Cerner OAuth 1.0a Access Token service to acquire consumer Access Tokens or service provider Keys.

Constant Summary collapse

MIME_WWW_FORM_URL_ENCODED =
'application/x-www-form-urlencoded'
DEFAULT_REALM_ALIASES =
{
  'https://oauth-api.cerner.com' => ['https://api.cernercare.com'].freeze,
  'https://api.cernercare.com' => ['https://oauth-api.cerner.com'].freeze,
  'https://oauth-api.sandboxcerner.com' => ['https://api.sandboxcernercare.com'].freeze,
  'https://api.sandboxcernercare.com' => ['https://oauth-api.sandboxcerner.com'].freeze,
  'https://oauth-api.devcerner.com' => ['https://api.devcernercare.com'].freeze,
  'https://api.devcernercare.com' => ['https://oauth-api.devcerner.com'].freeze
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(access_token_url:, consumer_key:, consumer_secret:, open_timeout: 5, read_timeout: 5, cache_keys: true, cache_access_tokens: true, realm_aliases: nil, signature_method: 'PLAINTEXT') ⇒ AccessTokenAgent

Public: Constructs an instance of the agent.

Caching

By default, AccessToken and Keys instances are maintained in a small, constrained memory cache used by #retrieve and #retrieve_keys, respectively.

The AccessToken cache keeps a maximum of 5 entries and prunes them when they expire. As the cache is based on the #consumer_key and the ‘principal’ parameter, the cache has limited effect. It’s strongly suggested that AccessToken’s be cached independently, as well.

The Keys cache keeps a maximum of 10 entries and prunes them 24 hours after retrieval.

arguments - The keyword arguments of the method:

:access_token_url    - The String or URI of the Access Token service endpoint.
:consumer_key        - The String of the Consumer Key of the account.
:consumer_secret     - The String of the Consumer Secret of the account.
:open_timeout        - An object responding to to_i. Used to set the timeout, in
                       seconds, for opening HTTP connections to the Access Token
                       service (optional, default: 5).
:read_timeout        - An object responding to to_i. Used to set the timeout, in
                       seconds, for reading data from HTTP connections to the
                       Access Token service (optional, default: 5).
:cache_keys          - A Boolean for configuring Keys caching within
                       #retrieve_keys. (optional, default: true)
:cache_access_tokens - A Boolean for configuring AccessToken caching within
                       #retrieve. (optional, default: true)
:realm_aliases       - An Array of Strings that provide realm aliases for the
                       realm that's extracted from :access_token_url. If nil,
                       this will be initalized with the DEFAULT_REALM_ALIASES.
                       (optional, default: nil)
:signature_method    - A String to set the signature method to use. MUST be
                       PLAINTEXT or HMAC-SHA1. (optional, default: 'PLAINTEXT')

Raises ArgumentError if access_token_url, consumer_key or consumer_key is nil; if

access_token_url is an invalid URI; if signature_method is invalid.

Raises:

  • (ArgumentError)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 80

def initialize(
  access_token_url:,
  consumer_key:,
  consumer_secret:,
  open_timeout: 5,
  read_timeout: 5,
  cache_keys: true,
  cache_access_tokens: true,
  realm_aliases: nil,
  signature_method: 'PLAINTEXT'
)
  raise ArgumentError, 'consumer_key is nil' unless consumer_key
  raise ArgumentError, 'consumer_secret is nil' unless consumer_secret

  @consumer_key = consumer_key
  @consumer_secret = consumer_secret

  @access_token_url = Internal.convert_to_http_uri(url: access_token_url, name: 'access_token_url')
  @realm = Protocol.realm_for(@access_token_url)
  @realm_aliases = realm_aliases
  @realm_aliases ||= DEFAULT_REALM_ALIASES[@realm]

  @open_timeout = (open_timeout ? open_timeout.to_i : 5)
  @read_timeout = (read_timeout ? read_timeout.to_i : 5)

  @keys_cache = cache_keys ? Cache.instance : nil
  @access_token_cache = cache_access_tokens ? Cache.instance : nil

  @signature_method = signature_method || 'PLAINTEXT'
  raise ArgumentError, 'signature_method is invalid' unless Signature::METHODS.include?(@signature_method)
end

Instance Attribute Details

#access_token_urlObject (readonly)

Returns the URI Access Token URL.



34
35
36
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 34

def access_token_url
  @access_token_url
end

#consumer_keyObject (readonly)

Returns the String Consumer Key.



36
37
38
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 36

def consumer_key
  @consumer_key
end

#consumer_secretObject (readonly)

Returns the String Consumer Secret.



38
39
40
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 38

def consumer_secret
  @consumer_secret
end

#realmObject (readonly)

Returns the String Protection Realm. The realm is root of the access_token_url (Protocol#realm_for).



40
41
42
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 40

def realm
  @realm
end

#realm_aliasesObject (readonly)

Returns the Array of Protection Realm String that are considered equivalent (#realm_eql?) to #realm.



42
43
44
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 42

def realm_aliases
  @realm_aliases
end

Instance Method Details

#generate_accessor_secretObject

Public: Generate an Accessor Secret for invocations of the Access Token service.

Returns a String containing the secret.



179
180
181
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 179

def generate_accessor_secret
  SecureRandom.uuid
end

#generate_nonceObject

Public: Generate a Nonce for invocations of the Access Token service.

Returns a String containing the nonce.



186
187
188
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 186

def generate_nonce
  Internal.generate_nonce
end

#generate_timestampObject

Public: Generate a Timestamp for invocations of the Access Token service.

Returns an Integer representing the number of seconds since the epoch.



193
194
195
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 193

def generate_timestamp
  Internal.generate_timestamp
end

#realm_eql?(realm) ⇒ Boolean

Public: Determines if the passed realm is equivalent to the configured realm by comparing it to the #realm and #realm_aliases.

realm - The String to check for equivalence.

Returns True if the passed realm is equivalent to the configured realm;

False otherwise.

Returns:

  • (Boolean)


204
205
206
207
208
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 204

def realm_eql?(realm)
  return true if @realm.eql?(realm)

  @realm_aliases.include?(realm)
end

#retrieve(principal: nil, ignore_cache: false) ⇒ Object

Public: Retrieves an AccessToken from the configured Access Token service endpoint (#access_token_url). This method will use the #generate_accessor_secret, #generate_nonce and #generate_timestamp methods to interact with the service, which can be overridden via a sub-class, if desired.

keywords - The keyword arguments:

:principal    - An optional principal identifier, which is passed via the
                xoauth_principal protocol parameter.
:ignore_cache - A flag for indicating that the cache should be ignored and a new
                Access Token should be retrieved.

Returns a AccessToken upon success.

Raises OAuthError for any functional errors returned within an HTTP 200 response. Raises StandardError sub-classes for any issues interacting with the service, such as networking issues.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 156

def retrieve(principal: nil, ignore_cache: false)
  cache_key = "#{@consumer_key}&#{principal}"

  if @access_token_cache && !ignore_cache
    cache_entry = @access_token_cache.get('cerner-oauth1a/access-tokens', cache_key)
    return cache_entry.value if cache_entry
  end

  # generate token request info
  timestamp = generate_timestamp
  accessor_secret = generate_accessor_secret

  request = retrieve_prepare_request(timestamp: timestamp, accessor_secret: accessor_secret, principal: principal)
  response = http_client.request(request)
  access_token =
    retrieve_handle_response(response: response, timestamp: timestamp, accessor_secret: accessor_secret)
  @access_token_cache&.put('cerner-oauth1a/access-tokens', cache_key, Cache::AccessTokenEntry.new(access_token))
  access_token
end

#retrieve_keys(keys_version, ignore_cache: false) ⇒ Object

Public: Retrieves the service provider keys from the configured Access Token service endpoint (@access_token_url). This method will invoke #retrieve to acquire an AccessToken to request the keys.

keys_version - The version identifier of the keys to retrieve. This corresponds to the

KeysVersion parameter of the oauth_token.

keywords - The keyword arguments:

:ignore_cache - A flag for indicating that the cache should be ignored and a
                new Access Token should be retrieved.

Return a Keys instance upon success.

Raises ArgumentError if keys_version is nil. Raises OAuthError for any functional errors returned within an HTTP 200 response. Raises StandardError sub-classes for any issues interacting with the service, such as networking issues.

Raises:

  • (ArgumentError)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/cerner/oauth1a/access_token_agent.rb', line 127

def retrieve_keys(keys_version, ignore_cache: false)
  raise ArgumentError, 'keys_version is nil' unless keys_version

  if @keys_cache && !ignore_cache
    cache_entry = @keys_cache.get('cerner-oauth1a/keys', keys_version)
    return cache_entry.value if cache_entry
  end

  request = retrieve_keys_prepare_request(keys_version)
  response = http_client.request(request)
  keys = retrieve_keys_handle_response(keys_version, response)
  @keys_cache&.put('cerner-oauth1a/keys', keys_version, Cache::KeysEntry.new(keys, Cache::TWENTY_FOUR_HOURS))
  keys
end