rodauth-oauth 0.10.4 → 1.0.0.pre.beta2

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/MIGRATION-GUIDE-v1.md +286 -0
  3. data/README.md +28 -35
  4. data/doc/release_notes/1_0_0_beta1.md +38 -0
  5. data/doc/release_notes/1_0_0_beta2.md +34 -0
  6. data/lib/generators/rodauth/oauth/install_generator.rb +0 -1
  7. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +21 -11
  8. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb +1 -1
  9. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb +2 -2
  10. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb +1 -6
  11. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application.html.erb +0 -2
  12. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_grants.html.erb +41 -0
  13. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_applications.html.erb +2 -2
  14. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_grants.html.erb +37 -0
  15. data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +57 -57
  16. data/lib/rodauth/features/oauth_application_management.rb +61 -74
  17. data/lib/rodauth/features/oauth_assertion_base.rb +19 -23
  18. data/lib/rodauth/features/oauth_authorization_code_grant.rb +62 -90
  19. data/lib/rodauth/features/oauth_authorize_base.rb +115 -22
  20. data/lib/rodauth/features/oauth_base.rb +397 -315
  21. data/lib/rodauth/features/oauth_client_credentials_grant.rb +20 -18
  22. data/lib/rodauth/features/{oauth_device_grant.rb → oauth_device_code_grant.rb} +62 -73
  23. data/lib/rodauth/features/oauth_dynamic_client_registration.rb +52 -31
  24. data/lib/rodauth/features/oauth_grant_management.rb +70 -0
  25. data/lib/rodauth/features/oauth_implicit_grant.rb +29 -27
  26. data/lib/rodauth/features/oauth_jwt.rb +53 -689
  27. data/lib/rodauth/features/oauth_jwt_base.rb +458 -0
  28. data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +48 -17
  29. data/lib/rodauth/features/oauth_jwt_jwks.rb +47 -0
  30. data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +116 -0
  31. data/lib/rodauth/features/oauth_management_base.rb +2 -0
  32. data/lib/rodauth/features/oauth_pkce.rb +22 -26
  33. data/lib/rodauth/features/oauth_resource_indicators.rb +33 -25
  34. data/lib/rodauth/features/oauth_resource_server.rb +59 -0
  35. data/lib/rodauth/features/oauth_saml_bearer_grant.rb +7 -1
  36. data/lib/rodauth/features/oauth_token_introspection.rb +76 -46
  37. data/lib/rodauth/features/oauth_token_revocation.rb +46 -33
  38. data/lib/rodauth/features/oidc.rb +382 -241
  39. data/lib/rodauth/features/oidc_dynamic_client_registration.rb +127 -51
  40. data/lib/rodauth/features/oidc_rp_initiated_logout.rb +115 -0
  41. data/lib/rodauth/oauth/database_extensions.rb +8 -6
  42. data/lib/rodauth/oauth/http_extensions.rb +74 -0
  43. data/lib/rodauth/oauth/railtie.rb +20 -0
  44. data/lib/rodauth/oauth/ttl_store.rb +2 -0
  45. data/lib/rodauth/oauth/version.rb +1 -1
  46. data/lib/rodauth/oauth.rb +29 -1
  47. data/locales/en.yml +34 -22
  48. data/locales/pt.yml +34 -22
  49. data/templates/authorize.str +19 -17
  50. data/templates/device_search.str +1 -1
  51. data/templates/device_verification.str +2 -2
  52. data/templates/jwks_field.str +1 -0
  53. data/templates/new_oauth_application.str +1 -2
  54. data/templates/oauth_application.str +2 -2
  55. data/templates/oauth_application_oauth_grants.str +54 -0
  56. data/templates/oauth_applications.str +2 -2
  57. data/templates/oauth_grants.str +52 -0
  58. metadata +23 -16
  59. data/lib/generators/rodauth/oauth/templates/app/models/oauth_token.rb +0 -4
  60. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_tokens.html.erb +0 -39
  61. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_tokens.html.erb +0 -35
  62. data/lib/rodauth/features/oauth.rb +0 -9
  63. data/lib/rodauth/features/oauth_http_mac.rb +0 -86
  64. data/lib/rodauth/features/oauth_token_management.rb +0 -81
  65. data/lib/rodauth/oauth/refinements.rb +0 -48
  66. data/templates/jwt_public_key_field.str +0 -4
  67. data/templates/oauth_application_oauth_tokens.str +0 -52
  68. data/templates/oauth_tokens.str +0 -50
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rodauth/oauth/refinements"
4
-
5
- module Rodauth
6
- Feature.define(:oauth_http_mac, :OauthHttpMac) do
7
- using PrefixExtensions
8
-
9
- depends :oauth
10
-
11
- auth_value_method :oauth_token_type, "mac"
12
- auth_value_method :oauth_mac_algorithm, "hmac-sha-256" # hmac-sha-256, hmac-sha-1
13
- auth_value_method :oauth_tokens_mac_key_column, :mac_key
14
-
15
- def authorization_token
16
- return @authorization_token if defined?(@authorization_token)
17
-
18
- @authorization_token = begin
19
- value = request.get_header("HTTP_AUTHORIZATION").to_s
20
-
21
- scheme, token = value.split(/ +/, 2)
22
-
23
- return unless scheme == "MAC"
24
-
25
- mac_attributes = parse_mac_authorization_header_props(token)
26
-
27
- oauth_token = oauth_token_by_token(mac_attributes["id"])
28
-
29
- return unless oauth_token && mac_signature_matches?(oauth_token, mac_attributes)
30
-
31
- oauth_token
32
-
33
- # TODO: set new MAC-KEY for the next request
34
- end
35
- end
36
-
37
- private
38
-
39
- def generate_oauth_token(params = {}, *args)
40
- super({ oauth_tokens_mac_key_column => oauth_unique_id_generator }.merge(params), *args)
41
- end
42
-
43
- def json_access_token_payload(oauth_token)
44
- payload = super
45
-
46
- payload["mac_key"] = oauth_token[oauth_tokens_mac_key_column]
47
- payload["mac_algorithm"] = oauth_mac_algorithm
48
-
49
- payload
50
- end
51
-
52
- def mac_signature_matches?(oauth_token, mac_attributes)
53
- nonce = mac_attributes["nonce"]
54
- uri = URI(request.url)
55
-
56
- request_signature = [
57
- nonce,
58
- request.request_method,
59
- uri.request_uri,
60
- uri.host,
61
- uri.port
62
- ].join("\n") + ("\n" * 3)
63
-
64
- mac_algorithm = case oauth_mac_algorithm
65
- when "hmac-sha-256"
66
- OpenSSL::Digest::SHA256
67
- when "hmac-sha-1"
68
- OpenSSL::Digest::SHA1
69
- else
70
- raise ArgumentError, "Unsupported algorithm"
71
- end
72
-
73
- mac_signature = Base64.strict_encode64 \
74
- OpenSSL::HMAC.digest(mac_algorithm.new, oauth_token[oauth_tokens_mac_key_column], request_signature)
75
-
76
- mac_signature == mac_attributes["mac"]
77
- end
78
-
79
- def parse_mac_authorization_header_props(token)
80
- @mac_authorization_header_props = token.split(/ *, */).each_with_object({}) do |prop, props|
81
- field, value = prop.split(/ *= */, 2)
82
- props[field] = value.delete_prefix("\"").delete_suffix("\"")
83
- end
84
- end
85
- end
86
- end
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rodauth/oauth/refinements"
4
-
5
- module Rodauth
6
- Feature.define(:oauth_token_management, :OauthTokenManagement) do
7
- using RegexpExtensions
8
-
9
- depends :oauth_management_base, :oauth_token_revocation
10
-
11
- view "oauth_tokens", "My Oauth Tokens", "oauth_tokens"
12
-
13
- button "Revoke", "oauth_token_revoke"
14
-
15
- auth_value_method :oauth_tokens_path, "oauth-tokens"
16
-
17
- %w[token refresh_token expires_in revoked_at].each do |param|
18
- translatable_method :"oauth_tokens_#{param}_label", param.gsub("_", " ").capitalize
19
- end
20
-
21
- auth_value_method :oauth_tokens_route, "oauth-tokens"
22
- auth_value_method :oauth_tokens_id_pattern, Integer
23
- auth_value_method :oauth_tokens_per_page, 20
24
-
25
- auth_value_methods(
26
- :oauth_token_path
27
- )
28
-
29
- def oauth_tokens_path(opts = {})
30
- route_path(oauth_tokens_route, opts)
31
- end
32
-
33
- def oauth_tokens_url(opts = {})
34
- route_url(oauth_tokens_route, opts)
35
- end
36
-
37
- def oauth_token_path(id)
38
- "#{oauth_tokens_path}/#{id}"
39
- end
40
-
41
- def oauth_tokens
42
- request.on(oauth_tokens_route) do
43
- require_account
44
-
45
- request.get do
46
- page = Integer(param_or_nil("page") || 1)
47
- per_page = per_page_param(oauth_tokens_per_page)
48
-
49
- scope.instance_variable_set(:@oauth_tokens, db[oauth_tokens_table]
50
- .select(Sequel[oauth_tokens_table].*, Sequel[oauth_applications_table][oauth_applications_name_column])
51
- .join(oauth_applications_table, Sequel[oauth_tokens_table][oauth_tokens_oauth_application_id_column] =>
52
- Sequel[oauth_applications_table][oauth_applications_id_column])
53
- .where(Sequel[oauth_tokens_table][oauth_tokens_account_id_column] => account_id)
54
- .where(oauth_tokens_revoked_at_column => nil)
55
- .order(Sequel.desc(oauth_tokens_id_column))
56
- .paginate(page, per_page))
57
- oauth_tokens_view
58
- end
59
-
60
- request.post(oauth_tokens_id_pattern) do |id|
61
- db[oauth_tokens_table]
62
- .where(oauth_tokens_id_column => id)
63
- .where(oauth_tokens_account_id_column => account_id)
64
- .update(oauth_tokens_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
65
-
66
- set_notice_flash revoke_oauth_token_notice_flash
67
- redirect oauth_tokens_path || "/"
68
- end
69
- end
70
- end
71
-
72
- def check_csrf?
73
- case request.path
74
- when oauth_tokens_path
75
- only_json? ? false : super
76
- else
77
- super
78
- end
79
- end
80
- end
81
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rodauth
4
- module PrefixExtensions
5
- unless String.method_defined?(:delete_prefix)
6
- refine(String) do
7
- def delete_suffix(suffix)
8
- suffix = suffix.to_s
9
- len = suffix.length
10
- return dup unless len.positive? && index(suffix, -len)
11
-
12
- self[0...-len]
13
- end
14
-
15
- def delete_prefix(prefix)
16
- prefix = prefix.to_s
17
- return dup unless rindex(prefix, 0)
18
-
19
- self[prefix.length..-1]
20
- end
21
- end
22
- end
23
-
24
- unless String.method_defined?(:delete_suffix!)
25
- refine(String) do
26
- def delete_suffix!(suffix)
27
- suffix = suffix.to_s
28
- chomp! if frozen?
29
- len = suffix.length
30
- return unless len.positive? && index(suffix, -len)
31
-
32
- self[-len..-1] = ""
33
- self
34
- end
35
- end
36
- end
37
- end
38
-
39
- module RegexpExtensions
40
- unless Regexp.method_defined?(:match?)
41
- refine(Regexp) do
42
- def match?(*args)
43
- !match(*args).nil?
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,4 +0,0 @@
1
- <div class="form-group">
2
- <label for="name">#{rodauth.oauth_applications_jwt_public_key_label}#{rodauth.input_field_label_suffix}</label>
3
- #{rodauth.input_field_string(rodauth.oauth_application_jwt_public_key_param, "jwt_public_key", :type=>"text", :required=>false)}
4
- </div>
@@ -1,52 +0,0 @@
1
- <div id="oauth-tokens">
2
- #{
3
- if @oauth_tokens.count.zero?
4
- "<p>No oauth tokens yet!</p>"
5
- else
6
- <<-HTML
7
- <table class="table">
8
- <thead>
9
- <tr>
10
- <th scope="col">#{rodauth.oauth_tokens_token_label}</th>
11
- <th scope="col">#{rodauth.oauth_tokens_refresh_token_label}</th>
12
- <th scope="col">#{rodauth.oauth_tokens_expires_in_label}</th>
13
- <th scope="col">#{rodauth.oauth_tokens_revoked_at_label}</th>
14
- <th scope="col">#{rodauth.oauth_tokens_scopes_label}</th>
15
- <th scope="col"><span class="badge badge-pill badge-dark">#{@oauth_tokens.count}</span>
16
- </tr>
17
- </thead>
18
- <tbody>
19
- #{
20
- @oauth_tokens.map do |oauth_token|
21
- <<-HTML
22
- <tr>
23
- <td><code class="token">#{oauth_token[rodauth.oauth_tokens_token_column]}</code></td>
24
- <td><code class="token">#{oauth_token[rodauth.oauth_tokens_refresh_token_column]}</code></td>
25
- <td>#{oauth_token[rodauth.oauth_tokens_expires_in_column]}</td>
26
- <td>#{oauth_token[rodauth.oauth_tokens_revoked_at_column]}</td>
27
- <td>#{oauth_token[rodauth.oauth_tokens_scopes_column]}</td>
28
- <td>
29
- #{
30
- if !oauth_token[rodauth.oauth_tokens_revoked_at_column] && !oauth_token[rodauth.oauth_tokens_token_hash_column]
31
- <<-HTML
32
- <form method="post" action="#{rodauth.revoke_path}" class="form-horizontal" role="form" id="revoke-form">
33
- #{csrf_tag(rodauth.revoke_path) if respond_to?(:csrf_tag)}
34
- #{rodauth.input_field_string("token_type_hint", "revoke-token-type-hint", :value => "access_token", :type=>"hidden")}
35
- #{rodauth.input_field_string("token", "revoke-token", :value => oauth_token[rodauth.oauth_tokens_token_column], :type=>"hidden")}
36
- #{rodauth.button(rodauth.oauth_token_revoke_button)}
37
- </form>
38
- HTML
39
- end
40
- }
41
- </td>
42
- </tr>
43
- HTML
44
- end.join
45
- }
46
- </tbody>
47
- </table>
48
- #{rodauth.oauth_management_pagination_links(@oauth_tokens)}
49
- HTML
50
- end
51
- }
52
- </div>
@@ -1,50 +0,0 @@
1
- <div id="oauth-tokens">
2
- #{
3
- if @oauth_tokens.count.zero?
4
- "<p>No oauth tokens yet!</p>"
5
- else
6
- <<-HTML
7
- <table class="table">
8
- <thead>
9
- <tr>
10
- <th scope="col">#{rodauth.oauth_applications_name_label}</th>
11
- <th scope="col">#{rodauth.oauth_tokens_token_label}</th>
12
- <th scope="col">#{rodauth.oauth_tokens_refresh_token_label}</th>
13
- <th scope="col">#{rodauth.oauth_tokens_expires_in_label}</th>
14
- <th scope="col">#{rodauth.oauth_tokens_scopes_label}</th>
15
- <th scope="col"><span class="badge badge-pill badge-dark">#{@oauth_tokens.count}</span>
16
- </tr>
17
- </thead>
18
- <tbody>
19
- #{
20
- @oauth_tokens.map do |oauth_token|
21
- <<-HTML
22
- <tr>
23
- <td>#{oauth_token[rodauth.oauth_applications_name_column]}</td>
24
- <td><code class="token">#{oauth_token[rodauth.oauth_tokens_token_column]}</code></td>
25
- <td><code class="token">#{oauth_token[rodauth.oauth_tokens_refresh_token_column]}</code></td>
26
- <td>#{oauth_token[rodauth.oauth_tokens_expires_in_column]}</td>
27
- <td>#{oauth_token[rodauth.oauth_tokens_scopes_column]}</td>
28
- <td>
29
- #{
30
- if !oauth_token[rodauth.oauth_tokens_token_hash_column]
31
- <<-HTML
32
- <form method="post" action="#{rodauth.oauth_token_path(oauth_token[rodauth.oauth_tokens_id_column])}" class="form-horizontal" role="form" id="token-revoke-form">
33
- #{csrf_tag(rodauth.oauth_token_path(oauth_token[rodauth.oauth_tokens_id_column])) if respond_to?(:csrf_tag)}
34
- #{rodauth.button(rodauth.oauth_token_revoke_button)}
35
- </form>
36
- HTML
37
- end
38
- }
39
- </td>
40
- </tr>
41
- HTML
42
- end.join
43
- }
44
- </tbody>
45
- </table>
46
- #{rodauth.oauth_management_pagination_links(@oauth_tokens)}
47
- HTML
48
- end
49
- }
50
- </div>