rack-oauth2 1.12.0 → 2.2.0
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 +32 -0
- data/CHANGELOG.md +25 -0
- data/README.rdoc +1 -26
- 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 +97 -41
- 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 +5 -5
- 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 +16 -5
- data/lib/rack/oauth2/urn.rb +3 -3
- data/lib/rack/oauth2/util.rb +6 -2
- data/lib/rack/oauth2.rb +11 -10
- data/rack-oauth2.gemspec +7 -5
- 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 +173 -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 +21 -21
- data/spec/rack/oauth2/server/token/authorization_code_spec.rb +2 -2
- data/spec/rack/oauth2/server/token/client_credentials_spec.rb +32 -2
- data/spec/rack/oauth2/server/token/error_spec.rb +8 -8
- data/spec/rack/oauth2/server/token_spec.rb +72 -3
- data/spec/rack/oauth2/util_spec.rb +8 -3
- metadata +47 -51
- data/.travis.yml +0 -7
- 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: 45ba67ac4566f374465673cc5711e71c15006bbe966531a4c1de2473206879b2
|
4
|
+
data.tar.gz: 56f8718f283533c369b1743dfd86499e49e5d828a83ac060fa919fac57a935d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63316467536c2c98cddea9b2b7907b3ff5fd6b53b892bd338709e1f7a6b014aa4dc20d71b12cd01ffac502c1ab0964218aac7ff6a0e81141ff8aa10e80557cdd
|
7
|
+
data.tar.gz: 97e685531853c4837a0e86636c865827033e25f646c4572d254e2584a811f937faa6dc7fe780742814bd9657066c9fc16394723ba87029605761d5acf2d490f7
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
name: Spec
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
spec:
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
os: ['ubuntu-20.04']
|
17
|
+
ruby-version: ['2.6', '2.7', '3.0', '3.1']
|
18
|
+
# ubuntu 22.04 only supports ssl 3 and thus only ruby 3.1
|
19
|
+
include:
|
20
|
+
- os: 'ubuntu-22.04'
|
21
|
+
ruby-version: '3.1'
|
22
|
+
runs-on: ${{ matrix.os }}
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v3
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true
|
31
|
+
- name: Run Specs
|
32
|
+
run: bundle exec rake spec
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
## [Unreleased]
|
2
|
+
|
3
|
+
## [2.1.0] - 2022-10-10
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- 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
|
8
|
+
|
9
|
+
## [2.0.1] - 2022-10-09
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- changes for mTLS on faraday by @nov in https://github.com/nov/rack-oauth2/pull/92
|
14
|
+
|
15
|
+
## [2.0.0] - 2022-10-09
|
16
|
+
|
17
|
+
### Added
|
18
|
+
|
19
|
+
- start recording CHANGELOG
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
|
23
|
+
- Switch from httpclient to faraday v2 https://github.com/nov/rack-oauth2/pull/91
|
24
|
+
- make url-encoded the default https://github.com/nov/rack-oauth2/commit/98faf139be4f5bf9ec6134d31f65a298259d8a8b
|
25
|
+
- 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
|
@@ -28,40 +23,20 @@ http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
|
|
28
23
|
|
29
24
|
=== Bearer
|
30
25
|
|
31
|
-
Running on Heroku
|
32
|
-
https://rack-oauth2-sample.heroku.com
|
33
|
-
|
34
26
|
Source on GitHub
|
35
27
|
https://github.com/nov/rack-oauth2-sample
|
36
28
|
|
37
|
-
=== MAC
|
38
|
-
|
39
|
-
Running on Heroku
|
40
|
-
https://rack-oauth2-sample-mac.heroku.com
|
41
|
-
|
42
|
-
Source on GitHub
|
43
|
-
https://github.com/nov/rack-oauth2-sample-mac
|
44
|
-
|
45
29
|
== Sample Client
|
46
30
|
|
47
|
-
=== Common between Bearer and MAC
|
48
|
-
|
49
31
|
Authorization Request (request_type: 'code' and 'token')
|
50
32
|
https://gist.github.com/862393
|
51
33
|
|
52
34
|
Token Request (grant_type: 'client_credentials', 'password', 'authorization_code' and 'refresh_token')
|
53
35
|
https://gist.github.com/883541
|
54
36
|
|
55
|
-
=== Bearer
|
56
|
-
|
57
37
|
Resource Request (request both for resource owner resource and for client resource)
|
58
38
|
https://gist.github.com/883575
|
59
39
|
|
60
|
-
=== MAC
|
61
|
-
|
62
|
-
Resource Request (request both for resource owner resource and for client resource)
|
63
|
-
https://gist.github.com/933885
|
64
|
-
|
65
40
|
== Note on Patches/Pull Requests
|
66
41
|
|
67
42
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.2.0
|
@@ -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|
|
@@ -16,12 +16,12 @@ module Rack
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def authorization_uri(params = {})
|
19
|
+
params[:redirect_uri] ||= self.redirect_uri
|
19
20
|
params[:response_type] ||= :code
|
20
21
|
params[:response_type] = Array(params[:response_type]).join(' ')
|
21
22
|
params[:scope] = Array(params[:scope]).join(' ')
|
22
23
|
Util.redirect_uri absolute_uri_for(authorization_endpoint), :query, params.merge(
|
23
|
-
client_id: self.identifier
|
24
|
-
redirect_uri: self.redirect_uri
|
24
|
+
client_id: self.identifier
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
@@ -69,20 +69,87 @@ 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
|
-
# Using Array#
|
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) || :basic
|
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
|
145
|
+
cred = Base64.strict_encode64 [
|
146
|
+
Util.www_form_url_encode(identifier),
|
147
|
+
Util.www_form_url_encode(secret)
|
148
|
+
].join(':')
|
149
|
+
headers.merge!(
|
150
|
+
'Authorization' => "Basic #{cred}"
|
151
|
+
)
|
152
|
+
when :basic_without_www_form_urlencode
|
86
153
|
cred = ["#{identifier}:#{secret}"].pack('m').tr("\n", '')
|
87
154
|
headers.merge!(
|
88
155
|
'Authorization' => "Basic #{cred}"
|
@@ -92,9 +159,11 @@ module Rack
|
|
92
159
|
client_assertion_type: URN::ClientAssertionType::JWT_BEARER
|
93
160
|
)
|
94
161
|
# NOTE: optionally auto-generate client_assertion.
|
95
|
-
if
|
162
|
+
params[:client_assertion] = if options[:client_assertion].present?
|
163
|
+
options.delete(:client_assertion)
|
164
|
+
else
|
96
165
|
require 'json/jwt'
|
97
|
-
|
166
|
+
JSON::JWT.new(
|
98
167
|
iss: identifier,
|
99
168
|
sub: identifier,
|
100
169
|
aud: absolute_uri_for(token_endpoint),
|
@@ -111,32 +180,16 @@ module Rack
|
|
111
180
|
params.merge!(
|
112
181
|
client_id: identifier
|
113
182
|
)
|
114
|
-
http_client.
|
115
|
-
http_client.
|
183
|
+
http_client.ssl.client_key = private_key
|
184
|
+
http_client.ssl.client_cert = certificate
|
116
185
|
else
|
117
186
|
params.merge!(
|
118
187
|
client_id: identifier,
|
119
188
|
client_secret: secret
|
120
189
|
)
|
121
190
|
end
|
122
|
-
handle_response do
|
123
|
-
http_client.post(
|
124
|
-
absolute_uri_for(token_endpoint),
|
125
|
-
Util.compact_hash(params),
|
126
|
-
headers
|
127
|
-
)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
private
|
132
191
|
|
133
|
-
|
134
|
-
_endpoint_ = Util.parse_uri endpoint
|
135
|
-
_endpoint_.scheme ||= self.scheme || 'https'
|
136
|
-
_endpoint_.host ||= self.host
|
137
|
-
_endpoint_.port ||= self.port
|
138
|
-
raise 'No Host Info' unless _endpoint_.host
|
139
|
-
_endpoint_.to_s
|
192
|
+
[headers, params, http_client, options]
|
140
193
|
end
|
141
194
|
|
142
195
|
def handle_response
|
@@ -149,27 +202,30 @@ module Rack
|
|
149
202
|
end
|
150
203
|
end
|
151
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
|
+
|
152
215
|
def handle_success_response(response)
|
153
|
-
token_hash =
|
154
|
-
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
|
155
218
|
when 'bearer'
|
156
219
|
AccessToken::Bearer.new(token_hash)
|
157
|
-
when 'mac'
|
158
|
-
AccessToken::MAC.new(token_hash)
|
159
|
-
when nil
|
160
|
-
AccessToken::Legacy.new(token_hash)
|
161
220
|
else
|
162
221
|
raise 'Unknown Token Type'
|
163
222
|
end
|
164
|
-
rescue JSON::ParserError
|
165
|
-
# NOTE: Facebook support (They don't use JSON as token response)
|
166
|
-
AccessToken::Legacy.new Rack::Utils.parse_nested_query(response.body).with_indifferent_access
|
167
223
|
end
|
168
224
|
|
169
225
|
def handle_error_response(response)
|
170
|
-
error =
|
226
|
+
error = response.body.with_indifferent_access
|
171
227
|
raise Error.new(response.status, error)
|
172
|
-
rescue
|
228
|
+
rescue Faraday::ParsingError, NoMethodError
|
173
229
|
raise Error.new(response.status, error: 'Unknown', error_description: response.body)
|
174
230
|
end
|
175
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)
|
@@ -5,7 +5,7 @@ module Rack
|
|
5
5
|
module ResponseExt
|
6
6
|
def redirect?
|
7
7
|
ensure_finish do
|
8
|
-
|
8
|
+
super
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -17,13 +17,13 @@ module Rack
|
|
17
17
|
|
18
18
|
def json
|
19
19
|
ensure_finish do
|
20
|
-
@
|
20
|
+
@body
|
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,16 +44,27 @@ 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)
|
51
51
|
if auth.provided? && auth.basic?
|
52
|
-
@client_id, @client_secret = auth.credentials
|
52
|
+
@client_id, @client_secret = auth.credentials.map do |cred|
|
53
|
+
Util.www_form_url_decode cred
|
54
|
+
end
|
53
55
|
super
|
54
56
|
else
|
55
57
|
super
|
56
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
|
57
68
|
end
|
58
69
|
@grant_type = params['grant_type'].to_s
|
59
70
|
end
|
@@ -69,9 +80,9 @@ module Rack
|
|
69
80
|
def finish
|
70
81
|
attr_missing!
|
71
82
|
write Util.compact_hash(protocol_params).to_json
|
72
|
-
|
73
|
-
|
74
|
-
|
83
|
+
headers['Content-Type'] = 'application/json'
|
84
|
+
headers['Cache-Control'] = 'no-store'
|
85
|
+
headers['Pragma'] = 'no-cache'
|
75
86
|
super
|
76
87
|
end
|
77
88
|
end
|
data/lib/rack/oauth2/urn.rb
CHANGED
@@ -3,14 +3,14 @@ module Rack
|
|
3
3
|
module URN
|
4
4
|
module TokenType
|
5
5
|
JWT = 'urn:ietf:params:oauth:token-type:jwt' # RFC7519
|
6
|
-
ACCESS_TOKEN = 'urn:ietf:params:oauth:token-type:
|
7
|
-
REFRESH_TOKEN = 'urn:ietf:params:oauth:token-type:
|
6
|
+
ACCESS_TOKEN = 'urn:ietf:params:oauth:token-type:access_token' # RFC8693
|
7
|
+
REFRESH_TOKEN = 'urn:ietf:params:oauth:token-type:refresh_token' # RFC8693
|
8
8
|
end
|
9
9
|
|
10
10
|
module GrantType
|
11
11
|
JWT_BEARER = 'urn:ietf:params:oauth:grant-type:jwt-bearer' # RFC7523
|
12
12
|
SAML2_BEARER = 'urn:ietf:params:oauth:grant-type:saml2-bearer' # RFC7522
|
13
|
-
TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange' #
|
13
|
+
TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange' # RFC8693
|
14
14
|
end
|
15
15
|
|
16
16
|
module ClientAssertionType
|
data/lib/rack/oauth2/util.rb
CHANGED
@@ -4,8 +4,12 @@ module Rack
|
|
4
4
|
module OAuth2
|
5
5
|
module Util
|
6
6
|
class << self
|
7
|
-
def
|
8
|
-
URI.
|
7
|
+
def www_form_url_encode(text)
|
8
|
+
URI.encode_www_form_component(text)
|
9
|
+
end
|
10
|
+
|
11
|
+
def www_form_url_decode(text)
|
12
|
+
URI.decode_www_form_component(text)
|
9
13
|
end
|
10
14
|
|
11
15
|
def base64_encode(text)
|
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.response :logger, Rack::OAuth2.logger, {bodies: true} if debugging?
|
49
|
+
faraday.adapter Faraday.default_adapter
|
50
|
+
local_http_config&.call(faraday)
|
51
|
+
http_config&.call(faraday)
|
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'
|