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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/spec.yml +32 -0
  4. data/CHANGELOG.md +25 -0
  5. data/README.rdoc +1 -26
  6. data/VERSION +1 -1
  7. data/lib/rack/oauth2/access_token/authenticator.rb +1 -10
  8. data/lib/rack/oauth2/access_token/bearer.rb +1 -1
  9. data/lib/rack/oauth2/access_token/mtls.rb +2 -2
  10. data/lib/rack/oauth2/access_token.rb +4 -6
  11. data/lib/rack/oauth2/client.rb +97 -41
  12. data/lib/rack/oauth2/server/abstract/error.rb +2 -1
  13. data/lib/rack/oauth2/server/extension/pkce.rb +1 -1
  14. data/lib/rack/oauth2/server/rails/response_ext.rb +5 -5
  15. data/lib/rack/oauth2/server/resource/error.rb +4 -4
  16. data/lib/rack/oauth2/server/resource.rb +0 -1
  17. data/lib/rack/oauth2/server/token/error.rb +3 -1
  18. data/lib/rack/oauth2/server/token.rb +16 -5
  19. data/lib/rack/oauth2/urn.rb +3 -3
  20. data/lib/rack/oauth2/util.rb +6 -2
  21. data/lib/rack/oauth2.rb +11 -10
  22. data/rack-oauth2.gemspec +7 -5
  23. data/spec/helpers/webmock_helper.rb +8 -2
  24. data/spec/rack/oauth2/access_token/authenticator_spec.rb +2 -22
  25. data/spec/rack/oauth2/access_token/bearer_spec.rb +2 -2
  26. data/spec/rack/oauth2/access_token_spec.rb +0 -17
  27. data/spec/rack/oauth2/client_spec.rb +173 -75
  28. data/spec/rack/oauth2/oauth2_spec.rb +0 -43
  29. data/spec/rack/oauth2/server/authorize/error_spec.rb +6 -6
  30. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +2 -2
  31. data/spec/rack/oauth2/server/resource/bearer_spec.rb +9 -9
  32. data/spec/rack/oauth2/server/resource/error_spec.rb +21 -21
  33. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +2 -2
  34. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +32 -2
  35. data/spec/rack/oauth2/server/token/error_spec.rb +8 -8
  36. data/spec/rack/oauth2/server/token_spec.rb +72 -3
  37. data/spec/rack/oauth2/util_spec.rb +8 -3
  38. metadata +47 -51
  39. data/.travis.yml +0 -7
  40. data/lib/rack/oauth2/access_token/legacy.rb +0 -19
  41. data/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb +0 -17
  42. data/lib/rack/oauth2/access_token/mac/signature.rb +0 -34
  43. data/lib/rack/oauth2/access_token/mac/verifier.rb +0 -44
  44. data/lib/rack/oauth2/access_token/mac.rb +0 -103
  45. data/lib/rack/oauth2/debugger/request_filter.rb +0 -30
  46. data/lib/rack/oauth2/debugger.rb +0 -3
  47. data/lib/rack/oauth2/server/resource/mac/error.rb +0 -24
  48. data/lib/rack/oauth2/server/resource/mac.rb +0 -36
  49. data/spec/mock_response/tokens/legacy.json +0 -5
  50. data/spec/mock_response/tokens/legacy.txt +0 -1
  51. data/spec/mock_response/tokens/legacy_without_expires_in.txt +0 -1
  52. data/spec/mock_response/tokens/mac.json +0 -8
  53. data/spec/rack/oauth2/access_token/legacy_spec.rb +0 -23
  54. data/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb +0 -28
  55. data/spec/rack/oauth2/access_token/mac/signature_spec.rb +0 -59
  56. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +0 -25
  57. data/spec/rack/oauth2/access_token/mac_spec.rb +0 -141
  58. data/spec/rack/oauth2/debugger/request_filter_spec.rb +0 -33
  59. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +0 -52
  60. data/spec/rack/oauth2/server/resource/mac_spec.rb +0 -119
  61. /data/spec/mock_response/{blank → blank.txt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c09e887a3c902ebbbfd1b2a1698d8a4d68d28e18e75616c629dd75e981e2a9d2
4
- data.tar.gz: c0142a2c05df047f0d8f1e9ac11f428983d27a8945d5ae5be213be41b5615e20
3
+ metadata.gz: 45ba67ac4566f374465673cc5711e71c15006bbe966531a4c1de2473206879b2
4
+ data.tar.gz: 56f8718f283533c369b1743dfd86499e49e5d828a83ac060fa919fac57a935d2
5
5
  SHA512:
6
- metadata.gz: ab1002bdd363b2edab71e8eeebd9872bca8ea2be6ad2a99875543974a2b85340ddcb42fc4ddf22f779b18429dc48a9d36fd91e9059391b76b537c04293ac2056
7
- data.tar.gz: bdffd308340040287a3a8777cdaaaa9de58873d4d27e080dc719b4715ca53fd413bc726f19382b63cd086ad3dd47ac139a665f0acfcd25d2bb2a5e266d8dafce
6
+ metadata.gz: 63316467536c2c98cddea9b2b7907b3ff5fd6b53b892bd338709e1f7a6b014aa4dc20d71b12cd01ffac502c1ab0964218aac7ff6a0e81141ff8aa10e80557cdd
7
+ data.tar.gz: 97e685531853c4837a0e86636c865827033e25f646c4572d254e2584a811f937faa6dc7fe780742814bd9657066c9fc16394723ba87029605761d5acf2d490f7
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: nov
@@ -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 and MAC token type are supported.
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.12.0
1
+ 2.2.0
@@ -6,18 +6,9 @@ module Rack
6
6
  @token = token
7
7
  end
8
8
 
9
- # Callback called in HTTPClient (before sending a request)
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
@@ -3,7 +3,7 @@ module Rack
3
3
  class AccessToken
4
4
  class Bearer < AccessToken
5
5
  def authenticate(request)
6
- request.header["Authorization"] = "Bearer #{access_token}"
6
+ request.headers["Authorization"] = "Bearer #{access_token}"
7
7
  end
8
8
 
9
9
  def to_mtls(attributes = {})
@@ -7,8 +7,8 @@ module Rack
7
7
  def initialize(attributes = {})
8
8
  super
9
9
  self.token_type = :bearer
10
- httpclient.ssl_config.client_key = private_key
11
- httpclient.ssl_config.client_cert = certificate
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: :httpclient
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 httpclient
22
- @httpclient ||= Rack::OAuth2.http_client("#{self.class} (#{VERSION})") do |config|
23
- config.request_filter << Authenticator.new(self)
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'
@@ -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 = {}, @grant.as_json
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#estract_options! for backward compatibility.
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 params[:client_assertion].blank?
162
+ params[:client_assertion] = if options[:client_assertion].present?
163
+ options.delete(:client_assertion)
164
+ else
96
165
  require 'json/jwt'
97
- params[:client_assertion] = JSON::JWT.new(
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.ssl_config.client_key = private_key
115
- http_client.ssl_config.client_cert = certificate
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
- def absolute_uri_for(endpoint)
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 = JSON.parse(response.body).with_indifferent_access
154
- case (@forced_token_type || token_hash[:token_type]).try(:downcase)
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 = JSON.parse(response.body).with_indifferent_access
226
+ error = response.body.with_indifferent_access
171
227
  raise Error.new(response.status, error)
172
- rescue JSON::ParserError
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.header['Content-Type'] = 'application/json'
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.try(:to_sym)
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
- @response.redirect?
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
- @response.body
20
+ @body
21
21
  end
22
22
  end
23
23
 
24
- def header
24
+ def headers
25
25
  ensure_finish do
26
- @header
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, @header, @response = finish unless finished?
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
- header = response.header['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\""
16
+ headers = response.headers['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\""
17
17
  if ErrorMethods::DEFAULT_DESCRIPTION.keys.include?(error)
18
- header << ", error=\"#{error}\""
19
- header << ", error_description=\"#{description}\"" if description.present?
20
- header << ", error_uri=\"#{uri}\"" if uri.present?
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
@@ -52,4 +52,3 @@ end
52
52
 
53
53
  require 'rack/oauth2/server/resource/error'
54
54
  require 'rack/oauth2/server/resource/bearer'
55
- require 'rack/oauth2/server/resource/mac'
@@ -8,7 +8,9 @@ module Rack
8
8
  class Unauthorized < Abstract::Unauthorized
9
9
  def finish
10
10
  super do |response|
11
- response.header['WWW-Authenticate'] = 'Basic realm="OAuth2 Token Endpoint"'
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
- header['Content-Type'] = 'application/json'
73
- header['Cache-Control'] = 'no-store'
74
- header['Pragma'] = 'no-cache'
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
@@ -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:access-token' # draft-ietf-oauth-token-exchange
7
- REFRESH_TOKEN = 'urn:ietf:params:oauth:token-type:refresh-token' # draft-ietf-oauth-token-exchange
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' # draft-ietf-oauth-token-exchange
13
+ TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange' # RFC8693
14
14
  end
15
15
 
16
16
  module ClientAssertionType
@@ -4,8 +4,12 @@ module Rack
4
4
  module OAuth2
5
5
  module Util
6
6
  class << self
7
- def rfc3986_encode(text)
8
- URI.encode(text, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
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 'httpclient'
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
- _http_client_ = HTTPClient.new(
44
- agent_name: agent_name
45
- )
46
- http_config.try(:call, _http_client_)
47
- local_http_config.try(:call, _http_client_) unless local_http_config.nil?
48
- _http_client_.request_filter << Debugger::RequestFilter.new if debugging?
49
- _http_client_
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'