cerner-oauth1a 1.0.1 → 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +9 -0
- data/NOTICE +1 -1
- data/README.md +77 -23
- data/lib/cerner/oauth1a.rb +4 -0
- data/lib/cerner/oauth1a/access_token.rb +224 -41
- data/lib/cerner/oauth1a/access_token_agent.rb +194 -87
- data/lib/cerner/oauth1a/cache.rb +79 -0
- data/lib/cerner/oauth1a/keys.rb +124 -0
- data/lib/cerner/oauth1a/oauth_error.rb +72 -6
- data/lib/cerner/oauth1a/protocol.rb +132 -0
- data/lib/cerner/oauth1a/version.rb +3 -1
- metadata +14 -9
@@ -1,25 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cerner/oauth1a/protocol'
|
4
|
+
require 'uri'
|
5
|
+
|
1
6
|
module Cerner
|
2
7
|
module OAuth1a
|
3
8
|
# Public: An OAuth-specific error.
|
4
9
|
class OAuthError < StandardError
|
5
|
-
# Returns the HTTP Response Code, if any, associated with this error.
|
10
|
+
# Returns the HTTP Response Code, if any, associated with this error. May be nil.
|
6
11
|
attr_reader :http_response_code
|
7
|
-
|
12
|
+
|
13
|
+
# Returns the OAuth Problem string, if any, associated with this error. May be nil.
|
8
14
|
# See http://oauth.pbwiki.com/ProblemReporting for more information.
|
9
15
|
attr_reader :oauth_problem
|
10
16
|
|
17
|
+
# Returns an Array of OAuth parameter names, if any, related to #oauth_problem.
|
18
|
+
# May be nil.
|
19
|
+
attr_reader :oauth_parameters
|
20
|
+
|
11
21
|
# Public: Construct an instance with a message, optional HTTP response code
|
12
22
|
# and optional OAuth Problem string.
|
13
23
|
#
|
14
24
|
# message - A descriptive message, passed to the super class.
|
15
25
|
# http_response_code - The HTTP response code associated with the error. Optional.
|
16
26
|
# oauth_problem - The OAuth Problem string associated with the error. Optional.
|
17
|
-
|
27
|
+
# oauth_parameters - A String/Symbol or Array of Strings/Symbols containing the names of parameters that
|
28
|
+
# are absent or rejected. This is should only be used when oauth_problem
|
29
|
+
# is 'parameter_absent' or 'parameter_rejected' Optional.
|
30
|
+
def initialize(
|
31
|
+
message,
|
32
|
+
http_response_code = nil,
|
33
|
+
oauth_problem = nil,
|
34
|
+
oauth_parameters = nil
|
35
|
+
)
|
18
36
|
@http_response_code = http_response_code
|
19
37
|
@oauth_problem = oauth_problem
|
20
|
-
|
21
|
-
|
22
|
-
|
38
|
+
@oauth_parameters = oauth_parameters ? Array(oauth_parameters) : nil
|
39
|
+
|
40
|
+
parts = []
|
41
|
+
parts << message if message
|
42
|
+
parts << "HTTP #{@http_response_code}" if @http_response_code
|
43
|
+
parts << "OAuth Problem #{@oauth_problem}" if @oauth_problem
|
44
|
+
parts << "OAuth Parameters [#{@oauth_parameters.join(', ')}]" if @oauth_parameters
|
45
|
+
super(parts.empty? ? nil : parts.join(' '))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Generates an HTTP WWW-Authenticate header value based from the
|
49
|
+
# data in this OAuthError.
|
50
|
+
#
|
51
|
+
# Returns the generated value or nil if there is no #oauth_problem and #oauth_parameters.
|
52
|
+
def to_http_www_authenticate_header
|
53
|
+
params = {}
|
54
|
+
params[:oauth_problem] = @oauth_problem if @oauth_problem
|
55
|
+
|
56
|
+
if @oauth_problem && @oauth_parameters
|
57
|
+
case @oauth_problem
|
58
|
+
when 'parameter_absent'
|
59
|
+
params[:oauth_parameters_absent] = format_parameters(@oauth_parameters)
|
60
|
+
when 'parameter_rejected'
|
61
|
+
params[:oauth_parameters_rejected] = format_parameters(@oauth_parameters)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Protocol.generate_www_authenticate_header(params)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Public: Provides an HTTP Status Symbol based on the #oauth_problem using
|
69
|
+
# Protocol.convert_problem_to_http_status.
|
70
|
+
#
|
71
|
+
# default - The Symbol to return if #oauth_problem contains an unknown value.
|
72
|
+
# Defaults to :unauthorized.
|
73
|
+
#
|
74
|
+
# Returns :unauthorized, :bad_request or the value passed in default parameter.
|
75
|
+
def to_http_status(default = :unauthorized)
|
76
|
+
Protocol.convert_problem_to_http_status(@oauth_problem, default)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Internal: Formats a list of parameter names according to the OAuth
|
82
|
+
# Problem extension.
|
83
|
+
#
|
84
|
+
# params - An Array of Strings.
|
85
|
+
#
|
86
|
+
# Returns a formatted String.
|
87
|
+
def format_parameters(params)
|
88
|
+
params.map { |p| URI.encode_www_form_component(p).gsub('+', '%20') }.join('&')
|
23
89
|
end
|
24
90
|
end
|
25
91
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Cerner
|
6
|
+
module OAuth1a
|
7
|
+
# Public: OAuth 1.0a protocol utilities.
|
8
|
+
module Protocol
|
9
|
+
# Public: Parses a URL-encoded query string into a Hash with symbolized keys.
|
10
|
+
#
|
11
|
+
# query - String containing a URL-encoded query string to parse.
|
12
|
+
#
|
13
|
+
# Returns a Hash with symbolized keys matching the query parameter names.
|
14
|
+
#
|
15
|
+
# Raises ArgumentError if query is nil.
|
16
|
+
def self.parse_url_query_string(query)
|
17
|
+
raise ArgumentError, 'query is nil' unless query
|
18
|
+
|
19
|
+
Hash[URI.decode_www_form(query).map { |pair| [pair[0].to_sym, pair[1]] }]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: Parses an OAuth HTTP Authorization scheme value, which can manifest
|
23
|
+
# in either an HTTP Authorization or WWW-Authenticate header.
|
24
|
+
#
|
25
|
+
# Reference: https://oauth.net/core/1.0a/#auth_header
|
26
|
+
#
|
27
|
+
# value - String containing the value to parse. If nil or doesn't begin with
|
28
|
+
# 'OAuth ', then an empty Hash will be returned.
|
29
|
+
#
|
30
|
+
# Examples
|
31
|
+
#
|
32
|
+
# header = 'OAuth oauth_version="1.0", oauth_token="XYZ"'
|
33
|
+
# Cerner::OAuth1a::Protocol.parse_authorization_header(header)
|
34
|
+
# # => {:oauth_version=>"1.0", :oauth_token=>"XYZ"}
|
35
|
+
#
|
36
|
+
# header = 'OAuth realm="https://test.host", oauth_problem="token_expired"'
|
37
|
+
# Cerner::OAuth1a::Protocol.parse_www_authenticate_header(header)
|
38
|
+
# # => {:realm=>"https://test.host", :oauth_problem=>"token_expired"}
|
39
|
+
#
|
40
|
+
# Returns a Hash with symbolized keys of all of the parameters.
|
41
|
+
def self.parse_authorization_header(value)
|
42
|
+
params = {}
|
43
|
+
return params unless value
|
44
|
+
|
45
|
+
value = value.strip
|
46
|
+
return params unless value.size > 6 && value[0..5].casecmp?('OAuth ')
|
47
|
+
|
48
|
+
value.scan(/([^,\s=]*)=\"([^\"]*)\"/).each do |pair|
|
49
|
+
k = URI.decode_www_form_component(pair[0])
|
50
|
+
v = URI.decode_www_form_component(pair[1])
|
51
|
+
params[k.to_sym] = v
|
52
|
+
end
|
53
|
+
|
54
|
+
params
|
55
|
+
end
|
56
|
+
|
57
|
+
# Public: Generates an OAuth HTTP Authorization scheme value, which can be
|
58
|
+
# in either an HTTP Authorization or WWW-Authenticate header.
|
59
|
+
#
|
60
|
+
# Reference: https://oauth.net/core/1.0a/#auth_header
|
61
|
+
#
|
62
|
+
# params - Hash containing the key-value pairs to build the value with.
|
63
|
+
#
|
64
|
+
# Examples
|
65
|
+
#
|
66
|
+
# params = { oauth_version: '1.0', oauth_token: 'XYZ' }
|
67
|
+
# Cerner::OAuth1a::Protocol.generate_authorization_header(params)
|
68
|
+
# # => "OAuth oauth_version=\"1.0\",oauth_token=\"XYZ\""
|
69
|
+
#
|
70
|
+
# params = { realm: 'https://test.host', oauth_problem: 'token_expired' }
|
71
|
+
# Cerner::OAuth1a::Protocol.generate_www_authenticate_header(params)
|
72
|
+
# # => "OAuth realm=\"https%3A%2F%2Ftest.host\",oauth_problem=\"token_expired\""
|
73
|
+
#
|
74
|
+
# Returns the String containing the generated value or nil if params is nil or empty.
|
75
|
+
def self.generate_authorization_header(params)
|
76
|
+
return nil unless params && !params.empty?
|
77
|
+
|
78
|
+
encoded_params = params.map do |k, v|
|
79
|
+
k = URI.encode_www_form_component(k).gsub('+', '%20')
|
80
|
+
v = URI.encode_www_form_component(v).gsub('+', '%20')
|
81
|
+
"#{k}=\"#{v}\""
|
82
|
+
end
|
83
|
+
|
84
|
+
'OAuth ' + encoded_params.join(',')
|
85
|
+
end
|
86
|
+
|
87
|
+
# Alias the parse and generate methods
|
88
|
+
class << self
|
89
|
+
# Public: Alias for Protocol.parse_authorization_header
|
90
|
+
alias parse_www_authenticate_header parse_authorization_header
|
91
|
+
|
92
|
+
# Public: Alias for Protocol.generate_www_authenticate_header
|
93
|
+
alias generate_www_authenticate_header generate_authorization_header
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: The oauth_problem values that are mapped to HTTP 400 Bad Request.
|
97
|
+
# The values come from http://wiki.oauth.net/w/page/12238543/ProblemReporting
|
98
|
+
# and are mapped based on https://oauth.net/core/1.0/#rfc.section.10.
|
99
|
+
BAD_REQUEST_PROBLEMS = %w[
|
100
|
+
additional_authorization_required parameter_absent parameter_rejected
|
101
|
+
signature_method_rejected timestamp_refused verifier_invalid
|
102
|
+
version_rejected
|
103
|
+
].freeze
|
104
|
+
|
105
|
+
# Public: The oauth_problem values that are mapped to HTTP 401 Unauthorized.
|
106
|
+
# The values come from http://wiki.oauth.net/w/page/12238543/ProblemReporting
|
107
|
+
# and are mapped based on https://oauth.net/core/1.0/#rfc.section.10.
|
108
|
+
UNAUTHORIZED_PROBLEMS = %w[
|
109
|
+
consumer_key_refused consumer_key_rejected consumer_key_unknown
|
110
|
+
nonce_used permission_denied permission_unknown signature_invalid
|
111
|
+
token_expired token_rejected token_revoked token_used user_refused
|
112
|
+
].freeze
|
113
|
+
|
114
|
+
# Public: Converts a oauth_problem value to an HTTP Status using the
|
115
|
+
# mappings in ::BAD_REQUEST_PROBLEMS and ::UNAUTHORIZED_PROBLEMS.
|
116
|
+
#
|
117
|
+
# problem - A String containing the oauth_problem value.
|
118
|
+
# default - An optional Symbol containing the value to return if an
|
119
|
+
# unknown problem value is passed. Defaults to :unauthorized.
|
120
|
+
#
|
121
|
+
# Returns :unauthorized, :bad_request or the value passed in the default
|
122
|
+
# parameter.
|
123
|
+
def self.convert_problem_to_http_status(problem, default = :unauthorized)
|
124
|
+
return default unless problem
|
125
|
+
problem = problem.to_s
|
126
|
+
return :unauthorized if UNAUTHORIZED_PROBLEMS.include?(problem)
|
127
|
+
return :bad_request if BAD_REQUEST_PROBLEMS.include?(problem)
|
128
|
+
default
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cerner-oauth1a
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Beyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
14
|
-
|
13
|
+
description: |
|
14
|
+
A minimal dependency library for interacting with a Cerner OAuth 1.0a Access
|
15
|
+
Token Service for invoking Cerner OAuth 1.0a protected services or implementing
|
16
|
+
Cerner OAuth 1.0a authentication.
|
15
17
|
email:
|
16
18
|
- nbeyer@gmail.com
|
17
19
|
executables: []
|
@@ -26,7 +28,10 @@ files:
|
|
26
28
|
- lib/cerner/oauth1a.rb
|
27
29
|
- lib/cerner/oauth1a/access_token.rb
|
28
30
|
- lib/cerner/oauth1a/access_token_agent.rb
|
31
|
+
- lib/cerner/oauth1a/cache.rb
|
32
|
+
- lib/cerner/oauth1a/keys.rb
|
29
33
|
- lib/cerner/oauth1a/oauth_error.rb
|
34
|
+
- lib/cerner/oauth1a/protocol.rb
|
30
35
|
- lib/cerner/oauth1a/version.rb
|
31
36
|
homepage: http://github.com/cerner/cerner-oauth1a
|
32
37
|
licenses:
|
@@ -40,16 +45,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
45
|
requirements:
|
41
46
|
- - ">="
|
42
47
|
- !ruby/object:Gem::Version
|
43
|
-
version: '2.
|
48
|
+
version: '2.4'
|
44
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
50
|
requirements:
|
46
|
-
- - "
|
51
|
+
- - ">"
|
47
52
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
53
|
+
version: 1.3.1
|
49
54
|
requirements: []
|
50
55
|
rubyforge_project:
|
51
|
-
rubygems_version: 2.6
|
56
|
+
rubygems_version: 2.7.6
|
52
57
|
signing_key:
|
53
58
|
specification_version: 4
|
54
|
-
summary:
|
59
|
+
summary: Cerner OAuth 1.0a Consumer and Service Provider Library.
|
55
60
|
test_files: []
|