rodauth-oauth 1.1.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -8
- data/doc/release_notes/1_1_0.md +1 -1
- data/doc/release_notes/1_2_0.md +36 -0
- data/doc/release_notes/1_3_0.md +38 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +3 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +32 -9
- data/lib/rodauth/features/oauth_authorization_code_grant.rb +55 -33
- data/lib/rodauth/features/oauth_authorize_base.rb +25 -3
- data/lib/rodauth/features/oauth_base.rb +16 -16
- data/lib/rodauth/features/oauth_device_code_grant.rb +1 -2
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +182 -29
- data/lib/rodauth/features/oauth_implicit_grant.rb +23 -5
- data/lib/rodauth/features/oauth_jwt.rb +2 -0
- data/lib/rodauth/features/oauth_jwt_base.rb +52 -11
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +30 -22
- data/lib/rodauth/features/oauth_jwt_secured_authorization_response_mode.rb +126 -0
- data/lib/rodauth/features/oauth_management_base.rb +1 -3
- data/lib/rodauth/features/oauth_pushed_authorization_request.rb +135 -0
- data/lib/rodauth/features/oauth_tls_client_auth.rb +170 -0
- data/lib/rodauth/features/oidc.rb +97 -59
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +52 -2
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +3 -4
- data/lib/rodauth/features/oidc_self_issued.rb +73 -0
- data/lib/rodauth/oauth/version.rb +1 -1
- data/templates/authorize.str +1 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d7d5f8b68686703954bf4e335cef0ea33f9e31c94c439df84f08e8ff3270829
|
4
|
+
data.tar.gz: 1da57ba2082818a74dbca4d1c6bcab0c15f97da891e12c03a8bf91440a4edcfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8230b54e51d2081e25d1386d6294745d54eebbe11a6677bdb9cade14e0a418658bc2b8a67ae2e6355458f4b43d8a2df1700cd3e0496fa8a10e690318f3d03ba0
|
7
|
+
data.tar.gz: 31ab5721a6464b751860b6896f47999e189592582842ba419ab0a057ff38af98612d54a8b00177092e2fe5993af1e5554cecafbbfaab18a495656117f19ce4fd
|
data/README.md
CHANGED
@@ -17,6 +17,7 @@ This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framew
|
|
17
17
|
* Config OP
|
18
18
|
* Dynamic OP
|
19
19
|
* Form Post OP
|
20
|
+
* 3rd Party-Init OP
|
20
21
|
|
21
22
|
(it also passes the conformance tests for the RP-Initiated Logout OP).
|
22
23
|
|
@@ -24,7 +25,7 @@ This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framew
|
|
24
25
|
|
25
26
|
This gem implements the following RFCs and features of OAuth:
|
26
27
|
|
27
|
-
* `oauth` - [The OAuth 2.0 protocol framework](
|
28
|
+
* `oauth` - [The OAuth 2.0 protocol framework](-/wikis/home#oauth-20-protocol-framework):
|
28
29
|
* [Access Token generation](https://tools.ietf.org/html/rfc6749#section-1.4);
|
29
30
|
* [Access Token refresh token grant](https://tools.ietf.org/html/rfc6749#section-1.5);
|
30
31
|
* `oauth_authorization_code_grant` - [Authorization code grant](https://tools.ietf.org/html/rfc6749#section-1.3);
|
@@ -33,10 +34,13 @@ This gem implements the following RFCs and features of OAuth:
|
|
33
34
|
* `oauth_device_code_grant` - [Device code grant (off by default)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-device-flow-15);
|
34
35
|
* `oauth_token_revocation` - [Token revocation](https://tools.ietf.org/html/rfc7009);
|
35
36
|
* `oauth_token_introspection` - [Token introspection](https://tools.ietf.org/html/rfc7662);
|
37
|
+
* `oauth_pushed_authorization_request` - [Pushed Authorization Request](https://datatracker.ietf.org/doc/html/rfc9126);
|
36
38
|
* [Authorization Server Metadata](https://tools.ietf.org/html/rfc8414);
|
37
39
|
* `oauth_pkce` - [PKCE](https://tools.ietf.org/html/rfc7636);
|
40
|
+
* `oauth_tls_client_auth` - [Mutual-TLS Client Authentication](https://datatracker.ietf.org/doc/html/rfc8705);
|
38
41
|
* `oauth_jwt` - [JWT Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-07);
|
39
42
|
* `oauth_jwt_secured_authorization_request` - [JWT Secured Authorization Request](https://tools.ietf.org/html/draft-ietf-oauth-jwsreq-20);
|
43
|
+
* `oauth_jwt_secured_authorization_response_mode` - [JWT Secured Authorization Response_mode](https://openid.net/specs/openid-financial-api-jarm.html);
|
40
44
|
* `oauth_resource_indicators` - [Resource Indicators](https://datatracker.ietf.org/doc/html/rfc8707);
|
41
45
|
* Access Type (Token refresh online and offline);
|
42
46
|
* `oauth_http_mac` - [MAC Authentication Scheme](https://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-02);
|
@@ -44,18 +48,17 @@ This gem implements the following RFCs and features of OAuth:
|
|
44
48
|
* `oauth_saml_bearer_grant` - [SAML 2.0 Bearer Assertion](https://datatracker.ietf.org/doc/html/rfc7522);
|
45
49
|
* `oauth_jwt_bearer_grant` - [JWT Bearer Assertion](https://datatracker.ietf.org/doc/html/rfc7523);
|
46
50
|
|
47
|
-
* `oauth_dynamic_client_registration` - [Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591);
|
51
|
+
* `oauth_dynamic_client_registration` - [Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591) and [Dynamic Client Registration Management](https://www.rfc-editor.org/rfc/rfc7592);
|
48
52
|
* OAuth application and token management dashboards;
|
49
53
|
* The recommendations for [Native Apps](https://www.rfc-editor.org/rfc/rfc8252);
|
50
54
|
|
51
55
|
It also implements the [OpenID Connect layer](https://openid.net/connect/) (via the `openid` feature) on top of the OAuth features it provides, including:
|
52
56
|
|
53
|
-
*
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
*
|
58
|
-
* `oidc_rp_initiated_logout` - [RP Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html);
|
57
|
+
* [OpenID Connect Core](https://gitlab.com/os85/rodauth-oauth/-/wikis/Id-Token-Authentication);
|
58
|
+
* [OpenID Connect Discovery](https://gitlab.com/os85/rodauth-oauth/-/wikis/OIDC-Dynamic-Client-Registration);
|
59
|
+
* [OpenID Multiple Response Types](https://gitlab.com/os85/rodauth-oauth/-/wikis/Hybrid-flow);
|
60
|
+
* [OpenID Connect Dynamic Client Registration](https://gitlab.com/os85/rodauth-oauth/-/wikis/OIDC-Dynamic-Client-Registration);
|
61
|
+
* [RP Initiated Logout](https://gitlab.com/os85/rodauth-oauth/-/wikis/RP-Initiated-Logout);
|
59
62
|
|
60
63
|
This gem supports also rails (through [rodauth-rails]((https://github.com/janko/rodauth-rails))).
|
61
64
|
|
data/doc/release_notes/1_1_0.md
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
## 1.2.0 (13/02/2023)
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
#### Pushed Authorization Requests (PAR)
|
6
|
+
|
7
|
+
RFC: https://datatracker.ietf.org/doc/html/rfc9126
|
8
|
+
|
9
|
+
`rodauth-oauth` supports Pushed Authorization Requests, via the `:oauth_pushed_authorization_request` feature.
|
10
|
+
|
11
|
+
More info about the feature [in the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/Pushed-Authorization-Requests).
|
12
|
+
|
13
|
+
#### mTLS Client Auth (+ certificate-bound access tokens)
|
14
|
+
|
15
|
+
RFC: https://www.rfc-editor.org/rfc/rfc8705
|
16
|
+
|
17
|
+
The `:oauth_tls_client_auth` feature adds support for the variants of mTLS Client Authentication "PKI Mutual-TLS Method" and 2Self-Signed Certificate Mutual-TLS Method". It also supports client certificate bound access tokens.
|
18
|
+
|
19
|
+
More about it [in the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/mTLS-Client-Authentication).
|
20
|
+
|
21
|
+
#### Dynamic Client Registration management
|
22
|
+
|
23
|
+
RFC: https://www.rfc-editor.org/rfc/rfc7592
|
24
|
+
|
25
|
+
Support for dynamci client registration management was added to the `:oauth_dynamic_client_registration` feature.
|
26
|
+
|
27
|
+
More info about it [in the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/Dynamic-Client-Registration#getputdelete-registerclient_id).
|
28
|
+
|
29
|
+
### Improvements
|
30
|
+
|
31
|
+
* Support for 3rd-party initiated login was added, by including support for the `initiate_login_uri` attribute in the register route from the `:oauth_dynamic_client_registration` feature.
|
32
|
+
* Support for multitenant resource ownership was added, here's a [description from the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/How-to#scoping-grants-from-the-same-resource-owner).
|
33
|
+
|
34
|
+
### Bugfixes
|
35
|
+
|
36
|
+
* oidc: userinfo claims were not including claims with value `false`, such as `"email_verified"`. This behaviour has been fixed, and only claims of value `null` are omitted.
|
@@ -0,0 +1,38 @@
|
|
1
|
+
## 1.3.0 (02/04/2023)
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Self-Signed Issued Tokens
|
6
|
+
|
7
|
+
`rodauth-oauth` supports self-signed issued tokens, via the `oidc_self_issued` feature.
|
8
|
+
|
9
|
+
More info about the feature [in the docs](https://gitlab.com/os85/rodauth-oauth/-/wikis/Self-Issued-OpenID).
|
10
|
+
|
11
|
+
#### JARM
|
12
|
+
|
13
|
+
`rodauth-oauth` supports JWT-secured Authorization Response Mode, also known as JARM, via the `oauth_jwt_secured_authorization_response_mode`.
|
14
|
+
|
15
|
+
More info about the feature [in the docs](https://gitlab.com/os85/rodauth-oauth/-/wikis/JWT-Secured-Authorization-Response-Mode).
|
16
|
+
|
17
|
+
## Improvements
|
18
|
+
|
19
|
+
### `fill_with_account_claims` auth method
|
20
|
+
|
21
|
+
`fill_with_account_claims` is now exposed as an auth method. This allows one to override to be able to cover certain requirements, such as aggregated and distributed claims. Here's a [link to the docs](https://gitlab.com/os85/rodauth-oauth/-/wikis/Id-Token-Authentication#claim-types) explaining how to do it.
|
22
|
+
|
23
|
+
### oidc: only generate refresh token when `offline_access` scope is used.
|
24
|
+
|
25
|
+
When the `oidc` feature is used, refresh tokens won't be generated anymore by default; in order to do so, the `offline_access` needs to be requested for in the respective authorization request, [as the spec mandates](https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess).
|
26
|
+
|
27
|
+
### oidc: implicit grant loaded by default
|
28
|
+
|
29
|
+
The `oidc` feature now loads the `oauth_implicit_grant` feature by default. This hadn't been done before due to the wish to ship a secure integration by default, but since then, spec compliance became more prioritary, and this is a requirement.
|
30
|
+
|
31
|
+
## Bugfixes
|
32
|
+
|
33
|
+
* rails integration: activerecord migrations fixes:
|
34
|
+
* use `bigint` for foreign keys;
|
35
|
+
* index creation instruction with the wrong syntax;
|
36
|
+
* set precision 6 for default timestamps, to comply with AR defaults;
|
37
|
+
* add missing `code` column to the `oauth_pushed_requests` table;
|
38
|
+
* oidc: when using the `id_token` , or any composite response type including `id_token`, using any response mode other than `fragment` will result in an invalid request.
|
@@ -75,6 +75,9 @@
|
|
75
75
|
<% if params[:acr_values] %>
|
76
76
|
<%= hidden_field_tag :acr_values, params[:acr_values] %>
|
77
77
|
<% end %>
|
78
|
+
<% if params[:registration] %>
|
79
|
+
<%= hidden_field_tag :registration, params[:registration] %>
|
80
|
+
<% end %>
|
78
81
|
<% end %>
|
79
82
|
</div>
|
80
83
|
<p class="text-center">
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
create_table :oauth_applications do |t|
|
4
|
-
t.
|
4
|
+
t.bigint :account_id
|
5
5
|
t.foreign_key :accounts, column: :account_id
|
6
6
|
t.string :name, null: false
|
7
7
|
t.string :description, null: true
|
@@ -9,8 +9,9 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
9
9
|
t.string :redirect_uri, null: false
|
10
10
|
t.string :client_id, null: false, index: { unique: true }
|
11
11
|
t.string :client_secret, null: false, index: { unique: true }
|
12
|
+
t.string :registration_access_token, null: true
|
12
13
|
t.string :scopes, null: false
|
13
|
-
t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
14
|
+
t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP(6)" }
|
14
15
|
|
15
16
|
# :oauth_dynamic_client_configuration enabled, extra optional params
|
16
17
|
t.string :token_endpoint_auth_method, null: true
|
@@ -29,6 +30,7 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
29
30
|
# :oidc_dynamic_client_configuration enabled, extra optional params
|
30
31
|
t.string :sector_identifier_uri, null: true
|
31
32
|
t.string :application_type, null: true
|
33
|
+
t.string :initiate_login_uri, null: true
|
32
34
|
|
33
35
|
# :oidc enabled
|
34
36
|
t.string :subject_type, null: true
|
@@ -44,26 +46,35 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
44
46
|
t.string :request_object_encryption_alg, null: true
|
45
47
|
t.string :request_object_encryption_enc, null: true
|
46
48
|
t.string :request_uris, null: true
|
49
|
+
t.boolean :require_pushed_authorization_requests, null: false, default: false
|
50
|
+
|
51
|
+
# :oauth_tls_client_auth
|
52
|
+
t.string :tls_client_auth_subject_dn, null: true
|
53
|
+
t.string :tls_client_auth_san_dns, null: true
|
54
|
+
t.string :tls_client_auth_san_uri, null: true
|
55
|
+
t.string :tls_client_auth_san_ip, null: true
|
56
|
+
t.string :tls_client_auth_san_email, null: true
|
57
|
+
t.boolean :tls_client_certificate_bound_access_tokens, default: false
|
47
58
|
|
48
59
|
# :oidc_rp_initiated_logout enabled
|
49
60
|
t.string :post_logout_redirect_uris, null: false
|
50
61
|
end
|
51
62
|
|
52
63
|
create_table :oauth_grants do |t|
|
53
|
-
t.
|
64
|
+
t.bigint :account_id
|
54
65
|
t.foreign_key :accounts, column: :account_id
|
55
|
-
t.
|
66
|
+
t.bigint :oauth_application_id
|
56
67
|
t.foreign_key :oauth_applications, column: :oauth_application_id
|
57
68
|
t.string :type, null: true
|
58
69
|
t.string :code, null: true
|
59
70
|
t.index(%i[oauth_application_id code], unique: true)
|
60
|
-
t.string :token, unique: true
|
61
|
-
t.string :refresh_token, unique: true
|
71
|
+
t.string :token, index: { unique: true }
|
72
|
+
t.string :refresh_token, index: { unique: true }
|
62
73
|
t.datetime :expires_in, null: false
|
63
74
|
t.string :redirect_uri
|
64
75
|
t.datetime :revoked_at
|
65
76
|
t.string :scopes, null: false
|
66
|
-
t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
77
|
+
t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP(6)" }
|
67
78
|
t.string :access_type, null: false, default: "offline"
|
68
79
|
|
69
80
|
# :oauth_pkce enabled
|
@@ -71,9 +82,12 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
71
82
|
t.string :code_challenge_method
|
72
83
|
|
73
84
|
# :oauth_device_code_grant enabled
|
74
|
-
t.string :user_code, null: true, unique: true
|
85
|
+
t.string :user_code, null: true, index: { unique: true }
|
75
86
|
t.datetime :last_polled_at, null: true
|
76
87
|
|
88
|
+
# :oauth_tls_client_auth
|
89
|
+
t.string :certificate_thumbprint, null: true
|
90
|
+
|
77
91
|
# :resource_indicators enabled
|
78
92
|
t.string :resource
|
79
93
|
|
@@ -83,5 +97,14 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
83
97
|
t.string :claims_locales
|
84
98
|
t.string :claims
|
85
99
|
end
|
100
|
+
|
101
|
+
create_table :oauth_pushed_requests do |t|
|
102
|
+
t.bigint :oauth_application_id
|
103
|
+
t.foreign_key :oauth_applications, column: :oauth_application_id
|
104
|
+
t.string :code, null: false, index: { unique: true }
|
105
|
+
t.string :params, null: false
|
106
|
+
t.datetime :expires_in, null: false
|
107
|
+
t.index %i[oauth_application_id code], unique: true
|
108
|
+
end
|
86
109
|
end
|
87
|
-
end
|
110
|
+
end
|
@@ -27,7 +27,19 @@ module Rodauth
|
|
27
27
|
|
28
28
|
response_mode = param_or_nil("response_mode")
|
29
29
|
|
30
|
-
|
30
|
+
return unless response_mode
|
31
|
+
|
32
|
+
redirect_response_error("invalid_request") unless oauth_response_modes_supported.include?(response_mode)
|
33
|
+
|
34
|
+
response_type = param_or_nil("response_type")
|
35
|
+
|
36
|
+
return unless response_type.nil? || response_type == "code"
|
37
|
+
|
38
|
+
redirect_response_error("invalid_request") unless oauth_response_modes_for_code_supported.include?(response_mode)
|
39
|
+
end
|
40
|
+
|
41
|
+
def oauth_response_modes_for_code_supported
|
42
|
+
%w[query form_post]
|
31
43
|
end
|
32
44
|
|
33
45
|
def validate_token_params
|
@@ -57,7 +69,7 @@ module Rodauth
|
|
57
69
|
def _do_authorize_code
|
58
70
|
create_params = {
|
59
71
|
oauth_grants_type_column => "authorization_code",
|
60
|
-
|
72
|
+
**resource_owner_params
|
61
73
|
}
|
62
74
|
|
63
75
|
{ "code" => create_oauth_grant(create_params) }
|
@@ -67,55 +79,65 @@ module Rodauth
|
|
67
79
|
redirect_url = URI.parse(redirect_uri)
|
68
80
|
case mode
|
69
81
|
when "query"
|
70
|
-
params =
|
82
|
+
params = [URI.encode_www_form(params)]
|
71
83
|
params << redirect_url.query if redirect_url.query
|
72
84
|
redirect_url.query = params.join("&")
|
73
85
|
redirect(redirect_url.to_s)
|
74
86
|
when "form_post"
|
75
|
-
|
76
|
-
|
77
|
-
<
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
params.map do |name, value|
|
82
|
-
"<input type=\"hidden\" name=\"#{scope.h(name)}\" value=\"#{scope.h(value)}\" />"
|
83
|
-
end.join
|
84
|
-
}
|
85
|
-
<input type="submit" class="btn btn-outline-primary" value="#{scope.h(oauth_authorize_post_button)}"/>
|
86
|
-
</form>
|
87
|
-
</body>
|
88
|
-
</html>
|
89
|
-
FORM
|
87
|
+
inline_html = form_post_response_html(redirect_uri) do
|
88
|
+
params.map do |name, value|
|
89
|
+
"<input type=\"hidden\" name=\"#{scope.h(name)}\" value=\"#{scope.h(value)}\" />"
|
90
|
+
end.join
|
91
|
+
end
|
92
|
+
scope.view layout: false, inline: inline_html
|
90
93
|
end
|
91
94
|
end
|
92
95
|
|
93
|
-
def _redirect_response_error(redirect_url,
|
96
|
+
def _redirect_response_error(redirect_url, params)
|
94
97
|
response_mode = param_or_nil("response_mode") || oauth_response_mode
|
95
98
|
|
96
99
|
case response_mode
|
97
100
|
when "form_post"
|
98
101
|
response["Content-Type"] = "text/html"
|
99
|
-
|
100
|
-
|
101
|
-
<
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
query_params.map do |name, value|
|
106
|
-
"<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
|
107
|
-
end.join
|
108
|
-
}
|
109
|
-
</form>
|
110
|
-
</body>
|
111
|
-
</html>
|
112
|
-
FORM
|
102
|
+
error_body = form_post_error_response_html(redirect_url) do
|
103
|
+
params.map do |name, value|
|
104
|
+
"<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
|
105
|
+
end.join
|
106
|
+
end
|
107
|
+
response.write(error_body)
|
113
108
|
request.halt
|
114
109
|
else
|
115
110
|
super
|
116
111
|
end
|
117
112
|
end
|
118
113
|
|
114
|
+
def form_post_response_html(url)
|
115
|
+
<<-FORM
|
116
|
+
<html>
|
117
|
+
<head><title>Authorized</title></head>
|
118
|
+
<body onload="javascript:document.forms[0].submit()">
|
119
|
+
<form method="post" action="#{url}">
|
120
|
+
#{yield}
|
121
|
+
<input type="submit" class="btn btn-outline-primary" value="#{scope.h(oauth_authorize_post_button)}"/>
|
122
|
+
</form>
|
123
|
+
</body>
|
124
|
+
</html>
|
125
|
+
FORM
|
126
|
+
end
|
127
|
+
|
128
|
+
def form_post_error_response_html(url)
|
129
|
+
<<-FORM
|
130
|
+
<html>
|
131
|
+
<head><title></title></head>
|
132
|
+
<body onload="javascript:document.forms[0].submit()">
|
133
|
+
<form method="post" action="#{url}">
|
134
|
+
#{yield}
|
135
|
+
</form>
|
136
|
+
</body>
|
137
|
+
</html>
|
138
|
+
FORM
|
139
|
+
end
|
140
|
+
|
119
141
|
def create_token(grant_type)
|
120
142
|
return super unless supported_grant_type?(grant_type, "authorization_code")
|
121
143
|
|
@@ -28,6 +28,11 @@ module Rodauth
|
|
28
28
|
translatable_method :oauth_unsupported_response_type_message, "Unsupported response type"
|
29
29
|
translatable_method :oauth_authorize_parameter_required, "Invalid or missing '%<parameter>s'"
|
30
30
|
|
31
|
+
auth_value_methods(
|
32
|
+
:resource_owner_params,
|
33
|
+
:oauth_grants_resource_owner_columns
|
34
|
+
)
|
35
|
+
|
31
36
|
# /authorize
|
32
37
|
auth_server_route(:authorize) do |r|
|
33
38
|
require_authorizable_account
|
@@ -73,7 +78,9 @@ module Rodauth
|
|
73
78
|
|
74
79
|
if (redirect_uri = param_or_nil("redirect_uri"))
|
75
80
|
normalized_redirect_uri = normalize_redirect_uri_for_comparison(redirect_uri)
|
76
|
-
|
81
|
+
unless redirect_uris.include?(normalized_redirect_uri) || redirect_uris.include?(redirect_uri)
|
82
|
+
redirect_authorize_error("redirect_uri")
|
83
|
+
end
|
77
84
|
elsif redirect_uris.size > 1
|
78
85
|
redirect_authorize_error("redirect_uri")
|
79
86
|
end
|
@@ -85,6 +92,14 @@ module Rodauth
|
|
85
92
|
try_approval_prompt if use_oauth_access_type? && request.get?
|
86
93
|
|
87
94
|
redirect_response_error("invalid_scope") if (request.post? || param_or_nil("scope")) && !check_valid_scopes?
|
95
|
+
|
96
|
+
response_mode = param_or_nil("response_mode")
|
97
|
+
|
98
|
+
redirect_response_error("invalid_request") unless response_mode.nil? || oauth_response_modes_supported.include?(response_mode)
|
99
|
+
end
|
100
|
+
|
101
|
+
def check_valid_scopes?(scp = scopes)
|
102
|
+
super(scp - %w[offline_access])
|
88
103
|
end
|
89
104
|
|
90
105
|
def check_valid_response_type?
|
@@ -109,13 +124,20 @@ module Rodauth
|
|
109
124
|
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
|
110
125
|
end
|
111
126
|
|
127
|
+
def resource_owner_params
|
128
|
+
{ oauth_grants_account_id_column => account_id }
|
129
|
+
end
|
130
|
+
|
131
|
+
def oauth_grants_resource_owner_columns
|
132
|
+
[oauth_grants_account_id_column]
|
133
|
+
end
|
134
|
+
|
112
135
|
def try_approval_prompt
|
113
136
|
approval_prompt = param_or_nil("approval_prompt")
|
114
137
|
|
115
138
|
return unless approval_prompt && approval_prompt == "auto"
|
116
139
|
|
117
|
-
return if db[oauth_grants_table].where(
|
118
|
-
oauth_grants_account_id_column => account_id,
|
140
|
+
return if db[oauth_grants_table].where(resource_owner_params).where(
|
119
141
|
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
120
142
|
oauth_grants_redirect_uri_column => redirect_uri,
|
121
143
|
oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
|
@@ -762,31 +762,31 @@ module Rodauth
|
|
762
762
|
throw_json_response_error(status_code, error_code)
|
763
763
|
else
|
764
764
|
redirect_url = URI.parse(redirect_url)
|
765
|
-
|
765
|
+
params = []
|
766
766
|
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
767
|
+
params << if respond_to?(:"oauth_#{error_code}_error_code")
|
768
|
+
["error", send(:"oauth_#{error_code}_error_code")]
|
769
|
+
else
|
770
|
+
["error", error_code]
|
771
|
+
end
|
772
772
|
|
773
773
|
if respond_to?(:"oauth_#{error_code}_message")
|
774
774
|
message = send(:"oauth_#{error_code}_message")
|
775
|
-
|
775
|
+
params << ["error_description", CGI.escape(message)]
|
776
776
|
end
|
777
777
|
|
778
778
|
state = param_or_nil("state")
|
779
779
|
|
780
|
-
|
780
|
+
params << ["state", state] if state
|
781
781
|
|
782
|
-
_redirect_response_error(redirect_url,
|
782
|
+
_redirect_response_error(redirect_url, params)
|
783
783
|
end
|
784
784
|
end
|
785
785
|
|
786
|
-
def _redirect_response_error(redirect_url,
|
787
|
-
|
788
|
-
|
789
|
-
redirect_url.query =
|
786
|
+
def _redirect_response_error(redirect_url, params)
|
787
|
+
params = params.map { |k, v| "#{k}=#{v}" }
|
788
|
+
params << redirect_url.query if redirect_url.query
|
789
|
+
redirect_url.query = params.join("&")
|
790
790
|
redirect(redirect_url.to_s)
|
791
791
|
end
|
792
792
|
|
@@ -841,10 +841,10 @@ module Rodauth
|
|
841
841
|
throw_json_response_error(oauth_authorization_required_error_status, "invalid_client")
|
842
842
|
end
|
843
843
|
|
844
|
-
def check_valid_scopes?
|
845
|
-
return false unless
|
844
|
+
def check_valid_scopes?(scp = scopes)
|
845
|
+
return false unless scp
|
846
846
|
|
847
|
-
(
|
847
|
+
(scp - oauth_application[oauth_applications_scopes_column].split(oauth_scope_separator)).empty?
|
848
848
|
end
|
849
849
|
|
850
850
|
def check_valid_uri?(uri)
|
@@ -193,9 +193,8 @@ module Rodauth
|
|
193
193
|
|
194
194
|
# do not clean up device code just yet
|
195
195
|
update_params.delete(oauth_grants_code_column)
|
196
|
-
|
197
196
|
update_params[oauth_grants_user_code_column] = nil
|
198
|
-
update_params
|
197
|
+
update_params.merge!(resource_params)
|
199
198
|
|
200
199
|
super(grant_params, update_params)
|
201
200
|
end
|