rodauth-oauth 0.9.2 → 0.9.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2514b45f82f9e8dda98f15dc2c1ccc0eeba306c9d1ee40e6fa47e4999d766c1c
4
- data.tar.gz: d68579829772121a157b7bd654fb40999921af46673910caa21892462655ed0e
3
+ metadata.gz: 79fa7abfcf7ea1c0a2594f92bfd7a59e53769dec5a7221a22f740b37471e6e07
4
+ data.tar.gz: 9f7e8ce4370d44d985940d46d569e3192c35e53cb6e3841094517e64258b2b1a
5
5
  SHA512:
6
- metadata.gz: 8121458a789119610c920c835fc99cde76d4eca41fb7bb48acbe9c1e2f4be89f68c9370235335d7dc8c6b3b715b6825a4d77bafbda37551464ebf35a516f55de
7
- data.tar.gz: bdd2c1d2bee336459186606b2bfb293cd690333a58c421798155e6bc53e418b71bbd142ac19e48ddcff701f28eaaa6c65c8d045c715a7f84690fb5dd6865ddbe
6
+ metadata.gz: 520a85416c418f93615a471133201c7ec6dd5c16ff9d697a6ca87b609084b58c7b9799c5d3c7a8d02a4fc68ca9750c9ef41dd07dde17c1e1153f0cec8e58f3c1
7
+ data.tar.gz: 8e7ebc28ba158f43b5226a2de98fc76de8c81e8a8c87dbaa95a69050eed96793e487666389b60be6694437c298fdf23f183a1df098983eeec5f5549df0321c7c
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Rodauth::Oauth
2
2
 
3
- [![pipeline status](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/pipelines?page=1&ref=master)
3
+ [![Gem Version](https://badge.fury.io/rb/rodauth-oauth.svg)](http://rubygems.org/gems/rodauth-oauth)
4
+ [![pipeline status](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/pipelines?page=1&scope=all&ref=master)
4
5
  [![coverage report](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/coverage.svg?job=coverage)](https://honeyryderchuck.gitlab.io/rodauth-oauth/coverage/#_AllFiles)
5
6
 
6
7
  This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framework](https://tools.ietf.org/html/rfc6749) for an authorization server.
@@ -0,0 +1,9 @@
1
+ ### 0.9.2 (30/05/2022)
2
+
3
+ #### Bugfixes
4
+
5
+ * `oauth_jwt`: new access tokens generated via the `"refresh_token"` grant type are now JWT (it was falling back to non JWT behaviour);
6
+ * `oidc`: a new `id_token` is now generated via the `"refresh_token"` grant type with "rotation" policy (it was being omitted from the response);
7
+ * `oidc`: fixing calculation of `"auth_time"` claim, which (as per RFC) needs to stay the same across first authentication and subsequent `"refresh_token"` requests;
8
+ * it requires a new db column (default: `"auth_time"`, datetime) in the `"oauth_tokens"` database;
9
+ * hash-column `"refresh_token"` will now expose the refresh token (instead of the hash column version) in the `"refresh_token"` grant type response payload (only happened in "non-rotation" refresh token mode).
@@ -77,6 +77,7 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
77
77
  t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
78
78
  # uncomment to use OIDC nonce
79
79
  # t.string :nonce
80
+ # t.datetime :auth_time
80
81
  end
81
82
  end
82
83
  end
@@ -426,32 +426,40 @@ module Rodauth
426
426
  }.merge(params)
427
427
 
428
428
  rescue_from_uniqueness_error do
429
- token = oauth_unique_id_generator
429
+ access_token = _generate_access_token(create_params)
430
+ refresh_token = _generate_refresh_token(create_params) if should_generate_refresh_token
431
+ oauth_token = _store_oauth_token(create_params)
432
+ oauth_token[oauth_tokens_token_column] = access_token
433
+ oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
434
+ oauth_token
435
+ end
436
+ end
430
437
 
431
- if oauth_tokens_token_hash_column
432
- create_params[oauth_tokens_token_hash_column] = generate_token_hash(token)
433
- else
434
- create_params[oauth_tokens_token_column] = token
435
- end
438
+ def _generate_access_token(params = {})
439
+ token = oauth_unique_id_generator
436
440
 
437
- refresh_token = nil
438
- if should_generate_refresh_token
439
- refresh_token = oauth_unique_id_generator
441
+ if oauth_tokens_token_hash_column
442
+ params[oauth_tokens_token_hash_column] = generate_token_hash(token)
443
+ else
444
+ params[oauth_tokens_token_column] = token
445
+ end
440
446
 
441
- if oauth_tokens_refresh_token_hash_column
442
- create_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
443
- else
444
- create_params[oauth_tokens_refresh_token_column] = refresh_token
445
- end
446
- end
447
- oauth_token = _generate_oauth_token(create_params)
448
- oauth_token[oauth_tokens_token_column] = token
449
- oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
450
- oauth_token
447
+ token
448
+ end
449
+
450
+ def _generate_refresh_token(params)
451
+ token = oauth_unique_id_generator
452
+
453
+ if oauth_tokens_refresh_token_hash_column
454
+ params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(token)
455
+ else
456
+ params[oauth_tokens_refresh_token_column] = token
451
457
  end
458
+
459
+ token
452
460
  end
453
461
 
454
- def _generate_oauth_token(params = {})
462
+ def _store_oauth_token(params = {})
455
463
  ds = db[oauth_tokens_table]
456
464
 
457
465
  if __one_oauth_token_per_account
@@ -577,43 +585,24 @@ module Rodauth
577
585
 
578
586
  rescue_from_uniqueness_error do
579
587
  oauth_tokens_ds = db[oauth_tokens_table]
580
- token = oauth_unique_id_generator
588
+ access_token = _generate_access_token(update_params)
581
589
 
582
- if oauth_tokens_token_hash_column
583
- update_params[oauth_tokens_token_hash_column] = generate_token_hash(token)
590
+ if oauth_refresh_token_protection_policy == "rotation"
591
+ update_params = {
592
+ **update_params,
593
+ oauth_tokens_oauth_token_id_column => oauth_token[oauth_tokens_id_column],
594
+ oauth_tokens_account_id_column => oauth_token[oauth_tokens_account_id_column],
595
+ oauth_tokens_scopes_column => oauth_token[oauth_tokens_scopes_column]
596
+ }
597
+
598
+ refresh_token = _generate_refresh_token(update_params)
584
599
  else
585
- update_params[oauth_tokens_token_column] = token
600
+ refresh_token = param("refresh_token")
586
601
  end
602
+ oauth_token = __update_and_return__(oauth_tokens_ds, update_params)
587
603
 
588
- oauth_token = if oauth_refresh_token_protection_policy == "rotation"
589
- insert_params = {
590
- **update_params,
591
- oauth_tokens_oauth_token_id_column => oauth_token[oauth_tokens_id_column],
592
- oauth_tokens_scopes_column => oauth_token[oauth_tokens_scopes_column]
593
- }
594
-
595
- refresh_token = oauth_unique_id_generator
596
-
597
- if oauth_tokens_refresh_token_hash_column
598
- insert_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
599
- else
600
- insert_params[oauth_tokens_refresh_token_column] = refresh_token
601
- end
602
-
603
- # revoke the refresh token
604
- oauth_tokens_ds.where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
605
- .update(oauth_tokens_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
606
-
607
- insert_params[oauth_tokens_oauth_token_id_column] = oauth_token[oauth_tokens_id_column]
608
- __insert_and_return__(oauth_tokens_ds, oauth_tokens_id_column, insert_params)
609
- else
610
- # includes none
611
- ds = oauth_tokens_ds.where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
612
- __update_and_return__(ds, update_params)
613
- end
614
-
615
- oauth_token[oauth_tokens_token_column] = token
616
- oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
604
+ oauth_token[oauth_tokens_token_column] = access_token
605
+ oauth_token[oauth_tokens_refresh_token_column] = refresh_token
617
606
  oauth_token
618
607
  end
619
608
  end
@@ -66,7 +66,6 @@ module Rodauth
66
66
  :jwt_encode,
67
67
  :jwt_decode,
68
68
  :jwks_set,
69
- :last_account_login_at,
70
69
  :generate_jti
71
70
  )
72
71
 
@@ -99,12 +98,6 @@ module Rodauth
99
98
 
100
99
  private
101
100
 
102
- unless method_defined?(:last_account_login_at)
103
- def last_account_login_at
104
- nil
105
- end
106
- end
107
-
108
101
  def issuer
109
102
  @issuer ||= oauth_jwt_token_issuer || authorization_server_url
110
103
  end
@@ -175,41 +168,38 @@ module Rodauth
175
168
 
176
169
  # /token
177
170
 
178
- def generate_oauth_token(params = {}, should_generate_refresh_token = true)
179
- create_params = {
180
- oauth_grants_expires_in_column => Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_token_expires_in)
181
- }.merge(params)
182
-
183
- oauth_token = rescue_from_uniqueness_error do
184
- if should_generate_refresh_token
185
- refresh_token = oauth_unique_id_generator
186
-
187
- if oauth_tokens_refresh_token_hash_column
188
- create_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
189
- else
190
- create_params[oauth_tokens_refresh_token_column] = refresh_token
191
- end
192
- end
171
+ def create_oauth_token_from_token(oauth_token, update_params)
172
+ otoken = super
173
+ access_token = _generate_jwt_access_token(otoken)
174
+ otoken[oauth_tokens_token_column] = access_token
175
+ otoken
176
+ end
193
177
 
194
- _generate_oauth_token(create_params)
195
- end
178
+ def generate_oauth_token(params = {}, should_generate_refresh_token = true)
179
+ oauth_token = super
180
+ access_token = _generate_jwt_access_token(oauth_token)
181
+ oauth_token[oauth_tokens_token_column] = access_token
182
+ oauth_token
183
+ end
196
184
 
185
+ def _generate_jwt_access_token(oauth_token)
197
186
  claims = jwt_claims(oauth_token)
198
187
 
199
188
  # one of the points of using jwt is avoiding database lookups, so we put here all relevant
200
189
  # token data.
201
190
  claims[:scope] = oauth_token[oauth_tokens_scopes_column]
202
191
 
203
- token = jwt_encode(claims)
192
+ jwt_encode(claims)
193
+ end
204
194
 
205
- oauth_token[oauth_tokens_token_column] = token
206
- oauth_token
195
+ def _generate_access_token(*)
196
+ # no op
207
197
  end
208
198
 
209
199
  def jwt_claims(oauth_token)
210
200
  issued_at = Time.now.to_i
211
201
 
212
- claims = {
202
+ {
213
203
  iss: issuer, # issuer
214
204
  iat: issued_at, # issued at
215
205
  #
@@ -227,10 +217,6 @@ module Rodauth
227
217
  exp: issued_at + oauth_token_expires_in,
228
218
  aud: (oauth_jwt_audience || oauth_application[oauth_applications_client_id_column])
229
219
  }
230
-
231
- claims[:auth_time] = last_account_login_at.to_i if last_account_login_at
232
-
233
- claims
234
220
  end
235
221
 
236
222
  def jwt_subject(oauth_token)
@@ -74,6 +74,7 @@ module Rodauth
74
74
 
75
75
  auth_value_method :oauth_grants_nonce_column, :nonce
76
76
  auth_value_method :oauth_tokens_nonce_column, :nonce
77
+ auth_value_method :oauth_tokens_auth_time_column, :auth_time
77
78
 
78
79
  translatable_method :invalid_scope_message, "The Access Token expired"
79
80
 
@@ -341,8 +342,7 @@ module Rodauth
341
342
 
342
343
  # Time when the End-User authentication occurred.
343
344
  #
344
- # Sounds like the same as issued at claim.
345
- id_token_claims[:auth_time] = id_token_claims[:iat]
345
+ id_token_claims[:auth_time] = oauth_token[oauth_tokens_auth_time_column].to_i
346
346
 
347
347
  account = db[accounts_table].where(account_id_column => oauth_token[oauth_tokens_account_id_column]).first
348
348
 
@@ -488,7 +488,7 @@ module Rodauth
488
488
  end
489
489
  end
490
490
 
491
- scope_claims.unshift("auth_time") if last_account_login_at
491
+ scope_claims.unshift("auth_time")
492
492
 
493
493
  response_types_supported = metadata[:response_types_supported]
494
494
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rodauth
4
4
  module OAuth
5
- VERSION = "0.9.2"
5
+ VERSION = "0.9.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-oauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-11 00:00:00.000000000 Z
11
+ date: 2022-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rodauth
@@ -59,6 +59,7 @@ extra_rdoc_files:
59
59
  - doc/release_notes/0_9_0.md
60
60
  - doc/release_notes/0_9_1.md
61
61
  - doc/release_notes/0_9_2.md
62
+ - doc/release_notes/0_9_3.md
62
63
  files:
63
64
  - CHANGELOG.md
64
65
  - LICENSE.txt
@@ -89,6 +90,7 @@ files:
89
90
  - doc/release_notes/0_9_0.md
90
91
  - doc/release_notes/0_9_1.md
91
92
  - doc/release_notes/0_9_2.md
93
+ - doc/release_notes/0_9_3.md
92
94
  - lib/generators/rodauth/oauth/install_generator.rb
93
95
  - lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
94
96
  - lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb