rack-oauth2 1.17.0 → 2.2.1
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 +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/spec.yml +31 -0
- data/CHANGELOG.md +31 -0
- data/README.rdoc +1 -20
- data/VERSION +1 -1
- data/lib/rack/oauth2/access_token/authenticator.rb +1 -10
- data/lib/rack/oauth2/access_token/bearer.rb +1 -1
- data/lib/rack/oauth2/access_token/mtls.rb +2 -2
- data/lib/rack/oauth2/access_token.rb +4 -6
- data/lib/rack/oauth2/client.rb +86 -38
- data/lib/rack/oauth2/server/abstract/error.rb +2 -1
- data/lib/rack/oauth2/server/extension/pkce.rb +1 -1
- data/lib/rack/oauth2/server/rails/response_ext.rb +3 -3
- data/lib/rack/oauth2/server/resource/error.rb +4 -4
- data/lib/rack/oauth2/server/resource.rb +0 -1
- data/lib/rack/oauth2/server/token/error.rb +3 -1
- data/lib/rack/oauth2/server/token.rb +13 -4
- data/lib/rack/oauth2.rb +11 -10
- data/rack-oauth2.gemspec +6 -4
- data/spec/helpers/webmock_helper.rb +8 -2
- data/spec/rack/oauth2/access_token/authenticator_spec.rb +2 -22
- data/spec/rack/oauth2/access_token/bearer_spec.rb +2 -2
- data/spec/rack/oauth2/access_token_spec.rb +0 -17
- data/spec/rack/oauth2/client_spec.rb +135 -75
- data/spec/rack/oauth2/oauth2_spec.rb +0 -43
- data/spec/rack/oauth2/server/authorize/error_spec.rb +6 -6
- data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +2 -2
- data/spec/rack/oauth2/server/resource/bearer_spec.rb +9 -9
- data/spec/rack/oauth2/server/resource/error_spec.rb +14 -14
- data/spec/rack/oauth2/server/token/authorization_code_spec.rb +2 -2
- data/spec/rack/oauth2/server/token/error_spec.rb +5 -5
- data/spec/rack/oauth2/server/token_spec.rb +71 -2
- metadata +43 -47
- data/.travis.yml +0 -8
- data/lib/rack/oauth2/access_token/legacy.rb +0 -19
- data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +0 -17
- data/lib/rack/oauth2/access_token/mac/signature.rb +0 -34
- data/lib/rack/oauth2/access_token/mac/verifier.rb +0 -44
- data/lib/rack/oauth2/access_token/mac.rb +0 -103
- data/lib/rack/oauth2/debugger/request_filter.rb +0 -30
- data/lib/rack/oauth2/debugger.rb +0 -3
- data/lib/rack/oauth2/server/resource/mac/error.rb +0 -24
- data/lib/rack/oauth2/server/resource/mac.rb +0 -36
- data/spec/mock_response/tokens/legacy.json +0 -5
- data/spec/mock_response/tokens/legacy.txt +0 -1
- data/spec/mock_response/tokens/legacy_without_expires_in.txt +0 -1
- data/spec/mock_response/tokens/mac.json +0 -8
- data/spec/rack/oauth2/access_token/legacy_spec.rb +0 -23
- data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +0 -28
- data/spec/rack/oauth2/access_token/mac/signature_spec.rb +0 -59
- data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +0 -25
- data/spec/rack/oauth2/access_token/mac_spec.rb +0 -141
- data/spec/rack/oauth2/debugger/request_filter_spec.rb +0 -33
- data/spec/rack/oauth2/server/resource/mac/error_spec.rb +0 -52
- data/spec/rack/oauth2/server/resource/mac_spec.rb +0 -119
- /data/spec/mock_response/{blank → blank.txt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2c3515e2af90285deab9032fece3d0ef8c7445405cc1cce705160c19fb2052b
|
4
|
+
data.tar.gz: e95c0fca744d8d12d97e1be23ff48cb00250d92a536de03382021e73e809c737
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c2a9ddb2f9b4b9d18c337d678bf88d660f3597d09ec9d63195062cd1c5fc0a3c5105135f51aa1f4efef4e64b9e66c2a6f36dc6b4037b5c09cefbace858ce67e
|
7
|
+
data.tar.gz: e0add9d0227669a3cfd6e11c208bc36f89c13ec8cda2ab2352bb9b0d29ee0ac59b266aee90732c4e756895fc8d66ebaefdd4defe5342392e67e08d9022514da9
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
name: Spec
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
spec:
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
os: ['ubuntu-20.04', 'ubuntu-22.04']
|
17
|
+
ruby-version: ['3.1', '3.2', '3.3']
|
18
|
+
include:
|
19
|
+
- os: 'ubuntu-20.04'
|
20
|
+
ruby-version: '3.0'
|
21
|
+
runs-on: ${{ matrix.os }}
|
22
|
+
|
23
|
+
steps:
|
24
|
+
- uses: actions/checkout@v3
|
25
|
+
- name: Set up Ruby
|
26
|
+
uses: ruby/setup-ruby@v1
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby-version }}
|
29
|
+
bundler-cache: true
|
30
|
+
- name: Run Specs
|
31
|
+
run: bundle exec rake spec
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## [Unreleased]
|
2
|
+
|
3
|
+
## [2.2.0] - 2022-10-11
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
|
7
|
+
- automatic json response decoding, and remove legacy token support by @nov in https://github.com/nov/rack-oauth2/pull/95
|
8
|
+
|
9
|
+
## [2.1.0] - 2022-10-10
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- accept local_http_config on Rack::OAuth2::Client#access_token! & revoke! to support custom headers etc. by @nov in https://github.com/nov/rack-oauth2/pull/93
|
14
|
+
|
15
|
+
## [2.0.1] - 2022-10-09
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- changes for mTLS on faraday by @nov in https://github.com/nov/rack-oauth2/pull/92
|
20
|
+
|
21
|
+
## [2.0.0] - 2022-10-09
|
22
|
+
|
23
|
+
### Added
|
24
|
+
|
25
|
+
- start recording CHANGELOG
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- Switch from httpclient to faraday v2 https://github.com/nov/rack-oauth2/pull/91
|
30
|
+
- make url-encoded the default https://github.com/nov/rack-oauth2/commit/98faf139be4f5bf9ec6134d31f65a298259d8a8b
|
31
|
+
- let faraday encode params https://github.com/nov/rack-oauth2/commit/f399b3afb8facb3635b8842baee8584bc4d3ce73
|
data/README.rdoc
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
= rack-oauth2
|
2
2
|
|
3
3
|
OAuth 2.0 Server & Client Library.
|
4
|
-
Both Bearer
|
5
|
-
|
6
|
-
{<img src="https://secure.travis-ci.org/nov/rack-oauth2.png" />}[http://travis-ci.org/nov/rack-oauth2]
|
4
|
+
Both Bearer token type are supported.
|
7
5
|
|
8
6
|
The OAuth 2.0 Authorization Framework (RFC 6749)
|
9
7
|
http://www.rfc-editor.org/rfc/rfc6749.txt
|
@@ -11,9 +9,6 @@ http://www.rfc-editor.org/rfc/rfc6749.txt
|
|
11
9
|
The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750)
|
12
10
|
http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-06
|
13
11
|
|
14
|
-
HTTP Authentication: MAC Access Authentication (draft 01)
|
15
|
-
http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
|
16
|
-
|
17
12
|
== Installation
|
18
13
|
|
19
14
|
gem install rack-oauth2
|
@@ -31,31 +26,17 @@ http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
|
|
31
26
|
Source on GitHub
|
32
27
|
https://github.com/nov/rack-oauth2-sample
|
33
28
|
|
34
|
-
=== MAC
|
35
|
-
|
36
|
-
Source on GitHub
|
37
|
-
https://github.com/nov/rack-oauth2-sample-mac
|
38
|
-
|
39
29
|
== Sample Client
|
40
30
|
|
41
|
-
=== Common between Bearer and MAC
|
42
|
-
|
43
31
|
Authorization Request (request_type: 'code' and 'token')
|
44
32
|
https://gist.github.com/862393
|
45
33
|
|
46
34
|
Token Request (grant_type: 'client_credentials', 'password', 'authorization_code' and 'refresh_token')
|
47
35
|
https://gist.github.com/883541
|
48
36
|
|
49
|
-
=== Bearer
|
50
|
-
|
51
37
|
Resource Request (request both for resource owner resource and for client resource)
|
52
38
|
https://gist.github.com/883575
|
53
39
|
|
54
|
-
=== MAC
|
55
|
-
|
56
|
-
Resource Request (request both for resource owner resource and for client resource)
|
57
|
-
https://gist.github.com/933885
|
58
|
-
|
59
40
|
== Note on Patches/Pull Requests
|
60
41
|
|
61
42
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.2.1
|
@@ -6,18 +6,9 @@ module Rack
|
|
6
6
|
@token = token
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
# request:: HTTP::Message
|
11
|
-
def filter_request(request)
|
9
|
+
def authenticate(request)
|
12
10
|
@token.authenticate(request)
|
13
11
|
end
|
14
|
-
|
15
|
-
# Callback called in HTTPClient (after received a response)
|
16
|
-
# response:: HTTP::Message
|
17
|
-
# request:: HTTP::Message
|
18
|
-
def filter_response(response, request)
|
19
|
-
# nothing to do
|
20
|
-
end
|
21
12
|
end
|
22
13
|
end
|
23
14
|
end
|
@@ -7,8 +7,8 @@ module Rack
|
|
7
7
|
def initialize(attributes = {})
|
8
8
|
super
|
9
9
|
self.token_type = :bearer
|
10
|
-
|
11
|
-
|
10
|
+
http_client.ssl.client_key = private_key
|
11
|
+
http_client.ssl.client_cert = certificate
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -5,7 +5,7 @@ module Rack
|
|
5
5
|
attr_required :access_token, :token_type
|
6
6
|
attr_optional :refresh_token, :expires_in, :scope
|
7
7
|
attr_accessor :raw_attributes
|
8
|
-
delegate :get, :patch, :post, :put, :delete, to: :
|
8
|
+
delegate :get, :patch, :post, :put, :delete, to: :http_client
|
9
9
|
|
10
10
|
alias_method :to_s, :access_token
|
11
11
|
|
@@ -18,9 +18,9 @@ module Rack
|
|
18
18
|
attr_missing!
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
@
|
23
|
-
|
21
|
+
def http_client
|
22
|
+
@http_client ||= Rack::OAuth2.http_client("#{self.class} (#{VERSION})") do |faraday|
|
23
|
+
Authenticator.new(self).authenticate(faraday)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -39,6 +39,4 @@ end
|
|
39
39
|
|
40
40
|
require 'rack/oauth2/access_token/authenticator'
|
41
41
|
require 'rack/oauth2/access_token/bearer'
|
42
|
-
require 'rack/oauth2/access_token/mac'
|
43
|
-
require 'rack/oauth2/access_token/legacy'
|
44
42
|
require 'rack/oauth2/access_token/mtls'
|
data/lib/rack/oauth2/client.rb
CHANGED
@@ -3,7 +3,7 @@ module Rack
|
|
3
3
|
class Client
|
4
4
|
include AttrRequired, AttrOptional
|
5
5
|
attr_required :identifier
|
6
|
-
attr_optional :secret, :private_key, :certificate, :redirect_uri, :scheme, :host, :port, :authorization_endpoint, :token_endpoint
|
6
|
+
attr_optional :secret, :private_key, :certificate, :redirect_uri, :scheme, :host, :port, :authorization_endpoint, :token_endpoint, :revocation_endpoint
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
9
|
(required_attributes + optional_attributes).each do |key|
|
@@ -69,17 +69,76 @@ module Rack
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def access_token!(*args)
|
72
|
-
headers, params =
|
72
|
+
headers, params, http_client, options = authenticated_context_from(*args)
|
73
|
+
params[:scope] = Array(options.delete(:scope)).join(' ') if options[:scope].present?
|
74
|
+
params.merge! @grant.as_json
|
75
|
+
params.merge! options
|
76
|
+
handle_response do
|
77
|
+
http_client.post(
|
78
|
+
absolute_uri_for(token_endpoint),
|
79
|
+
Util.compact_hash(params),
|
80
|
+
headers
|
81
|
+
) do |req|
|
82
|
+
yield req if block_given?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def revoke!(*args)
|
88
|
+
headers, params, http_client, options = authenticated_context_from(*args)
|
89
|
+
|
90
|
+
params.merge! case
|
91
|
+
when access_token = options.delete(:access_token)
|
92
|
+
{
|
93
|
+
token: access_token,
|
94
|
+
token_type_hint: :access_token
|
95
|
+
}
|
96
|
+
when refresh_token = options.delete(:refresh_token)
|
97
|
+
{
|
98
|
+
token: refresh_token,
|
99
|
+
token_type_hint: :refresh_token
|
100
|
+
}
|
101
|
+
when @grant.is_a?(Grant::RefreshToken)
|
102
|
+
{
|
103
|
+
token: @grant.refresh_token,
|
104
|
+
token_type_hint: :refresh_token
|
105
|
+
}
|
106
|
+
when options[:token].blank?
|
107
|
+
raise ArgumentError, 'One of "token", "access_token" and "refresh_token" is required'
|
108
|
+
end
|
109
|
+
params.merge! options
|
110
|
+
|
111
|
+
handle_revocation_response do
|
112
|
+
http_client.post(
|
113
|
+
absolute_uri_for(revocation_endpoint),
|
114
|
+
Util.compact_hash(params),
|
115
|
+
headers
|
116
|
+
) do |req|
|
117
|
+
yield req if block_given?
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def absolute_uri_for(endpoint)
|
125
|
+
_endpoint_ = Util.parse_uri endpoint
|
126
|
+
_endpoint_.scheme ||= self.scheme || 'https'
|
127
|
+
_endpoint_.host ||= self.host
|
128
|
+
_endpoint_.port ||= self.port
|
129
|
+
raise 'No Host Info' unless _endpoint_.host
|
130
|
+
_endpoint_.to_s
|
131
|
+
end
|
132
|
+
|
133
|
+
def authenticated_context_from(*args)
|
134
|
+
headers, params = {}, {}
|
73
135
|
http_client = Rack::OAuth2.http_client
|
74
136
|
|
75
137
|
# NOTE:
|
76
138
|
# Using Array#extract_options! for backward compatibility.
|
77
139
|
# Until v1.0.5, the first argument was 'client_auth_method' in scalar.
|
78
140
|
options = args.extract_options!
|
79
|
-
client_auth_method = args.first || options.delete(:client_auth_method)
|
80
|
-
|
81
|
-
params[:scope] = Array(options.delete(:scope)).join(' ') if options[:scope].present?
|
82
|
-
params.merge! options
|
141
|
+
client_auth_method = args.first || options.delete(:client_auth_method)&.to_sym || :basic
|
83
142
|
|
84
143
|
case client_auth_method
|
85
144
|
when :basic
|
@@ -100,9 +159,11 @@ module Rack
|
|
100
159
|
client_assertion_type: URN::ClientAssertionType::JWT_BEARER
|
101
160
|
)
|
102
161
|
# NOTE: optionally auto-generate client_assertion.
|
103
|
-
if
|
162
|
+
params[:client_assertion] = if options[:client_assertion].present?
|
163
|
+
options.delete(:client_assertion)
|
164
|
+
else
|
104
165
|
require 'json/jwt'
|
105
|
-
|
166
|
+
JSON::JWT.new(
|
106
167
|
iss: identifier,
|
107
168
|
sub: identifier,
|
108
169
|
aud: absolute_uri_for(token_endpoint),
|
@@ -119,32 +180,16 @@ module Rack
|
|
119
180
|
params.merge!(
|
120
181
|
client_id: identifier
|
121
182
|
)
|
122
|
-
http_client.
|
123
|
-
http_client.
|
183
|
+
http_client.ssl.client_key = private_key
|
184
|
+
http_client.ssl.client_cert = certificate
|
124
185
|
else
|
125
186
|
params.merge!(
|
126
187
|
client_id: identifier,
|
127
188
|
client_secret: secret
|
128
189
|
)
|
129
190
|
end
|
130
|
-
handle_response do
|
131
|
-
http_client.post(
|
132
|
-
absolute_uri_for(token_endpoint),
|
133
|
-
Util.compact_hash(params),
|
134
|
-
headers
|
135
|
-
)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
191
|
|
141
|
-
|
142
|
-
_endpoint_ = Util.parse_uri endpoint
|
143
|
-
_endpoint_.scheme ||= self.scheme || 'https'
|
144
|
-
_endpoint_.host ||= self.host
|
145
|
-
_endpoint_.port ||= self.port
|
146
|
-
raise 'No Host Info' unless _endpoint_.host
|
147
|
-
_endpoint_.to_s
|
192
|
+
[headers, params, http_client, options]
|
148
193
|
end
|
149
194
|
|
150
195
|
def handle_response
|
@@ -157,27 +202,30 @@ module Rack
|
|
157
202
|
end
|
158
203
|
end
|
159
204
|
|
205
|
+
def handle_revocation_response
|
206
|
+
response = yield
|
207
|
+
case response.status
|
208
|
+
when 200..201
|
209
|
+
:success
|
210
|
+
else
|
211
|
+
handle_error_response response
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
160
215
|
def handle_success_response(response)
|
161
|
-
token_hash =
|
162
|
-
case (@forced_token_type || token_hash[:token_type])
|
216
|
+
token_hash = response.body.with_indifferent_access
|
217
|
+
case (@forced_token_type || token_hash[:token_type])&.downcase
|
163
218
|
when 'bearer'
|
164
219
|
AccessToken::Bearer.new(token_hash)
|
165
|
-
when 'mac'
|
166
|
-
AccessToken::MAC.new(token_hash)
|
167
|
-
when nil
|
168
|
-
AccessToken::Legacy.new(token_hash)
|
169
220
|
else
|
170
221
|
raise 'Unknown Token Type'
|
171
222
|
end
|
172
|
-
rescue JSON::ParserError
|
173
|
-
# NOTE: Facebook support (They don't use JSON as token response)
|
174
|
-
AccessToken::Legacy.new Rack::Utils.parse_nested_query(response.body).with_indifferent_access
|
175
223
|
end
|
176
224
|
|
177
225
|
def handle_error_response(response)
|
178
|
-
error =
|
226
|
+
error = response.body.with_indifferent_access
|
179
227
|
raise Error.new(response.status, error)
|
180
|
-
rescue
|
228
|
+
rescue Faraday::ParsingError, NoMethodError
|
181
229
|
raise Error.new(response.status, error: 'Unknown', error_description: response.body)
|
182
230
|
end
|
183
231
|
end
|
@@ -27,7 +27,7 @@ module Rack
|
|
27
27
|
response.status = status
|
28
28
|
yield response if block_given?
|
29
29
|
unless response.redirect?
|
30
|
-
response.
|
30
|
+
response.headers['Content-Type'] = 'application/json'
|
31
31
|
response.write Util.compact_hash(protocol_params).to_json
|
32
32
|
end
|
33
33
|
response.finish
|
@@ -42,6 +42,7 @@ module Rack
|
|
42
42
|
|
43
43
|
class Unauthorized < Error
|
44
44
|
def initialize(error = :unauthorized, description = nil, options = {})
|
45
|
+
@skip_www_authenticate = options[:skip_www_authenticate]
|
45
46
|
super 401, error, description, options
|
46
47
|
end
|
47
48
|
end
|
@@ -27,7 +27,7 @@ module Rack
|
|
27
27
|
|
28
28
|
def verify_code_verifier!(code_challenge, code_challenge_method = :S256)
|
29
29
|
if code_verifier.present? || code_challenge.present?
|
30
|
-
case code_challenge_method
|
30
|
+
case code_challenge_method&.to_sym
|
31
31
|
when :S256
|
32
32
|
code_challenge == Util.urlsafe_base64_encode(
|
33
33
|
OpenSSL::Digest::SHA256.digest(code_verifier.to_s)
|
@@ -21,9 +21,9 @@ module Rack
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def headers
|
25
25
|
ensure_finish do
|
26
|
-
@
|
26
|
+
@headers
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -39,7 +39,7 @@ module Rack
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def ensure_finish
|
42
|
-
@status, @
|
42
|
+
@status, @headers, @body = finish unless finished?
|
43
43
|
yield
|
44
44
|
end
|
45
45
|
end
|
@@ -13,11 +13,11 @@ module Rack
|
|
13
13
|
def finish
|
14
14
|
super do |response|
|
15
15
|
self.realm ||= DEFAULT_REALM
|
16
|
-
|
16
|
+
headers = response.headers['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\""
|
17
17
|
if ErrorMethods::DEFAULT_DESCRIPTION.keys.include?(error)
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
headers << ", error=\"#{error}\""
|
19
|
+
headers << ", error_description=\"#{description}\"" if description.present?
|
20
|
+
headers << ", error_uri=\"#{uri}\"" if uri.present?
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -8,7 +8,9 @@ module Rack
|
|
8
8
|
class Unauthorized < Abstract::Unauthorized
|
9
9
|
def finish
|
10
10
|
super do |response|
|
11
|
-
|
11
|
+
unless @skip_www_authenticate
|
12
|
+
response.headers['WWW-Authenticate'] = 'Basic realm="OAuth2 Token Endpoint"'
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -44,7 +44,7 @@ module Rack
|
|
44
44
|
|
45
45
|
class Request < Abstract::Request
|
46
46
|
attr_required :grant_type
|
47
|
-
attr_optional :client_secret
|
47
|
+
attr_optional :client_secret, :client_assertion, :client_assertion_type
|
48
48
|
|
49
49
|
def initialize(env)
|
50
50
|
auth = Rack::Auth::Basic::Request.new(env)
|
@@ -56,6 +56,15 @@ module Rack
|
|
56
56
|
else
|
57
57
|
super
|
58
58
|
@client_secret = params['client_secret']
|
59
|
+
@client_assertion = params['client_assertion']
|
60
|
+
@client_assertion_type = params['client_assertion_type']
|
61
|
+
if client_assertion.present? && client_assertion_type == URN::ClientAssertionType::JWT_BEARER
|
62
|
+
require 'json/jwt'
|
63
|
+
@client_id = JSON::JWT.decode(
|
64
|
+
client_assertion,
|
65
|
+
:skip_verification
|
66
|
+
)[:sub] rescue nil
|
67
|
+
end
|
59
68
|
end
|
60
69
|
@grant_type = params['grant_type'].to_s
|
61
70
|
end
|
@@ -71,9 +80,9 @@ module Rack
|
|
71
80
|
def finish
|
72
81
|
attr_missing!
|
73
82
|
write Util.compact_hash(protocol_params).to_json
|
74
|
-
|
75
|
-
|
76
|
-
|
83
|
+
headers['Content-Type'] = 'application/json'
|
84
|
+
headers['Cache-Control'] = 'no-store'
|
85
|
+
headers['Pragma'] = 'no-cache'
|
77
86
|
super
|
78
87
|
end
|
79
88
|
end
|
data/lib/rack/oauth2.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rack'
|
2
|
-
require '
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday/follow_redirects'
|
3
4
|
require 'logger'
|
4
5
|
require 'active_support'
|
5
6
|
require 'active_support/core_ext'
|
@@ -40,13 +41,15 @@ module Rack
|
|
40
41
|
self.debugging = false
|
41
42
|
|
42
43
|
def self.http_client(agent_name = "Rack::OAuth2 (#{VERSION})", &local_http_config)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
Faraday.new(headers: {user_agent: agent_name}) do |faraday|
|
45
|
+
faraday.request :url_encoded
|
46
|
+
faraday.request :json
|
47
|
+
faraday.response :json
|
48
|
+
faraday.adapter Faraday.default_adapter
|
49
|
+
local_http_config&.call(faraday)
|
50
|
+
http_config&.call(faraday)
|
51
|
+
faraday.response :logger, Rack::OAuth2.logger, bodies: true if debugging?
|
52
|
+
end
|
50
53
|
end
|
51
54
|
|
52
55
|
def self.http_config(&block)
|
@@ -56,7 +59,6 @@ module Rack
|
|
56
59
|
def self.reset_http_config!
|
57
60
|
@@http_config = nil
|
58
61
|
end
|
59
|
-
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
@@ -65,4 +67,3 @@ require 'rack/oauth2/util'
|
|
65
67
|
require 'rack/oauth2/server'
|
66
68
|
require 'rack/oauth2/client'
|
67
69
|
require 'rack/oauth2/access_token'
|
68
|
-
require 'rack/oauth2/debugger'
|
data/rack-oauth2.gemspec
CHANGED
@@ -2,19 +2,20 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'rack-oauth2'
|
3
3
|
s.version = File.read('VERSION')
|
4
4
|
s.authors = ['nov matake']
|
5
|
-
s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer
|
6
|
-
s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer
|
5
|
+
s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer token type are supported.}
|
6
|
+
s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer token type are supported}
|
7
7
|
s.email = 'nov@matake.jp'
|
8
8
|
s.extra_rdoc_files = ['LICENSE', 'README.rdoc']
|
9
9
|
s.rdoc_options = ['--charset=UTF-8']
|
10
|
-
s.homepage = '
|
10
|
+
s.homepage = 'https://github.com/nov/rack-oauth2'
|
11
11
|
s.license = 'MIT'
|
12
12
|
s.require_paths = ['lib']
|
13
13
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
14
|
s.files = `git ls-files`.split("\n")
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.add_runtime_dependency 'rack', '>= 2.1.0'
|
17
|
-
s.add_runtime_dependency '
|
17
|
+
s.add_runtime_dependency 'faraday', '~> 2.0'
|
18
|
+
s.add_runtime_dependency 'faraday-follow_redirects'
|
18
19
|
s.add_runtime_dependency 'activesupport'
|
19
20
|
s.add_runtime_dependency 'attr_required'
|
20
21
|
s.add_runtime_dependency 'json-jwt', '>= 1.11.0'
|
@@ -23,4 +24,5 @@ Gem::Specification.new do |s|
|
|
23
24
|
s.add_development_dependency 'rspec'
|
24
25
|
s.add_development_dependency 'rspec-its'
|
25
26
|
s.add_development_dependency 'webmock'
|
27
|
+
s.add_development_dependency 'rexml'
|
26
28
|
end
|
@@ -13,7 +13,7 @@ module WebMockHelper
|
|
13
13
|
|
14
14
|
def request_for(method, options = {})
|
15
15
|
request = {}
|
16
|
-
params = options
|
16
|
+
params = options&.[](:params) || {}
|
17
17
|
case method
|
18
18
|
when :post, :put, :delete
|
19
19
|
request[:body] = params
|
@@ -28,7 +28,13 @@ module WebMockHelper
|
|
28
28
|
|
29
29
|
def response_for(response_file, options = {})
|
30
30
|
response = {}
|
31
|
-
|
31
|
+
format = options[:format] || :json
|
32
|
+
if format == :json
|
33
|
+
response[:headers] = {
|
34
|
+
'Content-Type': 'application/json'
|
35
|
+
}
|
36
|
+
end
|
37
|
+
response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', "#{response_file}.#{format}"))
|
32
38
|
if options[:status]
|
33
39
|
response[:status] = options[:status]
|
34
40
|
end
|
@@ -2,25 +2,16 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Rack::OAuth2::AccessToken::Authenticator do
|
4
4
|
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
|
5
|
-
let(:request) {
|
5
|
+
let(:request) { Faraday::Request.new(:get, URI.parse(resource_endpoint)) }
|
6
6
|
let(:authenticator) { Rack::OAuth2::AccessToken::Authenticator.new(token) }
|
7
7
|
|
8
8
|
shared_examples_for :authenticator do
|
9
9
|
it 'should let the token authenticate the request' do
|
10
10
|
expect(token).to receive(:authenticate).with(request)
|
11
|
-
authenticator.
|
11
|
+
authenticator.authenticate(request)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
context 'when Legacy token is given' do
|
16
|
-
let(:token) do
|
17
|
-
Rack::OAuth2::AccessToken::Legacy.new(
|
18
|
-
access_token: 'access_token'
|
19
|
-
)
|
20
|
-
end
|
21
|
-
it_behaves_like :authenticator
|
22
|
-
end
|
23
|
-
|
24
15
|
context 'when Bearer token is given' do
|
25
16
|
let(:token) do
|
26
17
|
Rack::OAuth2::AccessToken::Bearer.new(
|
@@ -29,15 +20,4 @@ describe Rack::OAuth2::AccessToken::Authenticator do
|
|
29
20
|
end
|
30
21
|
it_behaves_like :authenticator
|
31
22
|
end
|
32
|
-
|
33
|
-
context 'when MAC token is given' do
|
34
|
-
let(:token) do
|
35
|
-
Rack::OAuth2::AccessToken::MAC.new(
|
36
|
-
access_token: 'access_token',
|
37
|
-
mac_key: 'secret',
|
38
|
-
mac_algorithm: 'hmac-sha-256'
|
39
|
-
)
|
40
|
-
end
|
41
|
-
it_behaves_like :authenticator
|
42
|
-
end
|
43
23
|
end
|