cerner-oauth1a 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +88 -0
- data/lib/cerner/oauth1a.rb +3 -0
- data/lib/cerner/oauth1a/access_token.rb +138 -0
- data/lib/cerner/oauth1a/access_token_agent.rb +179 -0
- data/lib/cerner/oauth1a/oauth_error.rb +26 -0
- data/lib/cerner/oauth1a/version.rb +5 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 78e443a0c2b7b55bc787c7892ddd671af08769e4
|
4
|
+
data.tar.gz: 6631bda81224b2102408deae304611d63eb3b52b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d5d68c6bfa9eae2007d5331ba60349a3c5e69c911f1d771bd0cae784136205e500cc727524f271854d5ef8d495b4aed5820cb4f3940aad00ef7528eed8612191
|
7
|
+
data.tar.gz: d8e086be1015712861286552827300d6bb72a1c8466b8d9f55962c797c44d5adcb9daaeaebd06dfe61a06ee89235b6f2f4a2f0276267d8116f4350007e711b77
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Cerner OAuth 1.0a Client Library
|
2
|
+
|
3
|
+
This RubyGem is a client library for interacting with the Cerner OAuth 1.0a provider to
|
4
|
+
participate in two-legged (B2B) authentication. The goal of this project is to provide a zero-dependency Ruby library that simply and compactly implements the client aspects of
|
5
|
+
Cerner OAuth 1.0a variant of the OAuth 1.0a B2B workflow.
|
6
|
+
|
7
|
+
# Usage
|
8
|
+
|
9
|
+
## Install
|
10
|
+
This library can be installed using the `gem` command or added to a Gemfile for use with Bundler.
|
11
|
+
|
12
|
+
### `gem` command
|
13
|
+
|
14
|
+
$ gem install cerner-oauth1a
|
15
|
+
|
16
|
+
### Gemfile
|
17
|
+
|
18
|
+
gem 'cerner-oauth1a', '~> 1.0'
|
19
|
+
|
20
|
+
## Basic Use
|
21
|
+
|
22
|
+
require 'cerner/oauth1a'
|
23
|
+
require 'net/http'
|
24
|
+
|
25
|
+
# Setup the AccessTokenAgent with an Access Token URL, Key and Secret
|
26
|
+
agent = Cerner::OAuth1a::AccessTokenAgent.new(
|
27
|
+
access_token_url: 'https://api.cernercare.com/oauth/access',
|
28
|
+
consumer_key: 'CONSUMER_KEY',
|
29
|
+
consumer_secret: 'CONSUMER_SECRET')
|
30
|
+
|
31
|
+
# Retrieve an AccessToken instance
|
32
|
+
access_token = agent.retrieve
|
33
|
+
|
34
|
+
# Setup the HTTP library to access the protected API you want to invoke
|
35
|
+
uri = URI('https://authz-demo-api.cerner.com/me')
|
36
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
37
|
+
http.use_ssl = true if uri.scheme == 'https'
|
38
|
+
|
39
|
+
# Invoke the API's HTTP endpoint and use the AccessToken to generate an Authorization header
|
40
|
+
response = http.request_get(uri.path, Authorization: access_token.authorization_header)
|
41
|
+
|
42
|
+
## Access Token Reuse
|
43
|
+
Generally, you'll want to use an Access Token more than once. Access Tokens can be reused, but
|
44
|
+
they do expire, so you'll need to acquire new tokens after one expires. All of the expiration
|
45
|
+
information is contained in the AccessToken class and you can easily determine if a token is
|
46
|
+
expired or about to by using the AccessToken#expired? method. Below is an example of you might
|
47
|
+
implement that:
|
48
|
+
|
49
|
+
uri = URI('https://authz-demo-api.cerner.com/me')
|
50
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
51
|
+
http.use_ssl = true if uri.scheme == 'https'
|
52
|
+
|
53
|
+
access_token = agent.retrieve if access_token.expired?
|
54
|
+
|
55
|
+
response = http.request_get(uri.path, Authorization: access_token.authorization_header)
|
56
|
+
|
57
|
+
## References
|
58
|
+
* https://wiki.ucern.com/display/public/reference/Cerner%27s+OAuth+Specification
|
59
|
+
* http://oauth.net/core/1.0a
|
60
|
+
* http://oauth.pbwiki.com/ProblemReporting
|
61
|
+
* https://wiki.ucern.com/display/public/reference/Accessing+Cerner%27s+Web+Services+Using+OAuth+1.0a
|
62
|
+
|
63
|
+
# Building
|
64
|
+
|
65
|
+
This project is built using Ruby 2.2+, Rake and Bundler. RSpec is used for unit tests and SimpleCov
|
66
|
+
is utilized for test coverage.
|
67
|
+
|
68
|
+
# Availability
|
69
|
+
|
70
|
+
This RubyGem will be available on https://rubygems.org/.
|
71
|
+
|
72
|
+
# Communication
|
73
|
+
|
74
|
+
All questions, bugs, enhancements and pull requests can be submitted here, on GitHub via Issues.
|
75
|
+
|
76
|
+
# Contributing
|
77
|
+
|
78
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
79
|
+
|
80
|
+
# LICENSE
|
81
|
+
|
82
|
+
Copyright 2017 Cerner Innovation, Inc.
|
83
|
+
|
84
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
85
|
+
|
86
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
87
|
+
|
88
|
+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Cerner
|
2
|
+
module OAuth1a
|
3
|
+
|
4
|
+
# Public: An OAuth 1.0a Access Token.
|
5
|
+
class AccessToken
|
6
|
+
# Returns the String Accessor Secret related to this token.
|
7
|
+
attr_reader :accessor_secret
|
8
|
+
# Returns the String Consumer Key related to this token.
|
9
|
+
attr_reader :consumer_key
|
10
|
+
# Returns the Time this token expires at.
|
11
|
+
attr_reader :expires_at
|
12
|
+
# Returns the String nonce related to this token.
|
13
|
+
attr_reader :nonce
|
14
|
+
# Returns the Time this token was created.
|
15
|
+
attr_reader :timestamp
|
16
|
+
# Returns the String Token.
|
17
|
+
attr_reader :token
|
18
|
+
# Returns the String Token Secret related to this token.
|
19
|
+
attr_reader :token_secret
|
20
|
+
|
21
|
+
# Public: Constructs an instance.
|
22
|
+
#
|
23
|
+
# arguments - The keyword arguments of the method:
|
24
|
+
# :accessor_secret - The String representing the accessor secret.
|
25
|
+
# :consumer_key - The String representing the consumer key.
|
26
|
+
# :expires_at - A Time representing the expiration moment or any object
|
27
|
+
# responding to to_i that represents the expiration moment
|
28
|
+
# as the number of seconds since the epoch.
|
29
|
+
# :nonce - The String representing the nonce.
|
30
|
+
# :expires_at - A Time representing the creation moment or any object
|
31
|
+
# responding to to_i that represents the creation moment
|
32
|
+
# as the number of seconds since the epoch.
|
33
|
+
# :token - The String representing the token.
|
34
|
+
# :token_secret - The String representing the token secret.
|
35
|
+
#
|
36
|
+
# Raises ArgumentError if any of the arguments is nil
|
37
|
+
def initialize(accessor_secret:, consumer_key:, expires_at:, nonce:, timestamp:, token:, token_secret:)
|
38
|
+
raise ArgumentError, 'accessor_secret is nil' unless accessor_secret
|
39
|
+
raise ArgumentError, 'consumer_key is nil' unless consumer_key
|
40
|
+
raise ArgumentError, 'expires_at is nil' unless expires_at
|
41
|
+
raise ArgumentError, 'nonce is nil' unless nonce
|
42
|
+
raise ArgumentError, 'timestamp is nil' unless timestamp
|
43
|
+
raise ArgumentError, 'token is nil' unless token
|
44
|
+
raise ArgumentError, 'token_secret is nil' unless token_secret
|
45
|
+
|
46
|
+
@accessor_secret = accessor_secret
|
47
|
+
@consumer_key = consumer_key
|
48
|
+
@expires_at = convert_to_time(expires_at)
|
49
|
+
@nonce = nonce
|
50
|
+
@timestamp = convert_to_time(timestamp)
|
51
|
+
@token = token
|
52
|
+
@token_secret = token_secret
|
53
|
+
@authorization_header = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Generates a value suitable for use as an HTTP Authorization header.
|
57
|
+
#
|
58
|
+
# Returns a String representation of the access token.
|
59
|
+
def authorization_header
|
60
|
+
return @authorization_header if @authorization_header
|
61
|
+
|
62
|
+
tuples = {
|
63
|
+
oauth_version: '1.0',
|
64
|
+
oauth_signature_method: 'PLAINTEXT',
|
65
|
+
oauth_signature: "#{@accessor_secret}&#{@token_secret}",
|
66
|
+
oauth_consumer_key: @consumer_key,
|
67
|
+
oauth_nonce: @nonce,
|
68
|
+
oauth_timestamp: @timestamp.tv_sec,
|
69
|
+
oauth_token: @token
|
70
|
+
}
|
71
|
+
@authorization_header = "OAuth " + tuples.map { |k, v| "#{k}=\"#{URI.encode_www_form_component(v)}\"" }.join(', ')
|
72
|
+
end
|
73
|
+
|
74
|
+
# Public: Check whether the access token has expired. By default (with no arguments),
|
75
|
+
# the method checks whether the token has expired based on the current time and a fudge
|
76
|
+
# factor of 300 seconds. Non-default argument values can be used to see whether the
|
77
|
+
# access token has expired at a different time and with a different fudge factor.
|
78
|
+
#
|
79
|
+
# now - A Time instance to check the expiration information against. Default is Time.now.
|
80
|
+
# fudge_sec - The number of seconds to remove from 'now' to adjust the comparion.
|
81
|
+
#
|
82
|
+
# Returns true if the access token as expired; false otherwise
|
83
|
+
def expired?(now: Time.now, fudge_sec: 300)
|
84
|
+
now = convert_to_time(now)
|
85
|
+
(now.tv_sec - fudge_sec) >= expires_at.tv_sec
|
86
|
+
end
|
87
|
+
|
88
|
+
# Public: Compare this to other based on attributes.
|
89
|
+
#
|
90
|
+
# Return true if equal; false otherwise
|
91
|
+
def ==(other)
|
92
|
+
accessor_secret == other.accessor_secret &&
|
93
|
+
consumer_key == other.consumer_key &&
|
94
|
+
expires_at == other.expires_at &&
|
95
|
+
nonce == other.nonce &&
|
96
|
+
timestamp == other.timestamp &&
|
97
|
+
token == other.token &&
|
98
|
+
token_secret == other.token_secret
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: Compare this to other based on the attributes. Equivalent to calling #==.
|
102
|
+
#
|
103
|
+
# Return true if equal; false otherwise
|
104
|
+
def eql?(other)
|
105
|
+
self == other
|
106
|
+
end
|
107
|
+
|
108
|
+
# Public: Generates a Hash of the attributes.
|
109
|
+
#
|
110
|
+
# Returns a Hash with keys for each attribute.
|
111
|
+
def to_h
|
112
|
+
{
|
113
|
+
accessor_secret: @accessor_secret,
|
114
|
+
consumer_key: @consumer_key,
|
115
|
+
expires_at: @expires_at,
|
116
|
+
nonce: @nonce,
|
117
|
+
timestamp: @timestamp,
|
118
|
+
token: @token,
|
119
|
+
token_secret: @token_secret
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Internal: Used by #initialize and #expired? to convert data into a Time instance.
|
126
|
+
# Returns a Time instance in the UTC time zone
|
127
|
+
def convert_to_time(time)
|
128
|
+
raise ArgumentError, 'time is nil' unless time
|
129
|
+
if time.is_a? Time
|
130
|
+
time.utc
|
131
|
+
else
|
132
|
+
Time.at(time.to_i).utc
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'cerner/oauth1a/access_token'
|
2
|
+
require 'cerner/oauth1a/oauth_error'
|
3
|
+
require 'cerner/oauth1a/version'
|
4
|
+
require 'net/https'
|
5
|
+
require 'securerandom'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module Cerner
|
9
|
+
module OAuth1a
|
10
|
+
|
11
|
+
# Public: A User Agent for interacting with the Access Token service to acquire
|
12
|
+
# Access Tokens.
|
13
|
+
class AccessTokenAgent
|
14
|
+
MIME_WWW_FORM_URL_ENCODED = 'application/x-www-form-urlencoded'
|
15
|
+
|
16
|
+
# Returns the URI Access Token URL.
|
17
|
+
attr_reader :access_token_url
|
18
|
+
# Returns the String Consumer Key.
|
19
|
+
attr_reader :consumer_key
|
20
|
+
# Returns the String Consumer Secret.
|
21
|
+
attr_reader :consumer_secret
|
22
|
+
|
23
|
+
# Public: Constructs an instance of the agent.
|
24
|
+
#
|
25
|
+
# arguments - The keyword arguments of the method:
|
26
|
+
# :access_token_url - The String or URI of the Access Token service endpoint.
|
27
|
+
# :consumer_key - The String of the Consumer Key of the account.
|
28
|
+
# :consumer_secret - The String of the Consumer Secret of the account.
|
29
|
+
# :open_timeout - An object responding to to_i. Used to set the timeout, in seconds,
|
30
|
+
# for opening HTTP connections to the Access Token service (optional, default: 5).
|
31
|
+
# :read_timeout - An object responding to to_i. Used to set the timeout, in seconds,
|
32
|
+
# for reading data from HTTP connections to the Access Token service (optional, default: 5).
|
33
|
+
#
|
34
|
+
# Raises ArgumentError if access_token_url, consumer_key or consumer_key is nil; if access_token_url is
|
35
|
+
# an invalid URI.
|
36
|
+
def initialize(access_token_url:, consumer_key:, consumer_secret:, open_timeout: 5, read_timeout: 5)
|
37
|
+
raise ArgumentError, 'consumer_key is nil' unless consumer_key
|
38
|
+
raise ArgumentError, 'consumer_secret is nil' unless consumer_secret
|
39
|
+
|
40
|
+
@consumer_key = consumer_key
|
41
|
+
@consumer_secret = consumer_secret
|
42
|
+
|
43
|
+
@access_token_url = convert_to_http_uri(access_token_url)
|
44
|
+
|
45
|
+
@open_timeout = (open_timeout ? open_timeout.to_i : 5)
|
46
|
+
@read_timeout = (read_timeout ? read_timeout.to_i : 5)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Public: Retrives an AccessToken from the configured Access Token service endpoint (#access_token_url).
|
50
|
+
# This method will the #generate_accessor_secret, #generate_nonce and #generate_timestamp methods to
|
51
|
+
# interact with the service, which can be overridden via a sub-class, if desired.
|
52
|
+
#
|
53
|
+
# Returns a AccessToken upon success.
|
54
|
+
#
|
55
|
+
# Raises OAuthError unless the service returns a HTTP Status Code of 200.
|
56
|
+
# Raises StandardError sub-classes for any issues interacting with the service.
|
57
|
+
def retrieve
|
58
|
+
# construct a POST request
|
59
|
+
request = Net::HTTP::Post.new @access_token_url
|
60
|
+
|
61
|
+
# setup the data to construct the POST's message
|
62
|
+
accessor_secret = generate_accessor_secret
|
63
|
+
nonce = generate_nonce
|
64
|
+
timestamp = generate_timestamp
|
65
|
+
params = [
|
66
|
+
[:oauth_consumer_key, @consumer_key],
|
67
|
+
[:oauth_signature_method, 'PLAINTEXT'],
|
68
|
+
[:oauth_version, '1.0'],
|
69
|
+
[:oauth_timestamp, timestamp],
|
70
|
+
[:oauth_nonce, nonce],
|
71
|
+
[:oauth_signature, "#{@consumer_secret}&"],
|
72
|
+
[:oauth_accessor_secret, accessor_secret]
|
73
|
+
]
|
74
|
+
# set the POST's body as a URL form-encoded string
|
75
|
+
request.set_form(params, MIME_WWW_FORM_URL_ENCODED, charset: 'UTF-8')
|
76
|
+
|
77
|
+
request['Accept'] = MIME_WWW_FORM_URL_ENCODED
|
78
|
+
# Set a custom User-Agent to help identify these invocation
|
79
|
+
request['User-Agent'] = "cerner-oauth1a #{VERSION} (Ruby #{RUBY_VERSION})"
|
80
|
+
|
81
|
+
http = Net::HTTP.new(@access_token_url.host, @access_token_url.port)
|
82
|
+
if @access_token_url.scheme == 'https'
|
83
|
+
# if the scheme is HTTPS, then enable SSL
|
84
|
+
http.use_ssl = true
|
85
|
+
# make sure to verify peers
|
86
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
87
|
+
# tweak the ciphers to eliminate unsafe options
|
88
|
+
http.ciphers = 'DEFAULT:!aNULL:!eNULL:!LOW:!SSLv2:!RC4'
|
89
|
+
end
|
90
|
+
http.open_timeout = @open_timeout
|
91
|
+
http.read_timeout = @read_timeout
|
92
|
+
|
93
|
+
response = http.request request
|
94
|
+
|
95
|
+
case response
|
96
|
+
when Net::HTTPSuccess
|
97
|
+
# Part the HTTP response and convert it into a Symbol-keyed Hash
|
98
|
+
tuples = Hash[URI.decode_www_form(response.body).map { |pair| [pair[0].to_sym, pair[1]] }]
|
99
|
+
# Use the parsed response to construct the AccessToken
|
100
|
+
access_token = AccessToken.new(accessor_secret: accessor_secret,
|
101
|
+
consumer_key: @consumer_key,
|
102
|
+
expires_at: timestamp + tuples[:oauth_expires_in].to_i,
|
103
|
+
nonce: nonce,
|
104
|
+
timestamp: timestamp,
|
105
|
+
token: tuples[:oauth_token],
|
106
|
+
token_secret: tuples[:oauth_token_secret])
|
107
|
+
access_token
|
108
|
+
else
|
109
|
+
# Extract any OAuth Problems reported in the response
|
110
|
+
oauth_data = parse_www_authenticate(response['WWW-Authenticate'])
|
111
|
+
# Raise an error for a failure to acquire a token
|
112
|
+
raise OAuthError.new('unable to acquire token', response.code, oauth_data['oauth_problem'])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Public: Generate an Accessor Secret for invocations of the Access Token service.
|
117
|
+
#
|
118
|
+
# Returns a String containing the secret.
|
119
|
+
def generate_accessor_secret
|
120
|
+
SecureRandom.uuid
|
121
|
+
end
|
122
|
+
|
123
|
+
# Public: Generate a Nonce for invocations of the Access Token service.
|
124
|
+
#
|
125
|
+
# Returns a String containing the nonce.
|
126
|
+
def generate_nonce
|
127
|
+
SecureRandom.hex
|
128
|
+
end
|
129
|
+
|
130
|
+
# Public: Generate a Timestamp for invocations of the Access Token service.
|
131
|
+
#
|
132
|
+
# Returns an Integer representing the number of seconds since the epoch.
|
133
|
+
def generate_timestamp
|
134
|
+
Time.now.to_i
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# Internal: Parse a WWW-Authenticate HTTP header for any OAuth
|
140
|
+
# information, which is indicated by a value starting with 'OAuth '.
|
141
|
+
#
|
142
|
+
# value - The String containing the header value.
|
143
|
+
#
|
144
|
+
# Returns a Hash containing any name-value pairs found in the value.
|
145
|
+
def parse_www_authenticate(value)
|
146
|
+
return {} unless value
|
147
|
+
value = value.strip
|
148
|
+
return {} unless value.start_with?('OAuth ')
|
149
|
+
|
150
|
+
Hash[value.scan(/([^\s=]*)=\"([^\"]*)\"/)]
|
151
|
+
end
|
152
|
+
|
153
|
+
# Internal: Convert an Access Token URL into a URI with some verification checks
|
154
|
+
#
|
155
|
+
# access_token_url - A String URL or a URI instance
|
156
|
+
# Returns a URI::HTTP or URI::HTTPS
|
157
|
+
#
|
158
|
+
# Raises ArgumentError if access_token_url is nil, invalid or not an HTTP/HTTPS URI
|
159
|
+
def convert_to_http_uri(access_token_url)
|
160
|
+
raise ArgumentError, 'access_token_url is nil' unless access_token_url
|
161
|
+
if access_token_url.is_a? URI
|
162
|
+
uri = access_token_url
|
163
|
+
else
|
164
|
+
begin
|
165
|
+
uri = URI(access_token_url)
|
166
|
+
rescue URI::InvalidURIError => e
|
167
|
+
# raise argument error with cause
|
168
|
+
raise ArgumentError, 'access_token_url is invalid'
|
169
|
+
end
|
170
|
+
end
|
171
|
+
unless uri.is_a? URI::HTTP
|
172
|
+
raise ArgumentError, 'access_token_url must be an HTTP or HTTPS URI'
|
173
|
+
end
|
174
|
+
uri
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Cerner
|
2
|
+
module OAuth1a
|
3
|
+
# Public: An OAuth-specific error.
|
4
|
+
class OAuthError < StandardError
|
5
|
+
# Returns the HTTP Response Code, if any, associated with this error.
|
6
|
+
attr_reader :http_response_code
|
7
|
+
# Returns the OAuth Problem string, if any, associated with this error.
|
8
|
+
# See http://oauth.pbwiki.com/ProblemReporting for more information.
|
9
|
+
attr_reader :oauth_problem
|
10
|
+
|
11
|
+
# Public: Construct an instance with a message, optional HTTP response code
|
12
|
+
# and optional OAuth Problem string.
|
13
|
+
#
|
14
|
+
# message - A descriptive message, passed to the super class.
|
15
|
+
# http_response_code - The HTTP response code associated with the error. Optional.
|
16
|
+
# oauth_problem - The OAuth Problem string associated with the error. Optional.
|
17
|
+
def initialize(message, http_response_code=nil, oauth_problem=nil)
|
18
|
+
@http_response_code = http_response_code
|
19
|
+
@oauth_problem = oauth_problem
|
20
|
+
message += " HTTP #{@http_response_code}" if @http_response_code
|
21
|
+
message += " OAuth Problem #{@oauth_problem}" if @oauth_problem
|
22
|
+
super message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cerner-oauth1a
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Beyer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-05 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A minimal dependency client library for two-legged OAuth1.0a service
|
14
|
+
providers, such as Cerner's OAuth 1.0aprovider.
|
15
|
+
email:
|
16
|
+
- nbeyer@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- README.md
|
22
|
+
- lib/cerner/oauth1a.rb
|
23
|
+
- lib/cerner/oauth1a/access_token.rb
|
24
|
+
- lib/cerner/oauth1a/access_token_agent.rb
|
25
|
+
- lib/cerner/oauth1a/oauth_error.rb
|
26
|
+
- lib/cerner/oauth1a/version.rb
|
27
|
+
homepage: http://github.com/cerner/cerner-oauth1a
|
28
|
+
licenses: []
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '2.2'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.6.8
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: B2B/two-legged OAuth 1.0a service client.
|
50
|
+
test_files: []
|