rodauth 2.8.0 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +6 -0
- data/README.rdoc +10 -2
- data/doc/json.rdoc +47 -0
- data/doc/jwt.rdoc +1 -28
- data/doc/release_notes/2.9.0.txt +21 -0
- data/doc/remember.rdoc +1 -1
- data/lib/rodauth/features/json.rb +189 -0
- data/lib/rodauth/features/jwt.rb +10 -169
- data/lib/rodauth/features/jwt_refresh.rb +1 -4
- data/lib/rodauth/features/remember.rb +1 -0
- data/lib/rodauth/features/webauthn_verify_account.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a51cd006e762abd197f16ec9b8337cd54bf15206fcc2ce3a83cb1c424bb83845
|
4
|
+
data.tar.gz: 41e21158bee2b7ef8c75a93b035a5ff08c0245e5719aecbf783a818a860329b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb2c83005f29f8e8f2ea36ae97111c2b2108dc370ce1fee624c6cd27fd96eaa70be8f1471d9b9cb4a8b652b55e2277cce3489514bf56624bceb2c4f52413b580
|
7
|
+
data.tar.gz: 6bf8b23187ab6935cd33259b4ee546281df100641b7927c9e03e531f591a451ba5d56b50b8621cbc7948ad8807253dbded5da0b85247e70db7aa5db1d2be765a
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
=== 2.9.0 (2021-01-22)
|
2
|
+
|
3
|
+
* Split jwt feature into json and jwt features, with the json feature using standard session support (janko, jeremyevans) (#145)
|
4
|
+
|
5
|
+
* Mark remember cookie as only transmitted over HTTPS by default if created via an HTTPS request (janko) (#144)
|
6
|
+
|
1
7
|
=== 2.8.0 (2021-01-06)
|
2
8
|
|
3
9
|
* [SECURITY] Set HttpOnly on remember cookie by default so it cannot be accessed by Javascript (janko) (#142)
|
data/README.rdoc
CHANGED
@@ -52,7 +52,8 @@ HTML and JSON API for all supported features.
|
|
52
52
|
* Session Expiration
|
53
53
|
* Active Sessions (Prevent session reuse after logout, allow logout of all sessions)
|
54
54
|
* Single Session (Only one active session per account)
|
55
|
-
*
|
55
|
+
* JSON (JSON API support for all other features)
|
56
|
+
* JWT (JSON Web Token support for all other features)
|
56
57
|
* JWT Refresh (Access & Refresh Token)
|
57
58
|
* JWT CORS (Cross-Origin Resource Sharing)
|
58
59
|
* Update Password Hash (when hash cost changes)
|
@@ -872,6 +873,7 @@ view the appropriate file in the doc directory.
|
|
872
873
|
* {Disallow Password Reuse}[rdoc-ref:doc/disallow_password_reuse.rdoc]
|
873
874
|
* {Email Authentication}[rdoc-ref:doc/email_auth.rdoc]
|
874
875
|
* {HTTP Basic Auth}[rdoc-ref:doc/http_basic_auth.rdoc]
|
876
|
+
* {JSON}[rdoc-ref:doc/json.rdoc]
|
875
877
|
* {JWT CORS}[rdoc-ref:doc/jwt_cors.rdoc]
|
876
878
|
* {JWT Refresh}[rdoc-ref:doc/jwt_refresh.rdoc]
|
877
879
|
* {JWT}[rdoc-ref:doc/jwt.rdoc]
|
@@ -1320,7 +1322,13 @@ use the necessary *_email_body configuration options to specify
|
|
1320
1322
|
the body of the emails.
|
1321
1323
|
|
1322
1324
|
The JWT feature enables JSON API support for all of the other features
|
1323
|
-
that Rodauth ships with.
|
1325
|
+
that Rodauth ships with. If you would like JSON API access that still uses
|
1326
|
+
rack session for storing session data, enable the JSON feature instead:
|
1327
|
+
|
1328
|
+
plugin :rodauth, :json=>true do
|
1329
|
+
enable :login, :logout, :json
|
1330
|
+
only_json? true # if you want to only handle JSON requests
|
1331
|
+
end
|
1324
1332
|
|
1325
1333
|
=== Adding Custom Methods to the +rodauth+ Object
|
1326
1334
|
|
data/doc/json.rdoc
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
= Documentation for JSON Feature
|
2
|
+
|
3
|
+
The json feature adds support for JSON API access for all other
|
4
|
+
features that ship with Rodauth.
|
5
|
+
|
6
|
+
When this feature is used, all other features become accessible via a
|
7
|
+
JSON API. The JSON API uses the POST method for all requests, using
|
8
|
+
the same parameter names as the features uses. JSON API requests to
|
9
|
+
Rodauth endpoints that use a method other than POST will result in a
|
10
|
+
405 Method Not Allowed response.
|
11
|
+
|
12
|
+
Responses are returned as JSON hashes. In case of an error, the +error+
|
13
|
+
entry is set to an error message, and the <tt>field-error</tt> entry is set to
|
14
|
+
an array containing the field name and the error message for that field.
|
15
|
+
Successful requests by default store a +success+ entry with a success
|
16
|
+
message, though that can be disabled.
|
17
|
+
|
18
|
+
The session state is managed in the rack session, so make sure that
|
19
|
+
CSRF protection is enabled. This will be the case when passing the
|
20
|
+
<tt>json: true</tt> option when loading the rodauth plugin. If you
|
21
|
+
want to only handle JSON requests, set <tt>only_json? true</tt> in
|
22
|
+
your rodauth configuration.
|
23
|
+
|
24
|
+
If you want token-based authentication sent via the Authorization
|
25
|
+
header, consider using the jwt feature.
|
26
|
+
|
27
|
+
== Auth Value Methods
|
28
|
+
|
29
|
+
json_accept_regexp :: The regexp to use to check the Accept header for JSON if +json_check_accept?+ is true.
|
30
|
+
json_check_accept? :: Whether to check the Accept header to see if the client supports JSON responses, true by default.
|
31
|
+
json_non_post_error_message :: The error message to use when a JSON non-POST request is sent.
|
32
|
+
json_not_accepted_error_message :: The error message to display if +json_check_accept?+ is true and the Accept header is present but does not match +json_request_content_type_regexp+.
|
33
|
+
json_request_content_type_regexp :: The regexp to use to recognize a request as a json request.
|
34
|
+
json_response_content_type :: The content type to set for json responses, <tt>application/json</tt> by default.
|
35
|
+
json_response_custom_error_status? :: Whether to use custom error statuses, instead of always using +json_response_error_status+, true by default, can be set to false for backwards compatibility with Rodauth 1.
|
36
|
+
json_response_error_key :: The JSON result key containing an error message, +error+ by default.
|
37
|
+
json_response_error_status :: The HTTP status code to use for JSON error responses if not using custom error statuses, 400 by default.
|
38
|
+
json_response_field_error_key :: The JSON result key containing an field error message, <tt>field-error</tt> by default.
|
39
|
+
json_response_success_key :: The JSON result key containing a success message for successful request, if set. +success+ by default.
|
40
|
+
non_json_request_error_message :: The error message to use when a non-JSON request is sent and +only_json?+ is set.
|
41
|
+
only_json? :: Whether to have Rodauth only allow JSON requests. True by default if <tt>json: :only</tt> option was given when loading the plugin. If set, rodauth endpoints will issue an error for non-JSON requests.
|
42
|
+
use_json? :: Whether to return a JSON response. By default, a JSON response is returned if +only_json?+ is true, or if the request uses a json content type.
|
43
|
+
|
44
|
+
== Auth Methods
|
45
|
+
|
46
|
+
json_request? :: Whether the current request is a JSON request, looks at the Content-Type request header by default.
|
47
|
+
json_response_body(hash) :: The body to use for JSON response. By default just converts hash to JSON. Can be used to reformat JSON output in arbitrary ways.
|
data/doc/jwt.rdoc
CHANGED
@@ -2,19 +2,7 @@
|
|
2
2
|
|
3
3
|
The jwt feature adds support for JSON API access for all other features
|
4
4
|
that ship with Rodauth, using JWT (JSON Web Tokens) to hold the
|
5
|
-
session information.
|
6
|
-
|
7
|
-
When this feature is used, all other features become accessible via a
|
8
|
-
JSON API. The JSON API uses the POST method for all requests, using
|
9
|
-
the same parameter names as the features uses. JSON API requests to
|
10
|
-
Rodauth endpoints that use a method other than POST will result in a
|
11
|
-
405 Method Not Allowed response.
|
12
|
-
|
13
|
-
Responses are returned as JSON hashes. In case of an error, the +error+
|
14
|
-
entry is set to an error message, and the <tt>field-error</tt> entry is set to
|
15
|
-
an array containing the field name and the error message for that field.
|
16
|
-
Successful requests by default store a +success+ entry with a success
|
17
|
-
message, though that can be disabled.
|
5
|
+
session information. It depends on the json feature.
|
18
6
|
|
19
7
|
In order to use this feature, you have to set the +jwt_secret+ configuration
|
20
8
|
option the secret used to cryptographically protect the token.
|
@@ -41,32 +29,17 @@ from +rodauth.session+.
|
|
41
29
|
== Auth Value Methods
|
42
30
|
|
43
31
|
invalid_jwt_format_error_message :: The error message to use when a JWT with an invalid format is submitted in the Authorization header.
|
44
|
-
json_accept_regexp :: The regexp to use to check the Accept header for JSON if +jwt_check_accept?+ is true.
|
45
|
-
json_non_post_error_message :: The error message to use when a JSON non-POST request is sent.
|
46
|
-
json_not_accepted_error_message :: The error message to display if +jwt_check_accept?+ is true and the Accept header is present but does not match +json_request_content_type_regexp+.
|
47
|
-
json_request_content_type_regexp :: The regexp to use to recognize a request as a json request.
|
48
|
-
json_response_content_type :: The content type to set for json responses, <tt>application/json</tt> by default.
|
49
|
-
json_response_custom_error_status? :: Whether to use custom error statuses, instead of always using +json_response_error_status+, true by default, can be set to false for backwards compatibility with Rodauth 1.
|
50
|
-
json_response_error_key :: The JSON result key containing an error message, +error+ by default.
|
51
|
-
json_response_error_status :: The HTTP status code to use for JSON error responses if not using custom error statuses, 400 by default.
|
52
|
-
json_response_field_error_key :: The JSON result key containing an field error message, <tt>field-error</tt> by default.
|
53
|
-
json_response_success_key :: The JSON result key containing a success message for successful request, if set. +success+ by default.
|
54
32
|
jwt_algorithm :: The JWT algorithm to use, +HS256+ by default.
|
55
33
|
jwt_authorization_ignore :: A regexp matched against the Authorization header, which skips JWT processing if it matches. By default, HTTP Basic and Digest authentication are ignored.
|
56
34
|
jwt_authorization_remove :: A regexp to remove from the Authorization header before processing the JWT. By default, a Bearer prefix is removed.
|
57
|
-
jwt_check_accept? :: Whether to check the Accept header to see if the client supports JSON responses, true by default, can be set to false for backwards compatibility with Rodauth 1.
|
58
35
|
jwt_decode_opts :: An optional hash to pass to +JWT.decode+. Can be used to set JWT verifiers.
|
59
36
|
jwt_secret :: The JWT secret to use. Access to this should be protected the same as a session secret.
|
60
37
|
jwt_session_key :: A key to nest the session hash under in the JWT payload. nil by default, for no nesting.
|
61
38
|
jwt_symbolize_deeply? :: Whether to symbolize the session hash deeply. false by default.
|
62
|
-
non_json_request_error_message :: The error message to use when a non-JSON request is sent and +only_json?+ is set.
|
63
|
-
only_json? :: Whether to have Rodauth only allow JSON requests. True by default if <tt>json: :only</tt> option was given when loading the plugin. If set, rodauth endpoints will issue an error for non-JSON requests.
|
64
39
|
use_jwt? :: Whether to use the JWT in the Authorization header for authentication information. If false, falls back to using the rack session. By default, the Authorization header is used if it is present, if +only_json?+ is true, or if the request uses a json content type.
|
65
40
|
|
66
41
|
== Auth Methods
|
67
42
|
|
68
|
-
json_request? :: Whether the current request is a JSON request, looks at the Content-Type request header by default.
|
69
|
-
json_response_body(hash) :: The body to use for JSON response. By default just converts hash to JSON. Can be used to reformat JSON output in arbitrary ways.
|
70
43
|
jwt_session_hash :: The session hash used to create the session_jwt. Can be used to set JWT claims.
|
71
44
|
jwt_token :: Retrieve the JWT token from the request, by default taking it from the Authorization header.
|
72
45
|
session_jwt :: An encoded JWT for the current session.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A json feature has been extracted from the existing jwt feature.
|
4
|
+
This feature allows for the same JSON API previously supported
|
5
|
+
by the JWT feature, but stores the session information in the
|
6
|
+
Rack session instead of in a separate JWT. This makes it
|
7
|
+
significantly easier to have certain pages use the JSON API,
|
8
|
+
and other pages the HTML forms.
|
9
|
+
|
10
|
+
= Other Improvements
|
11
|
+
|
12
|
+
* If the remember cookie is created in an SSL request, the Secure
|
13
|
+
flag is added by default, so the cookie will not be transmitted
|
14
|
+
in non-SSL requests.
|
15
|
+
|
16
|
+
= Backwards Compatibility
|
17
|
+
|
18
|
+
* Rodauth configurations that use the remember feature and support
|
19
|
+
requests over both http and https and want to have the remember
|
20
|
+
cookie transmitted over both should now include :secure=>false in
|
21
|
+
remember_cookie_options.
|
data/doc/remember.rdoc
CHANGED
@@ -35,7 +35,7 @@ raw_remember_token_deadline :: A deadline before which to allow a raw remember t
|
|
35
35
|
remember_additional_form_tags :: HTML fragment containing additional form tags to use on the change remember setting form.
|
36
36
|
remember_button :: The text to use for the change remember settings button.
|
37
37
|
remember_cookie_key :: The cookie name to use for the remember token.
|
38
|
-
remember_cookie_options :: Any options to set for the remember cookie. By default, the `:path` cookie option is set to
|
38
|
+
remember_cookie_options :: Any options to set for the remember cookie. By default, the `:path` cookie option is set to `/` and `:httponly` is set to `true`. Also, `:secure` is set to `true` by default if the current request is an HTTPS request.
|
39
39
|
remember_deadline_column :: The column name in the +remember_table+ storing the deadline after which the token will be ignored.
|
40
40
|
remember_deadline_interval :: The amount of time for which to remember accounts, 14 days by default. Only used if +set_deadline_values?+ is true.
|
41
41
|
remember_disable_label :: The label for disabling remembering.
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:json, :Json) do
|
5
|
+
translatable_method :json_not_accepted_error_message, 'Unsupported Accept header. Must accept "application/json" or compatible content type'
|
6
|
+
translatable_method :json_non_post_error_message, 'non-POST method used in JSON API'
|
7
|
+
auth_value_method :json_accept_regexp, /(?:(?:\*|\bapplication)\/\*|\bapplication\/(?:vnd\.api\+)?json\b)/i
|
8
|
+
auth_value_method :json_check_accept?, true
|
9
|
+
auth_value_method :json_request_content_type_regexp, /\bapplication\/(?:vnd\.api\+)?json\b/i
|
10
|
+
auth_value_method :json_response_content_type, 'application/json'
|
11
|
+
auth_value_method :json_response_custom_error_status?, true
|
12
|
+
auth_value_method :json_response_error_status, 400
|
13
|
+
auth_value_method :json_response_error_key, "error"
|
14
|
+
auth_value_method :json_response_field_error_key, "field-error"
|
15
|
+
auth_value_method :json_response_success_key, "success"
|
16
|
+
translatable_method :non_json_request_error_message, 'Only JSON format requests are allowed'
|
17
|
+
|
18
|
+
auth_value_methods(
|
19
|
+
:only_json?,
|
20
|
+
:use_json?,
|
21
|
+
)
|
22
|
+
|
23
|
+
auth_methods(
|
24
|
+
:json_request?,
|
25
|
+
)
|
26
|
+
|
27
|
+
auth_private_methods :json_response_body
|
28
|
+
|
29
|
+
def set_field_error(field, message)
|
30
|
+
return super unless use_json?
|
31
|
+
json_response[json_response_field_error_key] = [field, message]
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_error_flash(message)
|
35
|
+
return super unless use_json?
|
36
|
+
json_response[json_response_error_key] = message
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_redirect_error_flash(message)
|
40
|
+
return super unless use_json?
|
41
|
+
json_response[json_response_error_key] = message
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_notice_flash(message)
|
45
|
+
return super unless use_json?
|
46
|
+
json_response[json_response_success_key] = message if include_success_messages?
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_notice_now_flash(message)
|
50
|
+
return super unless use_json?
|
51
|
+
json_response[json_response_success_key] = message if include_success_messages?
|
52
|
+
end
|
53
|
+
|
54
|
+
def json_request?
|
55
|
+
return @json_request if defined?(@json_request)
|
56
|
+
@json_request = request.content_type =~ json_request_content_type_regexp
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_json?
|
60
|
+
json_request? || only_json?
|
61
|
+
end
|
62
|
+
|
63
|
+
def view(page, title)
|
64
|
+
return super unless use_json?
|
65
|
+
return_json_response
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def before_view_recovery_codes
|
71
|
+
super if defined?(super)
|
72
|
+
if use_json?
|
73
|
+
json_response[:codes] = recovery_codes
|
74
|
+
json_response[json_response_success_key] ||= "" if include_success_messages?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def before_webauthn_setup_route
|
79
|
+
super if defined?(super)
|
80
|
+
if use_json? && !param_or_nil(webauthn_setup_param)
|
81
|
+
cred = new_webauthn_credential
|
82
|
+
json_response[webauthn_setup_param] = cred.as_json
|
83
|
+
json_response[webauthn_setup_challenge_param] = cred.challenge
|
84
|
+
json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def before_webauthn_auth_route
|
89
|
+
super if defined?(super)
|
90
|
+
if use_json? && !param_or_nil(webauthn_auth_param)
|
91
|
+
cred = webauth_credential_options_for_get
|
92
|
+
json_response[webauthn_auth_param] = cred.as_json
|
93
|
+
json_response[webauthn_auth_challenge_param] = cred.challenge
|
94
|
+
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def before_webauthn_login_route
|
99
|
+
super if defined?(super)
|
100
|
+
if use_json? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param))
|
101
|
+
cred = webauth_credential_options_for_get
|
102
|
+
json_response[webauthn_auth_param] = cred.as_json
|
103
|
+
json_response[webauthn_auth_challenge_param] = cred.challenge
|
104
|
+
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def before_webauthn_remove_route
|
109
|
+
super if defined?(super)
|
110
|
+
if use_json? && !param_or_nil(webauthn_remove_param)
|
111
|
+
json_response[webauthn_remove_param] = account_webauthn_usage
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def before_otp_setup_route
|
116
|
+
super if defined?(super)
|
117
|
+
if use_json? && otp_keys_use_hmac? && !param_or_nil(otp_setup_raw_param)
|
118
|
+
_otp_tmp_key(otp_new_secret)
|
119
|
+
json_response[otp_setup_param] = otp_user_key
|
120
|
+
json_response[otp_setup_raw_param] = otp_key
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def before_rodauth
|
125
|
+
if json_request?
|
126
|
+
if json_check_accept? && (accept = request.env['HTTP_ACCEPT']) && accept !~ json_accept_regexp
|
127
|
+
response.status = 406
|
128
|
+
json_response[json_response_error_key] = json_not_accepted_error_message
|
129
|
+
_return_json_response
|
130
|
+
end
|
131
|
+
|
132
|
+
unless request.post?
|
133
|
+
response.status = 405
|
134
|
+
response.headers['Allow'] = 'POST'
|
135
|
+
json_response[json_response_error_key] = json_non_post_error_message
|
136
|
+
return_json_response
|
137
|
+
end
|
138
|
+
elsif only_json?
|
139
|
+
response.status = json_response_error_status
|
140
|
+
response.write non_json_request_error_message
|
141
|
+
request.halt
|
142
|
+
end
|
143
|
+
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
def redirect(_)
|
148
|
+
return super unless use_json?
|
149
|
+
return_json_response
|
150
|
+
end
|
151
|
+
|
152
|
+
def return_json_response
|
153
|
+
_return_json_response
|
154
|
+
end
|
155
|
+
|
156
|
+
def _return_json_response
|
157
|
+
response.status ||= json_response_error_status if json_response[json_response_error_key]
|
158
|
+
response['Content-Type'] ||= json_response_content_type
|
159
|
+
response.write(_json_response_body(json_response))
|
160
|
+
request.halt
|
161
|
+
end
|
162
|
+
|
163
|
+
def include_success_messages?
|
164
|
+
!json_response_success_key.nil?
|
165
|
+
end
|
166
|
+
|
167
|
+
def _json_response_body(hash)
|
168
|
+
request.send(:convert_to_json, hash)
|
169
|
+
end
|
170
|
+
|
171
|
+
def json_response
|
172
|
+
@json_response ||= {}
|
173
|
+
end
|
174
|
+
|
175
|
+
def set_redirect_error_status(status)
|
176
|
+
if use_json? && json_response_custom_error_status?
|
177
|
+
response.status = status
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_response_error_status(status)
|
182
|
+
if use_json? && !json_response_custom_error_status?
|
183
|
+
status = json_response_error_status
|
184
|
+
end
|
185
|
+
|
186
|
+
super
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
data/lib/rodauth/features/jwt.rb
CHANGED
@@ -4,41 +4,29 @@ require 'jwt'
|
|
4
4
|
|
5
5
|
module Rodauth
|
6
6
|
Feature.define(:jwt, :Jwt) do
|
7
|
+
depends :json
|
8
|
+
|
7
9
|
translatable_method :invalid_jwt_format_error_message, "invalid JWT format or claim in Authorization header"
|
8
|
-
translatable_method :json_non_post_error_message, 'non-POST method used in JSON API'
|
9
|
-
translatable_method :json_not_accepted_error_message, 'Unsupported Accept header. Must accept "application/json" or compatible content type'
|
10
|
-
auth_value_method :json_accept_regexp, /(?:(?:\*|\bapplication)\/\*|\bapplication\/(?:vnd\.api\+)?json\b)/i
|
11
|
-
auth_value_method :json_request_content_type_regexp, /\bapplication\/(?:vnd\.api\+)?json\b/i
|
12
|
-
auth_value_method :json_response_content_type, 'application/json'
|
13
|
-
auth_value_method :json_response_error_status, 400
|
14
|
-
auth_value_method :json_response_custom_error_status?, true
|
15
|
-
auth_value_method :json_response_error_key, "error"
|
16
|
-
auth_value_method :json_response_field_error_key, "field-error"
|
17
|
-
auth_value_method :json_response_success_key, "success"
|
18
10
|
auth_value_method :jwt_algorithm, "HS256"
|
19
11
|
auth_value_method :jwt_authorization_ignore, /\A(?:Basic|Digest) /
|
20
12
|
auth_value_method :jwt_authorization_remove, /\ABearer:?\s+/
|
21
|
-
auth_value_method :jwt_check_accept?, true
|
22
13
|
auth_value_method :jwt_decode_opts, {}.freeze
|
23
14
|
auth_value_method :jwt_session_key, nil
|
24
15
|
auth_value_method :jwt_symbolize_deeply?, false
|
25
|
-
translatable_method :non_json_request_error_message, 'Only JSON format requests are allowed'
|
26
16
|
|
27
17
|
auth_value_methods(
|
28
|
-
:only_json?,
|
29
18
|
:jwt_secret,
|
30
19
|
:use_jwt?
|
31
20
|
)
|
32
21
|
|
33
22
|
auth_methods(
|
34
|
-
:json_request?,
|
35
23
|
:jwt_session_hash,
|
36
24
|
:jwt_token,
|
37
25
|
:session_jwt,
|
38
26
|
:set_jwt_token
|
39
27
|
)
|
40
28
|
|
41
|
-
|
29
|
+
def_deprecated_alias :json_check_accept?, :jwt_check_accept?
|
42
30
|
|
43
31
|
def session
|
44
32
|
return @session if defined?(@session)
|
@@ -48,10 +36,7 @@ module Rodauth
|
|
48
36
|
if jwt_token
|
49
37
|
unless session_data = jwt_payload
|
50
38
|
json_response[json_response_error_key] ||= invalid_jwt_format_error_message
|
51
|
-
|
52
|
-
response['Content-Type'] ||= json_response_content_type
|
53
|
-
response.write(_json_response_body(json_response))
|
54
|
-
request.halt
|
39
|
+
_return_json_response
|
55
40
|
end
|
56
41
|
|
57
42
|
if jwt_session_key
|
@@ -79,36 +64,6 @@ module Rodauth
|
|
79
64
|
end
|
80
65
|
end
|
81
66
|
|
82
|
-
def set_field_error(field, message)
|
83
|
-
return super unless use_jwt?
|
84
|
-
json_response[json_response_field_error_key] = [field, message]
|
85
|
-
end
|
86
|
-
|
87
|
-
def set_error_flash(message)
|
88
|
-
return super unless use_jwt?
|
89
|
-
json_response[json_response_error_key] = message
|
90
|
-
end
|
91
|
-
|
92
|
-
def set_redirect_error_flash(message)
|
93
|
-
return super unless use_jwt?
|
94
|
-
json_response[json_response_error_key] = message
|
95
|
-
end
|
96
|
-
|
97
|
-
def set_notice_flash(message)
|
98
|
-
return super unless use_jwt?
|
99
|
-
json_response[json_response_success_key] = message if include_success_messages?
|
100
|
-
end
|
101
|
-
|
102
|
-
def set_notice_now_flash(message)
|
103
|
-
return super unless use_jwt?
|
104
|
-
json_response[json_response_success_key] = message if include_success_messages?
|
105
|
-
end
|
106
|
-
|
107
|
-
def json_request?
|
108
|
-
return @json_request if defined?(@json_request)
|
109
|
-
@json_request = request.content_type =~ json_request_content_type_regexp
|
110
|
-
end
|
111
|
-
|
112
67
|
def jwt_secret
|
113
68
|
raise ArgumentError, "jwt_secret not set"
|
114
69
|
end
|
@@ -134,16 +89,15 @@ module Rodauth
|
|
134
89
|
end
|
135
90
|
|
136
91
|
def use_jwt?
|
137
|
-
|
92
|
+
use_json?
|
138
93
|
end
|
139
94
|
|
140
|
-
def
|
141
|
-
|
95
|
+
def use_json?
|
96
|
+
jwt_token || super
|
142
97
|
end
|
143
98
|
|
144
|
-
def
|
145
|
-
|
146
|
-
return_json_response
|
99
|
+
def valid_jwt?
|
100
|
+
!!(jwt_token && jwt_payload)
|
147
101
|
end
|
148
102
|
|
149
103
|
private
|
@@ -153,85 +107,6 @@ module Rodauth
|
|
153
107
|
super
|
154
108
|
end
|
155
109
|
|
156
|
-
def before_rodauth
|
157
|
-
if json_request?
|
158
|
-
if jwt_check_accept? && (accept = request.env['HTTP_ACCEPT']) && accept !~ json_accept_regexp
|
159
|
-
response.status = 406
|
160
|
-
json_response[json_response_error_key] = json_not_accepted_error_message
|
161
|
-
response['Content-Type'] ||= json_response_content_type
|
162
|
-
response.write(_json_response_body(json_response))
|
163
|
-
request.halt
|
164
|
-
end
|
165
|
-
|
166
|
-
unless request.post?
|
167
|
-
response.status = 405
|
168
|
-
response.headers['Allow'] = 'POST'
|
169
|
-
json_response[json_response_error_key] = json_non_post_error_message
|
170
|
-
return_json_response
|
171
|
-
end
|
172
|
-
elsif only_json?
|
173
|
-
response.status = json_response_error_status
|
174
|
-
response.write non_json_request_error_message
|
175
|
-
request.halt
|
176
|
-
end
|
177
|
-
|
178
|
-
super
|
179
|
-
end
|
180
|
-
|
181
|
-
def before_view_recovery_codes
|
182
|
-
super if defined?(super)
|
183
|
-
if use_jwt?
|
184
|
-
json_response[:codes] = recovery_codes
|
185
|
-
json_response[json_response_success_key] ||= "" if include_success_messages?
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def before_webauthn_setup_route
|
190
|
-
super if defined?(super)
|
191
|
-
if use_jwt? && !param_or_nil(webauthn_setup_param)
|
192
|
-
cred = new_webauthn_credential
|
193
|
-
json_response[webauthn_setup_param] = cred.as_json
|
194
|
-
json_response[webauthn_setup_challenge_param] = cred.challenge
|
195
|
-
json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def before_webauthn_auth_route
|
200
|
-
super if defined?(super)
|
201
|
-
if use_jwt? && !param_or_nil(webauthn_auth_param)
|
202
|
-
cred = webauth_credential_options_for_get
|
203
|
-
json_response[webauthn_auth_param] = cred.as_json
|
204
|
-
json_response[webauthn_auth_challenge_param] = cred.challenge
|
205
|
-
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
def before_webauthn_login_route
|
210
|
-
super if defined?(super)
|
211
|
-
if use_jwt? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param))
|
212
|
-
cred = webauth_credential_options_for_get
|
213
|
-
json_response[webauthn_auth_param] = cred.as_json
|
214
|
-
json_response[webauthn_auth_challenge_param] = cred.challenge
|
215
|
-
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
def before_webauthn_remove_route
|
220
|
-
super if defined?(super)
|
221
|
-
if use_jwt? && !param_or_nil(webauthn_remove_param)
|
222
|
-
json_response[webauthn_remove_param] = account_webauthn_usage
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def before_otp_setup_route
|
227
|
-
super if defined?(super)
|
228
|
-
if use_jwt? && otp_keys_use_hmac? && !param_or_nil(otp_setup_raw_param)
|
229
|
-
_otp_tmp_key(otp_new_secret)
|
230
|
-
json_response[otp_setup_param] = otp_user_key
|
231
|
-
json_response[otp_setup_raw_param] = otp_key
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
110
|
def _jwt_decode_opts
|
236
111
|
jwt_decode_opts
|
237
112
|
end
|
@@ -247,15 +122,6 @@ module Rodauth
|
|
247
122
|
@jwt_payload = false
|
248
123
|
end
|
249
124
|
|
250
|
-
def redirect(_)
|
251
|
-
return super unless use_jwt?
|
252
|
-
return_json_response
|
253
|
-
end
|
254
|
-
|
255
|
-
def include_success_messages?
|
256
|
-
!json_response_success_key.nil?
|
257
|
-
end
|
258
|
-
|
259
125
|
def set_session_value(key, value)
|
260
126
|
super
|
261
127
|
set_jwt if use_jwt?
|
@@ -268,38 +134,13 @@ module Rodauth
|
|
268
134
|
value
|
269
135
|
end
|
270
136
|
|
271
|
-
def json_response
|
272
|
-
@json_response ||= {}
|
273
|
-
end
|
274
|
-
|
275
|
-
def _json_response_body(hash)
|
276
|
-
request.send(:convert_to_json, hash)
|
277
|
-
end
|
278
|
-
|
279
137
|
def return_json_response
|
280
|
-
response.status ||= json_response_error_status if json_response[json_response_error_key]
|
281
138
|
set_jwt
|
282
|
-
|
283
|
-
response.write(_json_response_body(json_response))
|
284
|
-
request.halt
|
139
|
+
super
|
285
140
|
end
|
286
141
|
|
287
142
|
def set_jwt
|
288
143
|
set_jwt_token(session_jwt)
|
289
144
|
end
|
290
|
-
|
291
|
-
def set_redirect_error_status(status)
|
292
|
-
if use_jwt? && json_response_custom_error_status?
|
293
|
-
response.status = status
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
def set_response_error_status(status)
|
298
|
-
if use_jwt? && !json_response_custom_error_status?
|
299
|
-
status = json_response_error_status
|
300
|
-
end
|
301
|
-
|
302
|
-
super
|
303
|
-
end
|
304
145
|
end
|
305
146
|
end
|
@@ -51,11 +51,8 @@ module Rodauth
|
|
51
51
|
end
|
52
52
|
else
|
53
53
|
json_response[json_response_error_key] = jwt_refresh_invalid_token_message
|
54
|
-
response.status ||= json_response_error_status
|
55
54
|
end
|
56
|
-
|
57
|
-
response.write(_json_response_body(json_response))
|
58
|
-
request.halt
|
55
|
+
_return_json_response
|
59
56
|
end
|
60
57
|
end
|
61
58
|
|
@@ -134,6 +134,7 @@ module Rodauth
|
|
134
134
|
opts[:expires] = convert_timestamp(active_remember_key_ds.get(remember_deadline_column))
|
135
135
|
opts[:path] = "/" unless opts.key?(:path)
|
136
136
|
opts[:httponly] = true unless opts.key?(:httponly)
|
137
|
+
opts[:secure] = true unless opts.key?(:secure) || !request.ssl?
|
137
138
|
::Rack::Utils.set_cookie_header!(response.headers, remember_cookie_key, opts)
|
138
139
|
end
|
139
140
|
|
@@ -29,7 +29,7 @@ module Rodauth
|
|
29
29
|
|
30
30
|
def before_verify_account
|
31
31
|
super
|
32
|
-
if features.include?(:
|
32
|
+
if features.include?(:json) && use_json? && !param_or_nil(webauthn_setup_param)
|
33
33
|
cred = new_webauthn_credential
|
34
34
|
json_response[webauthn_setup_param] = cred.as_json
|
35
35
|
json_response[webauthn_setup_challenge_param] = cred.challenge
|
data/lib/rodauth/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -252,6 +252,7 @@ extra_rdoc_files:
|
|
252
252
|
- doc/email_auth.rdoc
|
253
253
|
- doc/email_base.rdoc
|
254
254
|
- doc/http_basic_auth.rdoc
|
255
|
+
- doc/json.rdoc
|
255
256
|
- doc/jwt.rdoc
|
256
257
|
- doc/jwt_cors.rdoc
|
257
258
|
- doc/jwt_refresh.rdoc
|
@@ -311,6 +312,7 @@ extra_rdoc_files:
|
|
311
312
|
- doc/release_notes/2.6.0.txt
|
312
313
|
- doc/release_notes/2.7.0.txt
|
313
314
|
- doc/release_notes/2.8.0.txt
|
315
|
+
- doc/release_notes/2.9.0.txt
|
314
316
|
files:
|
315
317
|
- CHANGELOG
|
316
318
|
- MIT-LICENSE
|
@@ -352,6 +354,7 @@ files:
|
|
352
354
|
- doc/guides/status_column.rdoc
|
353
355
|
- doc/guides/totp_or_recovery.rdoc
|
354
356
|
- doc/http_basic_auth.rdoc
|
357
|
+
- doc/json.rdoc
|
355
358
|
- doc/jwt.rdoc
|
356
359
|
- doc/jwt_cors.rdoc
|
357
360
|
- doc/jwt_refresh.rdoc
|
@@ -398,6 +401,7 @@ files:
|
|
398
401
|
- doc/release_notes/2.6.0.txt
|
399
402
|
- doc/release_notes/2.7.0.txt
|
400
403
|
- doc/release_notes/2.8.0.txt
|
404
|
+
- doc/release_notes/2.9.0.txt
|
401
405
|
- doc/remember.rdoc
|
402
406
|
- doc/reset_password.rdoc
|
403
407
|
- doc/session_expiration.rdoc
|
@@ -430,6 +434,7 @@ files:
|
|
430
434
|
- lib/rodauth/features/email_auth.rb
|
431
435
|
- lib/rodauth/features/email_base.rb
|
432
436
|
- lib/rodauth/features/http_basic_auth.rb
|
437
|
+
- lib/rodauth/features/json.rb
|
433
438
|
- lib/rodauth/features/jwt.rb
|
434
439
|
- lib/rodauth/features/jwt_cors.rb
|
435
440
|
- lib/rodauth/features/jwt_refresh.rb
|