rodauth-oauth 0.5.1 → 0.7.1

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: 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.