Class: Cerner::OAuth1a::AccessToken
- Inherits:
-
Object
- Object
- Cerner::OAuth1a::AccessToken
- Defined in:
- lib/cerner/oauth1a/access_token.rb
Overview
Public: A Cerner OAuth 1.0a Access Token and related request parameters for use in Consumer or Service Provider use cases.
Instance Attribute Summary collapse
-
#accessor_secret ⇒ Object
readonly
Returns a String, but may be nil, with the Accessor Secret (oauth_accessor_secret) related to this token.
-
#consumer_key ⇒ Object
readonly
Returns a String with the Consumer Key (oauth_consumer_key) related to this token.
-
#consumer_principal ⇒ Object
readonly
Returns a String with the Consumer Principal (Consumer.Principal param encoded within oauth_token).
-
#expires_at ⇒ Object
readonly
Returns a Time, but may be nil, which represents the moment when this token expires.
-
#nonce ⇒ Object
readonly
Returns a String, but may be nil, with the Nonce (oauth_nonce) related to this token.
-
#realm ⇒ Object
readonly
Returns a String, but may be nil, with the Protection Realm related to this token.
-
#signature ⇒ Object
readonly
Returns a String, but may be nil, with the Signature (oauth_signature) related to this token.
-
#signature_method ⇒ Object
readonly
Returns a String with the Signature Method (oauth_signature_method) related to this token.
-
#timestamp ⇒ Object
readonly
Returns a Time, but may be nil, with the Timestamp (oauth_timestamp) related to this token.
-
#token ⇒ Object
readonly
Returns a String with the Token (oauth_token).
-
#token_secret ⇒ Object
readonly
Returns a String, but may be nil, with the Token Secret related to this token.
Class Method Summary collapse
-
.from_authorization_header(value) ⇒ Object
Public: Constructs an AccessToken using the value of an HTTP Authorization Header based on the OAuth HTTP Authorization Scheme (oauth.net/core/1.0a/#auth_header).
Instance Method Summary collapse
-
#==(other) ⇒ Object
Public: Compare this to other based on attributes.
-
#authenticate(access_token_agent, http_method: 'GET', fully_qualified_url: nil, request_params: nil) ⇒ Object
Public: Authenticates the #token against the #consumer_key, #signature and side-channel secrets exchange via AccessTokenAgent#retrieve_keys.
-
#authorization_header(nonce: nil, timestamp: nil, http_method: 'GET', fully_qualified_url: nil, request_params: nil) ⇒ Object
Public: Generates a value suitable for use as an HTTP Authorization header.
-
#eql?(other) ⇒ Boolean
Public: Compare this to other based on the attributes.
-
#expired?(now: Time.now, fudge_sec: 300) ⇒ Boolean
Public: Check whether the access token has expired, if #expires_at is not nil.
-
#initialize(accessor_secret: nil, consumer_key:, expires_at: nil, nonce: nil, signature: nil, signature_method: 'PLAINTEXT', timestamp: nil, token:, token_secret: nil, realm: nil) ⇒ AccessToken
constructor
Public: Constructs an instance.
-
#to_h ⇒ Object
Public: Generates a Hash of the attributes.
Constructor Details
#initialize(accessor_secret: nil, consumer_key:, expires_at: nil, nonce: nil, signature: nil, signature_method: 'PLAINTEXT', timestamp: nil, token:, token_secret: nil, realm: nil) ⇒ AccessToken
Public: Constructs an instance.
arguments - The keyword arguments of the method:
:accessor_secret - The optional String representing the accessor secret.
:consumer_key - The required String representing the consumer key.
:expires_at - An optional Time representing the expiration moment or any
object responding to to_i that represents the expiration
moment as the number of seconds since the epoch.
:nonce - The optional String representing the nonce.
:timestamp - A optional Time representing the creation moment or any
object responding to to_i that represents the creation
moment as the number of seconds since the epoch.
:token - The required String representing the token.
:token_secret - The optional String representing the token secret.
:signature_method - The optional String representing the signature method.
Defaults to PLAINTEXT.
:signature - The optional String representing the signature.
:realm - The optional String representing the protection realm.
Raises ArgumentError if consumer_key or token is nil.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/cerner/oauth1a/access_token.rb', line 102 def initialize( accessor_secret: nil, consumer_key:, expires_at: nil, nonce: nil, signature: nil, signature_method: 'PLAINTEXT', timestamp: nil, token:, token_secret: nil, realm: nil ) raise ArgumentError, 'consumer_key is nil' unless consumer_key raise ArgumentError, 'token is nil' unless token @accessor_secret = accessor_secret || nil @consumer_key = consumer_key @consumer_principal = nil @expires_at = expires_at ? Internal.convert_to_time(time: expires_at, name: 'expires_at') : nil @nonce = nonce @signature = signature @signature_method = signature_method || 'PLAINTEXT' @timestamp = ? Internal.convert_to_time(time: , name: 'timestamp') : nil @token = token @token_secret = token_secret || nil @realm = realm || nil end |
Instance Attribute Details
#accessor_secret ⇒ Object (readonly)
Returns a String, but may be nil, with the Accessor Secret (oauth_accessor_secret) related to this token. Note: nil and empty are considered equivalent.
56 57 58 |
# File 'lib/cerner/oauth1a/access_token.rb', line 56 def accessor_secret @accessor_secret end |
#consumer_key ⇒ Object (readonly)
Returns a String with the Consumer Key (oauth_consumer_key) related to this token.
58 59 60 |
# File 'lib/cerner/oauth1a/access_token.rb', line 58 def consumer_key @consumer_key end |
#consumer_principal ⇒ Object (readonly)
Returns a String with the Consumer Principal (Consumer.Principal param encoded within oauth_token). This value is only populated after a successful #authenticate and only if the #token (oauth_token) contains a ‘Consumer.Principal’ parameter.
78 79 80 |
# File 'lib/cerner/oauth1a/access_token.rb', line 78 def consumer_principal @consumer_principal end |
#expires_at ⇒ Object (readonly)
Returns a Time, but may be nil, which represents the moment when this token expires.
60 61 62 |
# File 'lib/cerner/oauth1a/access_token.rb', line 60 def expires_at @expires_at end |
#nonce ⇒ Object (readonly)
Returns a String, but may be nil, with the Nonce (oauth_nonce) related to this token. This is generally only populated when parsing a token for authentication.
63 64 65 |
# File 'lib/cerner/oauth1a/access_token.rb', line 63 def nonce @nonce end |
#realm ⇒ Object (readonly)
Returns a String, but may be nil, with the Protection Realm related to this token.
80 81 82 |
# File 'lib/cerner/oauth1a/access_token.rb', line 80 def realm @realm end |
#signature ⇒ Object (readonly)
Returns a String, but may be nil, with the Signature (oauth_signature) related to this token.
74 75 76 |
# File 'lib/cerner/oauth1a/access_token.rb', line 74 def signature @signature end |
#signature_method ⇒ Object (readonly)
Returns a String with the Signature Method (oauth_signature_method) related to this token.
72 73 74 |
# File 'lib/cerner/oauth1a/access_token.rb', line 72 def signature_method @signature_method end |
#timestamp ⇒ Object (readonly)
Returns a Time, but may be nil, with the Timestamp (oauth_timestamp) related to this token. This is generally only populated when parsing a token for authentication.
66 67 68 |
# File 'lib/cerner/oauth1a/access_token.rb', line 66 def @timestamp end |
#token ⇒ Object (readonly)
Returns a String with the Token (oauth_token).
68 69 70 |
# File 'lib/cerner/oauth1a/access_token.rb', line 68 def token @token end |
#token_secret ⇒ Object (readonly)
Returns a String, but may be nil, with the Token Secret related to this token.
70 71 72 |
# File 'lib/cerner/oauth1a/access_token.rb', line 70 def token_secret @token_secret end |
Class Method Details
.from_authorization_header(value) ⇒ Object
Public: Constructs an AccessToken using the value of an HTTP Authorization Header based on the OAuth HTTP Authorization Scheme (oauth.net/core/1.0a/#auth_header).
value - A String containing the HTTP Authorization Header value.
Returns an AccessToken.
Raises a Cerner::OAuth1a::OAuthError with a populated oauth_problem if any of the parameters in the value are invalid.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/cerner/oauth1a/access_token.rb', line 23 def self.(value) params = Protocol.(value) if params[:oauth_version] && !params[:oauth_version].eql?('1.0') raise OAuthError.new('', nil, 'version_rejected') end missing_params = [] consumer_key = params[:oauth_consumer_key] missing_params << :oauth_consumer_key if consumer_key.nil? || consumer_key.empty? token = params[:oauth_token] missing_params << :oauth_token if token.nil? || token.empty? signature_method = params[:oauth_signature_method] missing_params << :oauth_signature_method if signature_method.nil? || signature_method.empty? signature = params[:oauth_signature] missing_params << :oauth_signature if signature.nil? || signature.empty? raise OAuthError.new('', nil, 'parameter_absent', missing_params) unless missing_params.empty? AccessToken.new( accessor_secret: params[:oauth_accessor_secret], consumer_key: consumer_key, nonce: params[:oauth_nonce], timestamp: params[:oauth_timestamp], token: token, signature_method: signature_method, signature: signature, realm: params[:realm] ) end |
Instance Method Details
#==(other) ⇒ Object
Public: Compare this to other based on attributes.
other - The AccessToken to compare this to.
Return true if equal; false otherwise
325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/cerner/oauth1a/access_token.rb', line 325 def ==(other) accessor_secret == other.accessor_secret && consumer_key == other.consumer_key && expires_at == other.expires_at && nonce == other.nonce && == other. && token == other.token && token_secret == other.token_secret && signature_method == other.signature_method && signature == other.signature && realm == other.realm end |
#authenticate(access_token_agent, http_method: 'GET', fully_qualified_url: nil, request_params: nil) ⇒ Object
Public: Authenticates the #token against the #consumer_key, #signature and side-channel secrets exchange via AccessTokenAgent#retrieve_keys. If this instance has a #realm set, then it will compare it to the AccessTokenAgent#realm using the AccessTokenAgent#realm_eql? method.
access_token_agent - An instance of Cerner::OAuth1a::AccessTokenAgent configured with
appropriate credentials to retrieve secrets via
Cerner::OAuth1a::AccessTokenAgent#retrieve_keys.
keywords - The keyword arguments:
:http_method - An optional String or Symbol containing an HTTP
method name. (default: 'GET')
:fully_qualified_url - An optional String or URI that contains the
scheme, host, port (optional) and path of a URL.
:request_params - An optional Hash of name/value pairs
representing the request parameters. The keys
and values of the Hash will be assumed to be
represented by the value returned from #to_s.
Returns a Hash (symbolized keys) of any extra parameters within #token (oauth_token), if authentication succeeds. In most scenarios, the Hash will be empty.
Raises ArgumentError if access_token_agent is nil Raises Cerner::OAuth1a::OAuthError with an oauth_problem if authentication fails.
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/cerner/oauth1a/access_token.rb', line 259 def authenticate( access_token_agent, http_method: 'GET', fully_qualified_url: nil, request_params: nil ) raise ArgumentError, 'access_token_agent is nil' unless access_token_agent if @realm && !access_token_agent.realm_eql?(@realm) raise OAuthError.new('realm does not match provider', nil, 'token_rejected', nil, access_token_agent.realm) end # Set realm to the provider's realm if it's not already set @realm ||= access_token_agent.realm tuples = Protocol.parse_url_query_string(@token) unless @consumer_key == tuples.delete(:ConsumerKey) raise OAuthError.new('consumer keys do not match', nil, 'consumer_key_rejected', nil, @realm) end verify_expiration(tuples.delete(:ExpiresOn)) keys = load_keys(access_token_agent, tuples.delete(:KeysVersion)) verify_token(keys) # RSASHA1 param gets consumed in #verify_token, so remove it too tuples.delete(:RSASHA1) verify_signature( keys: keys, hmac_secrets: tuples.delete(:HMACSecrets), http_method: http_method, fully_qualified_url: fully_qualified_url, request_params: request_params ) @consumer_principal = tuples.delete(:"Consumer.Principal") tuples end |
#authorization_header(nonce: nil, timestamp: nil, http_method: 'GET', fully_qualified_url: nil, request_params: nil) ⇒ Object
Public: Generates a value suitable for use as an HTTP Authorization header. If #signature is nil, then a signature will be generated based on the #signature_method.
PLAINTEXT Signature (preferred)
When using PLAINTEXT signatures, no additional arguments are necessary. If an oauth_nonce or oauth_timestamp are desired, then the values can be passed via the :nonce and :timestamp keyword arguments. The actual signature will be constructed from the Accessor Secret (#accessor_secret) and the Token Secret (#token_secret).
HMAC-SHA1 Signature
When using HMAC-SHA1 signatures, access to the HTTP request information is necessary. This requies that additional information is passed via the keyword arguments. The required information includes the HTTP method (see :http_method), the host authority & path (see :fully_qualified_url) and the request parameters (see :fully_qualified_url and :request_params).
keywords - The keyword arguments:
:nonce - The optional String containing a Nonce to generate the
header with HMAC-SHA1 signatures. When nil, a Nonce will
be generated.
:timestamp - The optional Time or #to_i compliant object containing a
Timestamp to generate the header with HMAC-SHA1
signatures. When nil, a Timestamp will be generated.
:http_method - The optional String or Symbol containing a HTTP Method for
constructing the HMAC-SHA1 signature. When nil, the value
defualts to 'GET'.
:fully_qualified_url - The optional String or URI containing the fully qualified
URL of the HTTP API being invoked for constructing the
HMAC-SHA1 signature. If the URL contains a query string,
the parameters will be extracted and used in addition to
the :request_params keyword argument.
:request_params - The optional Hash of name/value pairs containing the
request parameters of the HTTP API being invoked for
constructing the HMAC-SHA1 signature. Parameters passed
here will override and augment those passed in the
:fully_qualified_url parameter. The parameter names and
values MUST be unencoded. See
Protocol#parse_url_query_string for help with decoding an
encoded query string.
Returns a String representation of the access token.
Raises Cerner::OAuth1a::OAuthError if #signature_method is not PLAINTEXT or if a signature can’t be determined.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/cerner/oauth1a/access_token.rb', line 176 def ( nonce: nil, timestamp: nil, http_method: 'GET', fully_qualified_url: nil, request_params: nil ) oauth_params = {} oauth_params[:oauth_version] = '1.0' oauth_params[:oauth_signature_method] = @signature_method oauth_params[:oauth_consumer_key] = @consumer_key oauth_params[:oauth_nonce] = nonce if nonce oauth_params[:oauth_timestamp] = Internal.convert_to_time(time: , name: 'timestamp').to_i if oauth_params[:oauth_token] = @token if @signature sig = @signature else # NOTE: @accessor_secret is always used, but an empty value is allowed and project assumes # that nil implies an empty value raise OAuthError.new('token_secret is nil', nil, 'parameter_absent', nil, @realm) unless @token_secret if @signature_method == 'PLAINTEXT' sig = Signature.sign_via_plaintext(client_shared_secret: @accessor_secret, token_shared_secret: @token_secret) elsif @signature_method == 'HMAC-SHA1' http_method ||= 'GET' # default to HTTP GET request_params ||= {} # default to no request params oauth_params[:oauth_nonce] = Internal.generate_nonce unless oauth_params[:oauth_nonce] oauth_params[:oauth_timestamp] = Internal. unless oauth_params[:oauth_timestamp] begin fully_qualified_url = Internal.convert_to_http_uri(url: fully_qualified_url, name: 'fully_qualified_url') rescue ArgumentError => ae raise OAuthError.new(ae., nil, 'parameter_absent', nil, @realm) end query_params = fully_qualified_url.query ? Protocol.parse_url_query_string(fully_qualified_url.query) : {} request_params = query_params.merge(request_params) params = request_params.merge(oauth_params) signature_base_string = Signature.build_signature_base_string( http_method: http_method, fully_qualified_url: fully_qualified_url, params: params ) sig = Signature.sign_via_hmacsha1( client_shared_secret: @accessor_secret, token_shared_secret: @token_secret, signature_base_string: signature_base_string ) else raise OAuthError.new('signature_method is invalid', nil, 'signature_method_rejected', nil, @realm) end end oauth_params[:realm] = @realm if @realm oauth_params[:oauth_signature] = sig Protocol.(oauth_params) end |
#eql?(other) ⇒ Boolean
Public: Compare this to other based on the attributes. Equivalent to calling #==.
other - The AccessToken to compare this to.
Return true if equal; false otherwise
343 344 345 |
# File 'lib/cerner/oauth1a/access_token.rb', line 343 def eql?(other) self == other end |
#expired?(now: Time.now, fudge_sec: 300) ⇒ Boolean
Public: Check whether the access token has expired, if #expires_at is not nil. By default (with no arguments), the method checks whether the token has expired based on the current time and a fudge factor of 300 seconds (5 minutes). Non-default argument values can be used to see whether the access token has expired at a different time and with a different fudge factor.
now - A Time instance to check the expiration information against. Defaults to
Time.now.
fudge_sec - The number of seconds to remove from #expires_at to adjust the comparison.
Returns true if the access token is expired or #expires_at is nil; false otherwise
312 313 314 315 316 317 318 |
# File 'lib/cerner/oauth1a/access_token.rb', line 312 def expired?(now: Time.now, fudge_sec: 300) # if @expires_at is nil, return true now return true unless @expires_at now = Internal.convert_to_time(time: now, name: 'now') now.tv_sec >= @expires_at.tv_sec - fudge_sec end |
#to_h ⇒ Object
Public: Generates a Hash of the attributes.
Returns a Hash with keys for each attribute.
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/cerner/oauth1a/access_token.rb', line 350 def to_h { accessor_secret: @accessor_secret, consumer_key: @consumer_key, expires_at: @expires_at, nonce: @nonce, timestamp: @timestamp, token: @token, token_secret: @token_secret, signature_method: @signature_method, signature: @signature, consumer_principal: @consumer_principal, realm: @realm } end |