rodauth-oauth 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
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