rodauth-oauth 0.5.1 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 366fa7201a8cb26525b2abdfab0c4108a4afbef4fa8697cf57e874919eda2afd
4
- data.tar.gz: 958b9fd8b4cd2996a85b96fac6dff6a6b35832adcdaed4d81e20842041a1299e
3
+ metadata.gz: 0e6a9da692805069b0250b975d86c02f81af6bd1cc80ce24ecbc92ea6d3fef14
4
+ data.tar.gz: c4996d52e4119f6a2d8fde3f0149f8deadb609324fb894c99d5fbcdf836efd4c
5
5
  SHA512:
6
- metadata.gz: fb496f7d438c0447ba4ef899f9ec37549cea355fb5c670818cd040970c1316c13442caa58aebc4ea66cd92f2f369d6ff7c39b502190e2d4fec2f95d5e27b4279
7
- data.tar.gz: 73048d860285b29056ade97d9092103e2cae18fa9967df603ddce9c83c10fd5c44891e7282f3195d0b79b2d73bf12c748483a811f404d50fb29df40da26a6bf4
6
+ metadata.gz: d8ec7872e8997019182b04a40c11f5db1e272de0bcceada11f870d706f2646aca911239d1f01876f26126e0936938a6ea233f312304410ce0c35d3964ebe7f1f
7
+ data.tar.gz: 4a5df07c4da7c30803d7cb513c87ca6296b205dcdae89eb3ab475aa6780a4b37acd0e3b3bae5d43372eb8f9d3a92bd30a761ad7cda269d18d7bc16658f719768
data/CHANGELOG.md CHANGED
@@ -2,6 +2,55 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ### 0.7.1 (05/12/2021)
6
+
7
+ #### Improvements
8
+
9
+ * Adapted the `rodauth-i18n` configuration to comply with the guidelines for `v0.2.0` (which is the defacto minimmal supported version).
10
+
11
+ #### Bugfixes
12
+
13
+ * `convert_timestamp` was removed from the templates, as it's private API.
14
+ * Several missing or wrong URLs in templates fixed (authorize form was wrongly processing scopes when none was selected).
15
+
16
+ ### 0.7.0 (02/12/2021)
17
+
18
+ #### Features
19
+
20
+ * Internationalization (i18n) support by hooking on [rodauth-i18n](https://github.com/janko/rodauth-i18n).
21
+ * Sets all text using `translatable_method`.
22
+ * Provides english translations for all `rodauth-oauth` related user facing text.
23
+
24
+ #### Improvements
25
+
26
+ * Enable CORS requests for OpenID configuration endpoint (@ianks)
27
+ * Introspect endpoint now exposes the `exp` token property (@gmanley)
28
+
29
+ #### Bugfixes
30
+
31
+ * on rotation policy, although the first refresh token was invalidated, a new one wasn't being provided. This change allows a new refresh token to be generated and exposed in the response (@gmanley)
32
+
33
+ #### Chore
34
+
35
+ Setting `rodauth` minimal supported version to `2.0.0`.
36
+
37
+ ### 0.6.1 (08/09/2021)
38
+
39
+ #### Bugfixes
40
+
41
+ * Fixed rails view templates escaping.
42
+ * Fixed declaration of authorize template in the generator.
43
+
44
+ ### 0.6.0 (21/05/2021)
45
+
46
+ ### Improvements
47
+
48
+ * RBS signatures
49
+
50
+ ### Chore
51
+
52
+ * Ruby 3 and Truffleruby are now officially supported and tested in CI.
53
+
5
54
  ### 0.5.1 (19/03/2021)
6
55
 
7
56
  #### Improvements
data/README.md CHANGED
@@ -173,7 +173,7 @@ puts payload #=> {"access_token" => "awr23f3h8f9d2h89...", "token_type" => "Bear
173
173
 
174
174
  #### Revoking tokens
175
175
 
176
- Token revocation can be done both by the idenntity owner or the application owner, and can therefore be done either online (browser-based form) or server-to-server. Here's an example using server-to-server:
176
+ Token revocation can be done both by the identity owner or the application owner, and can therefore be done either online (browser-based form) or server-to-server. Here's an example using server-to-server:
177
177
 
178
178
  ```ruby
179
179
  require "httpx"
@@ -516,7 +516,7 @@ payload = json.parse(response.to_s)
516
516
  puts payload #=> {
517
517
  # "access_token" => ....
518
518
  # "mac_key" => ....
519
- # "mac_algorithm" =>
519
+ # "mac_algorithm" =>
520
520
  ```
521
521
 
522
522
  which you'll be able to use to generate the mac signature to send in the "Authorization" header.
@@ -565,7 +565,7 @@ plugin :rodauth do
565
565
  enable :oauth_jwt
566
566
  oauth_jwt_key rsa_private
567
567
  oauth_jwt_public_key rsa_public
568
- oauth_jwt_algorithm "RS256"
568
+ oauth_jwt_algorithm "RS256"
569
569
  end
570
570
  ```
571
571
 
@@ -581,7 +581,7 @@ plugin :rodauth do
581
581
  enable :oauth_jwt
582
582
  oauth_jwt_jwk_key rsa_private
583
583
  oauth_jwt_jwk_public_key rsa_public
584
- oauth_jwt_jwk_algorithm "RS256"
584
+ oauth_jwt_jwk_algorithm "RS256"
585
585
  end
586
586
  ```
587
587
 
@@ -627,17 +627,25 @@ puts payload #=> {
627
627
 
628
628
  You'll still need the "oauth_tokens" table, however you can remove the "token" column.
629
629
 
630
+ #### Internationalization (i18n)
631
+
632
+ `rodauth-oauth` supports translating all user-facing text found in all pages and forms, by integrating with [rodauth-i18n](https://github.com/janko/rodauth-i18n). Just set it up in your application and `rodauth` configuration.
633
+
634
+ Default translations shipping with `rodauth-oauth` can be found [in this directory](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/locales). If they're not available for the languages you'd like to support, consider getting them translated from the english text, and contributing them to this repository via a Merge Request.
635
+
636
+ (This feature is available since `v0.7`.)
637
+
630
638
  #### Caveats
631
639
 
632
640
  Although very handy for the mentioned use case, one can't revoke a JWT token on demand (it must expire first).
633
641
 
634
642
  ## Ruby support policy
635
643
 
636
- The minimum Ruby version required to run `rodauth-oauth` is 2.3 . Besides that, it should support all rubies that rodauth and roda support, including JRuby and (potentially, I don't know yet) truffleruby.
644
+ The minimum Ruby version required to run `rodauth-oauth` is 2.3 . Besides that, it should support all rubies that rodauth and roda support, including JRuby and truffleruby.
637
645
 
638
- ### JRuby
646
+ ### Rails
639
647
 
640
- If you're interested in using this library in rails, be sure to check `rodauth-rails` policy, as it supports rails 5.2 upwards.
648
+ If you're interested in using this library with rails, be sure to check `rodauth-rails` policy, as it supports rails 5.2 upwards.
641
649
 
642
650
  ## Development
643
651
 
@@ -646,4 +654,3 @@ After checking out the repo, run `bundle install` to install dependencies. Then,
646
654
  ## Contributing
647
655
 
648
656
  Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/honeyryderchuck/rodauth-oauth.
649
-
@@ -9,7 +9,7 @@ module Rodauth::OAuth
9
9
  source_root "#{__dir__}/templates"
10
10
  namespace "rodauth:oauth:views"
11
11
 
12
- DEFAULT = %w[oauth_authorize].freeze
12
+ DEFAULT = %w[authorize].freeze
13
13
  VIEWS = {
14
14
  oauth_authorize: DEFAULT,
15
15
  oauth_applications: %w[oauth_applications oauth_application new_oauth_application]
@@ -9,7 +9,7 @@ require "rodauth/oauth/ttl_store"
9
9
  require "rodauth/oauth/database_extensions"
10
10
 
11
11
  module Rodauth
12
- Feature.define(:oauth) do
12
+ Feature.define(:oauth, :Oauth) do
13
13
  # RUBY EXTENSIONS
14
14
  unless Regexp.method_defined?(:match?)
15
15
  # If you wonder why this is there: the oauth feature uses a refinement to enhance the
@@ -168,24 +168,24 @@ module Rodauth
168
168
  auth_value_method :oauth_token_type, "bearer"
169
169
  auth_value_method :oauth_refresh_token_protection_policy, "none" # can be: none, sender_constrained, rotation
170
170
 
171
- auth_value_method :invalid_client_message, "Invalid client"
172
- auth_value_method :invalid_grant_type_message, "Invalid grant type"
173
- auth_value_method :invalid_grant_message, "Invalid grant"
174
- auth_value_method :invalid_scope_message, "Invalid scope"
171
+ translatable_method :invalid_client_message, "Invalid client"
172
+ translatable_method :invalid_grant_type_message, "Invalid grant type"
173
+ translatable_method :invalid_grant_message, "Invalid grant"
174
+ translatable_method :invalid_scope_message, "Invalid scope"
175
175
 
176
- auth_value_method :invalid_url_message, "Invalid URL"
177
- auth_value_method :unsupported_token_type_message, "Invalid token type hint"
176
+ translatable_method :invalid_url_message, "Invalid URL"
177
+ translatable_method :unsupported_token_type_message, "Invalid token type hint"
178
178
 
179
- auth_value_method :unique_error_message, "is already in use"
180
- auth_value_method :null_error_message, "is not filled"
181
- auth_value_method :already_in_use_message, "error generating unique token"
179
+ translatable_method :unique_error_message, "is already in use"
180
+ translatable_method :null_error_message, "is not filled"
181
+ translatable_method :already_in_use_message, "error generating unique token"
182
182
  auth_value_method :already_in_use_error_code, "invalid_request"
183
183
 
184
184
  # PKCE
185
185
  auth_value_method :code_challenge_required_error_code, "invalid_request"
186
- auth_value_method :code_challenge_required_message, "code challenge required"
186
+ translatable_method :code_challenge_required_message, "code challenge required"
187
187
  auth_value_method :unsupported_transform_algorithm_error_code, "invalid_request"
188
- auth_value_method :unsupported_transform_algorithm_message, "transform algorithm not supported"
188
+ translatable_method :unsupported_transform_algorithm_message, "transform algorithm not supported"
189
189
 
190
190
  # METADATA
191
191
  auth_value_method :oauth_metadata_service_documentation, nil
@@ -466,10 +466,6 @@ module Rodauth
466
466
  end
467
467
  end
468
468
 
469
- def initialize(scope)
470
- @scope = scope
471
- end
472
-
473
469
  def scopes
474
470
  scope = request.params["scope"]
475
471
  case scope
@@ -568,13 +564,14 @@ module Rodauth
568
564
  self.class.__send__(:include, Rodauth::OAuth::ExtendDatabase(db))
569
565
 
570
566
  # Check whether we can reutilize db entries for the same account / application pair
571
- one_oauth_token_per_account = begin
572
- db.indexes(oauth_tokens_table).values.any? do |definition|
573
- definition[:unique] &&
574
- definition[:columns] == oauth_tokens_unique_columns
575
- end
567
+ one_oauth_token_per_account = db.indexes(oauth_tokens_table).values.any? do |definition|
568
+ definition[:unique] &&
569
+ definition[:columns] == oauth_tokens_unique_columns
576
570
  end
571
+
577
572
  self.class.send(:define_method, :__one_oauth_token_per_account) { one_oauth_token_per_account }
573
+
574
+ i18n_register(File.expand_path(File.join(__dir__, "..", "..", "..", "locales"))) if features.include?(:i18n)
578
575
  end
579
576
 
580
577
  def use_date_arithmetic?
@@ -1108,6 +1105,14 @@ module Rodauth
1108
1105
  oauth_tokens_scopes_column => oauth_token[oauth_tokens_scopes_column]
1109
1106
  }
1110
1107
 
1108
+ refresh_token = oauth_unique_id_generator
1109
+
1110
+ if oauth_tokens_refresh_token_hash_column
1111
+ insert_params[oauth_tokens_refresh_token_hash_column] = generate_token_hash(refresh_token)
1112
+ else
1113
+ insert_params[oauth_tokens_refresh_token_column] = refresh_token
1114
+ end
1115
+
1111
1116
  # revoke the refresh token
1112
1117
  oauth_tokens_ds.where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
1113
1118
  .update(oauth_tokens_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
@@ -1121,6 +1126,7 @@ module Rodauth
1121
1126
  end
1122
1127
 
1123
1128
  oauth_token[oauth_tokens_token_column] = token
1129
+ oauth_token[oauth_tokens_refresh_token_column] = refresh_token if refresh_token
1124
1130
  oauth_token
1125
1131
  end
1126
1132
  end
@@ -1146,7 +1152,8 @@ module Rodauth
1146
1152
  scope: token[oauth_tokens_scopes_column],
1147
1153
  client_id: oauth_application[oauth_applications_client_id_column],
1148
1154
  # username
1149
- token_type: oauth_token_type
1155
+ token_type: oauth_token_type,
1156
+ exp: token[oauth_tokens_expires_in_column].to_i
1150
1157
  }
1151
1158
  end
1152
1159
 
@@ -1,7 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Rodauth
4
- Feature.define(:oauth_http_mac) do
4
+ Feature.define(:oauth_http_mac, :OauthHttpMac) do
5
5
  unless String.method_defined?(:delete_prefix)
6
6
  module PrefixExtensions
7
7
  refine(String) do
@@ -3,7 +3,7 @@
3
3
  require "rodauth/oauth/ttl_store"
4
4
 
5
5
  module Rodauth
6
- Feature.define(:oauth_jwt) do
6
+ Feature.define(:oauth_jwt, :OauthJwt) do
7
7
  depends :oauth
8
8
 
9
9
  JWKS = OAuth::TtlStore.new
@@ -33,8 +33,8 @@ module Rodauth
33
33
  auth_value_method :oauth_jwt_jwe_copyright, nil
34
34
  auth_value_method :oauth_jwt_audience, nil
35
35
 
36
- auth_value_method :request_uri_not_supported_message, "request uri is unsupported"
37
- auth_value_method :invalid_request_object_message, "request object is invalid"
36
+ translatable_method :request_uri_not_supported_message, "request uri is unsupported"
37
+ translatable_method :invalid_request_object_message, "request object is invalid"
38
38
 
39
39
  auth_value_methods(
40
40
  :jwt_encode,
@@ -3,7 +3,7 @@
3
3
  require "onelogin/ruby-saml"
4
4
 
5
5
  module Rodauth
6
- Feature.define(:oauth_saml) do
6
+ Feature.define(:oauth_saml, :OauthSaml) do
7
7
  depends :oauth
8
8
 
9
9
  auth_value_method :oauth_saml_cert_fingerprint, "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D"
@@ -1,7 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Rodauth
4
- Feature.define(:oidc) do
4
+ Feature.define(:oidc, :Oidc) do
5
5
  # https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
6
6
  OIDC_SCOPES_MAP = {
7
7
  "profile" => %i[name family_name given_name middle_name nickname preferred_username
@@ -68,7 +68,7 @@ module Rodauth
68
68
  auth_value_method :oauth_grants_nonce_column, :nonce
69
69
  auth_value_method :oauth_tokens_nonce_column, :nonce
70
70
 
71
- auth_value_method :invalid_scope_message, "The Access Token expired"
71
+ translatable_method :invalid_scope_message, "The Access Token expired"
72
72
 
73
73
  auth_value_method :webfinger_relation, "http://openid.net/specs/connect/1.0/issuer"
74
74
 
@@ -186,6 +186,8 @@ module Rodauth
186
186
 
187
187
  def openid_configuration(alt_issuer = nil)
188
188
  request.on(".well-known/openid-configuration") do
189
+ allow_cors(request)
190
+
189
191
  request.get do
190
192
  json_response_success(openid_configuration_body(alt_issuer), cache: true)
191
193
  end
@@ -493,5 +495,15 @@ module Rodauth
493
495
  (val.respond_to?(:empty?) && val.empty?)
494
496
  end
495
497
  end
498
+
499
+ def allow_cors(request)
500
+ return unless request.request_method == "OPTIONS"
501
+
502
+ response["Access-Control-Allow-Origin"] = "*"
503
+ response["Access-Control-Allow-Methods"] = "GET, OPTIONS"
504
+ response["Access-Control-Max-Age"] = "3600"
505
+ response.status = 200
506
+ request.halt
507
+ end
496
508
  end
497
509
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rodauth
4
4
  module OAuth
5
- VERSION = "0.5.1"
5
+ VERSION = "0.7.1"
6
6
  end
7
7
  end
data/locales/en.yml ADDED
@@ -0,0 +1,34 @@
1
+ en:
2
+ rodauth:
3
+ require_authorization_error_flash: "Please authorize to continue"
4
+ create_oauth_application_error_flash: "There was an error registering your oauth application"
5
+ create_oauth_application_notice_flash: "Your oauth application has been registered"
6
+ revoke_oauth_token_notice_flash: "The oauth token has been revoked"
7
+ oauth_authorize_title: "Authorize"
8
+ oauth_oauth_applications_page_title: "Oauth Applications"
9
+ oauth_oauth_application_page_title: "Oauth Application"
10
+ oauth_new_oauth_application_page_title: "New Oauth Application"
11
+ oauth_oauth_tokens_page_title: "Oauth Tokens"
12
+ name_label: "Name"
13
+ description_label: "Description"
14
+ scopes_label: "Scopes"
15
+ homepage_url_label: "Homepage URL"
16
+ redirect_uri_label: "Redirect URL"
17
+ client_secret_label: "Client Secret"
18
+ client_id_label: "Client ID"
19
+ oauth_applications_button: "Register"
20
+ oauth_authorize_button: "Authorize"
21
+ oauth_token_revoke_button: "Revoke"
22
+ oauth_authorize_post_button: "Back to Client Application"
23
+ invalid_grant_message: "Invalid grant"
24
+ invalid_scope_message: "Invalid scope"
25
+ invalid_url_message: "Invalid URL"
26
+ unsupported_token_type_message: "Invalid token type hint"
27
+ unique_error_message: "is already in use"
28
+ null_error_message: "is not filled"
29
+ already_in_use_message: "error generating unique token"
30
+ code_challenge_required_message: "code challenge required"
31
+ unsupported_transform_algorithm_message: "transform algorithm not supported"
32
+ request_uri_not_supported_message: "request uri is unsupported"
33
+ invalid_request_object_message: "request object is invalid"
34
+ invalid_scope_message: "The Access Token expired"
@@ -1,4 +1,4 @@
1
- <form method="post" class="form-horizontal" role="form" id="authorize-form">
1
+ <form method="post" action="#{rodauth.authorize_path}" class="form-horizontal" role="form" id="authorize-form">
2
2
  #{csrf_tag(rodauth.authorize_path) if respond_to?(:csrf_tag)}
3
3
  <p class="lead">The application #{rodauth.oauth_application[rodauth.oauth_applications_name_column]} would like to access your data.</p>
4
4
 
@@ -7,5 +7,5 @@
7
7
  end.join
8
8
  }
9
9
  </dl>
10
- <a href="/#{"#{rodauth.oauth_applications_path}/#{@oauth_application[:id]}/#{rodauth.oauth_tokens_path}"}" class="btn btn-outline-secondary">Oauth Tokens</a>
11
- </div>
10
+ <a href="#{rodauth.oauth_applications_path}/#{@oauth_application[:id]}/#{rodauth.oauth_tokens_path}" class="btn btn-outline-secondary">Oauth Tokens</a>
11
+ </div>
@@ -21,14 +21,14 @@
21
21
  <tr>
22
22
  <td>#{oauth_token[rodauth.oauth_tokens_token_column]}</td>
23
23
  <td>#{oauth_token[rodauth.oauth_tokens_refresh_token_column]}</td>
24
- <td>#{rodauth.convert_timestamp(oauth_token[rodauth.oauth_tokens_expires_in_column])}</td>
25
- <td>#{rodauth.convert_timestamp(oauth_token[rodauth.oauth_tokens_revoked_at_column])}</td>
24
+ <td>#{oauth_token[rodauth.oauth_tokens_expires_in_column]}</td>
25
+ <td>#{oauth_token[rodauth.oauth_tokens_revoked_at_column]}</td>
26
26
  <td>
27
27
  #{
28
28
  if !oauth_token[rodauth.oauth_tokens_revoked_at_param] && !oauth_token[rodauth.oauth_tokens_token_hash_column]
29
29
  <<-HTML
30
30
  <form method="post" action="#{rodauth.revoke_path}" class="form-horizontal" role="form" id="revoke-form">
31
- #{csrf_tag(rodauth.oauth_revoke_path) if respond_to?(:csrf_tag)}
31
+ #{csrf_tag(rodauth.revoke_path) if respond_to?(:csrf_tag)}
32
32
  #{rodauth.input_field_string("token_type_hint", "revoke-token-type-hint", :value => "access_token", :type=>"hidden")}
33
33
  #{rodauth.input_field_string("token", "revoke-token", :value => oauth_token[rodauth.oauth_tokens_token_column], :type=>"hidden")}
34
34
  #{rodauth.button(rodauth.oauth_token_revoke_button)}
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.5.1
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-19 00:00:00.000000000 Z
11
+ date: 2021-12-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Implementation of the OAuth 2.0 protocol on top of rodauth.
14
14
  email:
@@ -39,6 +39,7 @@ files:
39
39
  - lib/rodauth/oauth/railtie.rb
40
40
  - lib/rodauth/oauth/ttl_store.rb
41
41
  - lib/rodauth/oauth/version.rb
42
+ - locales/en.yml
42
43
  - templates/authorize.str
43
44
  - templates/client_secret_field.str
44
45
  - templates/description_field.str
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
72
  - !ruby/object:Gem::Version
72
73
  version: '0'
73
74
  requirements: []
74
- rubygems_version: 3.2.3
75
+ rubygems_version: 3.1.6
75
76
  signing_key:
76
77
  specification_version: 4
77
78
  summary: Implementation of the OAuth 2.0 protocol on top of rodauth.