rodauth 2.0.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +58 -0
  3. data/README.rdoc +14 -0
  4. data/doc/base.rdoc +2 -0
  5. data/doc/guides/admin_activation.rdoc +46 -0
  6. data/doc/guides/already_authenticated.rdoc +10 -0
  7. data/doc/guides/alternative_login.rdoc +46 -0
  8. data/doc/guides/create_account_programmatically.rdoc +38 -0
  9. data/doc/guides/delay_password.rdoc +25 -0
  10. data/doc/guides/email_only.rdoc +16 -0
  11. data/doc/guides/i18n.rdoc +26 -0
  12. data/doc/{internals.rdoc → guides/internals.rdoc} +0 -0
  13. data/doc/guides/links.rdoc +12 -0
  14. data/doc/guides/login_return.rdoc +37 -0
  15. data/doc/guides/password_column.rdoc +25 -0
  16. data/doc/guides/password_confirmation.rdoc +37 -0
  17. data/doc/guides/password_requirements.rdoc +30 -0
  18. data/doc/guides/paths.rdoc +36 -0
  19. data/doc/guides/query_params.rdoc +9 -0
  20. data/doc/guides/redirects.rdoc +17 -0
  21. data/doc/guides/registration_field.rdoc +68 -0
  22. data/doc/guides/require_mfa.rdoc +30 -0
  23. data/doc/guides/reset_password_autologin.rdoc +21 -0
  24. data/doc/guides/status_column.rdoc +28 -0
  25. data/doc/guides/totp_or_recovery.rdoc +16 -0
  26. data/doc/jwt_refresh.rdoc +11 -0
  27. data/doc/login.rdoc +8 -0
  28. data/doc/login_password_requirements_base.rdoc +3 -0
  29. data/doc/otp.rdoc +1 -0
  30. data/doc/password_pepper.rdoc +44 -0
  31. data/doc/release_notes/2.1.0.txt +31 -0
  32. data/doc/release_notes/2.2.0.txt +39 -0
  33. data/doc/release_notes/2.3.0.txt +37 -0
  34. data/doc/release_notes/2.4.0.txt +22 -0
  35. data/doc/release_notes/2.5.0.txt +20 -0
  36. data/doc/verify_login_change.rdoc +1 -0
  37. data/lib/rodauth.rb +5 -5
  38. data/lib/rodauth/features/active_sessions.rb +5 -7
  39. data/lib/rodauth/features/audit_logging.rb +2 -0
  40. data/lib/rodauth/features/base.rb +21 -2
  41. data/lib/rodauth/features/change_password.rb +1 -1
  42. data/lib/rodauth/features/close_account.rb +8 -6
  43. data/lib/rodauth/features/create_account.rb +1 -0
  44. data/lib/rodauth/features/disallow_password_reuse.rb +4 -2
  45. data/lib/rodauth/features/email_auth.rb +2 -2
  46. data/lib/rodauth/features/http_basic_auth.rb +15 -2
  47. data/lib/rodauth/features/jwt.rb +12 -8
  48. data/lib/rodauth/features/jwt_cors.rb +15 -15
  49. data/lib/rodauth/features/jwt_refresh.rb +39 -10
  50. data/lib/rodauth/features/login.rb +23 -12
  51. data/lib/rodauth/features/login_password_requirements_base.rb +9 -4
  52. data/lib/rodauth/features/otp.rb +5 -1
  53. data/lib/rodauth/features/password_complexity.rb +4 -2
  54. data/lib/rodauth/features/password_pepper.rb +45 -0
  55. data/lib/rodauth/features/remember.rb +2 -0
  56. data/lib/rodauth/features/session_expiration.rb +1 -6
  57. data/lib/rodauth/features/single_session.rb +1 -1
  58. data/lib/rodauth/features/sms_codes.rb +0 -1
  59. data/lib/rodauth/features/two_factor_base.rb +4 -4
  60. data/lib/rodauth/features/verify_account.rb +5 -0
  61. data/lib/rodauth/features/verify_account_grace_period.rb +3 -5
  62. data/lib/rodauth/features/verify_login_change.rb +2 -1
  63. data/lib/rodauth/features/webauthn.rb +1 -3
  64. data/lib/rodauth/features/webauthn_login.rb +1 -1
  65. data/lib/rodauth/migrations.rb +16 -5
  66. data/lib/rodauth/version.rb +1 -1
  67. data/templates/password-field.str +1 -1
  68. metadata +37 -5
@@ -0,0 +1,30 @@
1
+ = Customize password requirements
2
+
3
+ By default, Rodauth requires passwords to have at least 6 characters. You can
4
+ modify the minimum length:
5
+
6
+ plugin :rodauth do
7
+ enable :login, :logout, :create_account
8
+
9
+ # Require passwords to have at least 8 characters
10
+ password_minimum_length 8
11
+ end
12
+
13
+ You can use the {disallow common passwords feature}[rdoc-ref:doc/disallow_common_passwords.rdoc]
14
+ to prevent the usage of common passwords (the most common 10,000 by default).
15
+
16
+ You can use additional complexity checks on passwords via the {password
17
+ complexity feature}[rdoc-ref:doc/password_complexity.rdoc], though most of
18
+ those complexity checks are no longer considered modern security best
19
+ practices and are likely to decrease overall security.
20
+
21
+ If you want complete control over whether passwords meet requirements, you
22
+ can use the <tt>password_meets_requirements?</tt> configuration method.
23
+
24
+ plugin :rodauth do
25
+ enable :login, :logout, :create_account
26
+
27
+ password_meets_requirements? do |password|
28
+ #true if password meets requirements, false otherwise
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ = Change route path
2
+
3
+ You can change the URL path of any Rodauth route by overriding the
4
+ corresponding <tt>*_route</tt> method:
5
+
6
+ plugin :rodauth do
7
+ enable :login, :logout, :create_account, :reset_password
8
+
9
+ # Change login route to "/signin"
10
+ login_route "signin"
11
+
12
+ # Change create account route to "/register"
13
+ create_account_route "register"
14
+
15
+ # Change password reset request route to "/reset-password/request"
16
+ reset_password_request_route "reset-password/request"
17
+ end
18
+
19
+ If you want to add a prefix to all Rodauth routes, you should use the +prefix+
20
+ setting:
21
+
22
+ plugin :rodauth do
23
+ enable :login, :logout
24
+
25
+ # Use /auth prefix to each Rodauth route
26
+ prefix "/auth"
27
+ end
28
+
29
+ route do |r|
30
+ r.on "auth" do
31
+ # Serve Rodauth routes under the /auth branch of the routing tree
32
+ r.rodauth
33
+ end
34
+
35
+ # ...
36
+ end
@@ -0,0 +1,9 @@
1
+ = Pass query parameters to auth URLs
2
+
3
+ The <tt>*_path</tt> and <tt>*_url</tt> methods allow passing additional query parameters:
4
+
5
+ rodauth.create_account_path(type: "seller")
6
+ #=> "/create-account?type=seller"
7
+
8
+ rodauth.login_url(type: "operator")
9
+ #=> "https//example.com/login?type=operator"
@@ -0,0 +1,17 @@
1
+ = Change redirect destination
2
+
3
+ You can change the redirect destination for any Rodauth action by overriding
4
+ the corresponding <tt>*_redirect</tt> method:
5
+
6
+ plugin :rodauth do
7
+ enable :login, :logout, :create_account, :reset_password
8
+
9
+ # Redirect to "/dashboard" after login
10
+ login_redirect "/dashboard"
11
+
12
+ # Redirect to wherever login redirects to after creating account
13
+ create_account_redirect { login_redirect }
14
+
15
+ # Redirect to login page after password reset
16
+ reset_password_redirect { login_path }
17
+ end
@@ -0,0 +1,68 @@
1
+ = Add new field during account creation
2
+
3
+ The create account form only handles login and password parameters by
4
+ default. However, you might want to ask for additional information during
5
+ account creation, such as requiring the user to also enter their full name
6
+ or their company's name.
7
+
8
+ == A) Accounts table
9
+
10
+ Let's assume you wanted to wanted to store the additional field(s) directly on
11
+ the +accounts+ table:
12
+
13
+ atler_table :accounts do
14
+ add_column :name, String
15
+ end
16
+
17
+ You need to override the <tt>create-account</tt> template, which by default in
18
+ Rodauth you can do by adding a <tt>create-account.erb</tt> template in your
19
+ Roda +views+ directory.
20
+
21
+ Once you've added the <tt>create-account.erb</tt> template, and had it include
22
+ a field for the +name+, you can handle the submission of that field in a before
23
+ create account hook:
24
+
25
+ plugin :rodauth do
26
+ enable :login, :logout, :create_account
27
+
28
+ before_create_account do
29
+ # Validate presence of the name field
30
+ unless name = param_or_nil("name")
31
+ throw_error_status(422, "name", "must be present")
32
+ end
33
+
34
+ # Assign the new field to the account record
35
+ account[:name] = name
36
+ end
37
+ end
38
+
39
+ == B) Separate table
40
+
41
+ Alternatively, you can store the additional field(s) in separate table, for
42
+ example:
43
+
44
+ create_table :account_names do
45
+ foreign_key :account_id, :accounts, primary_key: true, type: :Bignum
46
+ String :name, null: false
47
+ end
48
+
49
+ You can then handle the new submitted field as follows:
50
+
51
+ plugin :rodauth do
52
+ enable :login, :logout, :create_account
53
+
54
+ before_create_account do
55
+ # Validate presence of the name field
56
+ throw_error_status(422, "name", "must be present") unless param_or_nil("name")
57
+ end
58
+
59
+ after_create_account do
60
+ # Create the associated record
61
+ db[:account_names].insert(account_id: account[:id], name: param("name"))
62
+ end
63
+
64
+ after_close_account do
65
+ # Delete the associated record
66
+ db[:account_names].where(account_id: account[:id]).delete
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ = Require multifactor authentication after login
2
+
3
+ You may want to require multifactor authentication on login for people
4
+ that have multifactor authentication set up. The +require_authentication+
5
+ Rodauth method works for pages that require an authenticated user, but not for
6
+ pages where authentication is optional.
7
+
8
+ You can set this up as follows:
9
+
10
+ plugin :rodauth do
11
+ enable :login, :logout, :otp
12
+
13
+ # If you don't want to show an error message when redirecting
14
+ # to the multifactor authentication page.
15
+ two_factor_need_authentication_error_flash nil
16
+
17
+ # Display the same flash message after multifactor
18
+ # authentication than is displayed after login
19
+ two_factor_auth_notice_flash { login_notice_flash }
20
+ end
21
+
22
+ route do |r|
23
+ r.rodauth
24
+
25
+ if rodauth.logged_in? && rodauth.two_factor_authentication_setup?
26
+ rodauth.require_two_factor_authenticated
27
+ end
28
+
29
+ # ...
30
+ end
@@ -0,0 +1,21 @@
1
+ = Autologin after password reset
2
+
3
+ When the user resets their password, by default they are not automatically
4
+ logged in. You can change this behaviour and login the user automatically
5
+ after password reset.
6
+
7
+ plugin :rodauth do
8
+ enable :login, :logout, :reset_password
9
+
10
+ reset_password_autologin? true
11
+ end
12
+
13
+ Similarly, when the verify login change feature is used, the user is not
14
+ automatically logged in after verifying the login change. You can configure
15
+ Rodauth to automatically log the user in in this case:
16
+
17
+ plugin :rodauth do
18
+ enable :login, :logout, :verify_login_change
19
+
20
+ verify_login_change_autologin? true
21
+ end
@@ -0,0 +1,28 @@
1
+ = Store account status in a text column
2
+
3
+ By default, Rodauth recommends using a separate table for account statuses, and
4
+ linking them via foreign keys. This is useful as it achieves an enum-like
5
+ behaviour, where the database ensures a constrained set of status values.
6
+
7
+ However, if you use a testing environment that starts with a blank database,
8
+ and don't want to fix your testing environment to support real foreign keys,
9
+ you can configure Rodauth to store the account status in a text column.
10
+ Doing so results in problems if a text value you do not expect gets stored
11
+ in the column. We can mitigate the problems by using a CHECK constraint
12
+ on the column.
13
+
14
+ create_table :accounts do
15
+ # ...
16
+ String :status, null: false, default: "verified",
17
+ check: {status: %w'unverified verified closed'}
18
+ end
19
+
20
+ Then we can configure Rodauth to support this.
21
+
22
+ plugin :rodauth do
23
+ # ...
24
+ account_status_column :status
25
+ account_unverified_status_value "unverified"
26
+ account_open_status_value "verified"
27
+ account_closed_status_value "closed"
28
+ end
@@ -0,0 +1,16 @@
1
+ = Allow recovery code on TOTP code field
2
+
3
+ If using the otp feature, for convenience you might want to allow
4
+ the user to enter the recovery code into the TOTP code field, instead
5
+ of requiring they use the separate recovery codes form. You can
6
+ implement this using the following configuration:
7
+
8
+ plugin :rodauth do
9
+ enable :login, :logout, :otp, :recovery_codes
10
+
11
+ before_otp_auth_route do
12
+ if recovery_code_match?(param(otp_auth_param))
13
+ two_factor_authenticate("recovery_code")
14
+ end
15
+ end
16
+ end
@@ -13,6 +13,15 @@ older access tokens. Older access tokens remain valid until they expire. You
13
13
  can use the active_sessions feature if you want previous access tokens to be invalid
14
14
  as soon as the refresh token is used.
15
15
 
16
+ You can have multiple active refresh tokens active at a time, since each browser session
17
+ will generally use a separate refresh token. If you would like to revoke a refresh token
18
+ when logging out, provide the refresh token when submitting the JSON request to logout.
19
+ If you would like to remove all refresh tokens for the account when logging out, provide
20
+ a value of <tt>all</tt> as the token value.
21
+
22
+ When using the refresh token, you must provide a valid access token, as that contains
23
+ information about the current session, which is used to create the new access token.
24
+
16
25
  This feature depends on the jwt feature.
17
26
 
18
27
  == Auth Value Methods
@@ -30,6 +39,8 @@ jwt_refresh_token_key :: Name of the key in the response json holding the refres
30
39
  jwt_refresh_token_key_column :: The column name in the +jwt_refresh_token_table+ holding the refresh token key value.
31
40
  jwt_refresh_token_key_param :: Name of parameter in which the refresh token is provided when requesting a new token. Default is +refresh_token+.
32
41
  jwt_refresh_token_table :: Name of the table holding refresh token keys.
42
+ jwt_refresh_without_access_token_message :: Error message when trying to refresh with providing an access token.
43
+ jwt_refresh_without_access_token_status :: The HTTP status code to use when trying to refresh without providing an access token.
33
44
 
34
45
  == Auth Methods
35
46
 
@@ -3,6 +3,13 @@
3
3
  The login feature implements a login page. It's the most commonly
4
4
  used feature.
5
5
 
6
+ In addition to the auth methods below, it provides a +login+ method that wraps
7
+ +login_session+, running login hooks and redirecting to the configured
8
+ location.
9
+
10
+ rodauth.account #=> { id: 123, ... }
11
+ rodauth.login('password') # login the current account
12
+
6
13
  == Auth Value Methods
7
14
 
8
15
  login_additional_form_tags :: HTML fragment containing additional form tags to use on the login form.
@@ -27,4 +34,5 @@ use_multi_phase_login? :: Whether to ask for login first, and only ask for passw
27
34
 
28
35
  before_login_route :: Run arbitrary code before handling a login route.
29
36
  login_view :: The HTML to use for the login form.
37
+ login_return_to_requested_location_path :: If +login_return_to_requested_location?+ is true, the path to use as the requested location. By default, uses the full path of the request for GET requests, and is nil for non-GET requests (in which case the default +login_redirect+ will be used).
30
38
  multi_phase_login_view :: The HTML to use for the login form after login has been entered when using multi phase login.
@@ -9,8 +9,10 @@ already_an_account_with_this_login_message :: The error message to display when
9
9
  login_confirm_label :: The label to use for login confirmations.
10
10
  login_confirm_param :: The parameter name to use for login confirmations.
11
11
  login_does_not_meet_requirements_message :: The error message to display when the login does not meet the requirements you have set.
12
+ login_email_regexp :: The regular expression used to validate whether login is a valid email address.
12
13
  login_maximum_length :: The maximum length for logins, 255 by default.
13
14
  login_minimum_length :: The minimum length for logins, 3 by default.
15
+ login_not_valid_email_message :: The error message to display when login is not a valid email address.
14
16
  login_too_long_message :: The error message fragment to show if the login is too long.
15
17
  login_too_short_message :: The error message fragment to show if the login is too short.
16
18
  logins_do_not_match_message :: The error message to display when login and login confirmation do not match.
@@ -29,6 +31,7 @@ same_as_existing_password_message :: The error message to display when a new pas
29
31
  == Auth Methods
30
32
 
31
33
  login_meets_requirements?(login) :: Whether the given login meets the requirements. By default, just checks that the login is a valid email address.
34
+ login_valid_email?(login) :: Whether the login is a valid email address.
32
35
  password_hash(password) :: A hash of the given password.
33
36
  password_meets_requirements?(password) :: Whether the given password meets the requirements. Can be used to implement complexity requirements for passwords.
34
37
  set_password(password) :: Set the password for the current account to the given password.
@@ -73,6 +73,7 @@ otp_auth_view :: The HTML to use for the OTP authentication form.
73
73
  otp_disable_view :: The HTML to use for the OTP disable form.
74
74
  otp_exists? :: Whether the current account has setup OTP.
75
75
  otp_key :: The stored OTP secret for the account.
76
+ otp_last_use :: The last time OTP authentication was successful for the account.
76
77
  otp_locked_out? :: Whether the current account has been locked out of OTP authentication.
77
78
  otp_new_secret :: A new secret to use when setting up OTP.
78
79
  otp_provisioning_name :: The provisioning name to use during OTP setup, defaults to the account's email.
@@ -0,0 +1,44 @@
1
+ = Documentation for Password Pepper Feature
2
+
3
+ The password pepper feature appends a specified secret string to passwords
4
+ before they are hashed. This way, if the password hashes get compromised, an
5
+ attacker cannot use them to crack the passwords without also knowing the
6
+ pepper.
7
+
8
+ In the configuration block set the +password_pepper+ with your secret string.
9
+ It's recommended for the password pepper to be at last 32 characters long and
10
+ randomly generated.
11
+
12
+ password_pepper "<long secret key>"
13
+
14
+ If your database already contains password hashes that were created without a
15
+ password pepper, these will get automatically updated with a password pepper
16
+ next time the user successfully enters their password.
17
+
18
+ You can rotate the password pepper as well, just make sure to add the previous
19
+ pepper to the +previous_password_peppers+ array. Password hashes using the old
20
+ pepper will get automatically updated on the next successful password match.
21
+
22
+ password_pepper "new pepper"
23
+ previous_password_peppers ["old pepper", ""]
24
+
25
+ The empty string above ensures password hashes without pepper are handled as
26
+ well.
27
+
28
+ Note that each entry in +previous_password_peppers+ will multiply the amount of
29
+ possible password checks during login, at least for incorrect passwords.
30
+
31
+ Additionally, when using this feature with the disallow_password_reuse feature,
32
+ the number of passwords checked when changing or resetting a password will be
33
+
34
+ (previous_password_peppers.length + 1) * previous_passwords_to_check
35
+
36
+ So if you have 2 entries in +previous_password_peppers+, using the default
37
+ value of 6 for +previous_passwords_to_check+, every time a password
38
+ is changed, there will be 18 password checks done, which will be quite slow.
39
+
40
+ == Auth Value Methods
41
+
42
+ password_pepper :: The secret string appended to passwords before they are hashed.
43
+ previous_password_peppers :: An array of password peppers that will be tried on an unsuccessful password match. Defaults to <tt>[""]</tt>, which allows introducing this feature with existing passwords.
44
+ password_pepper_update? :: Whether to update password hashes that use a pepper from +previous_password_peppers+ with a new pepper. Defaults to +true+.
@@ -0,0 +1,31 @@
1
+ = New Features
2
+
3
+ * A check_csrf configuration method has been added for checking
4
+ the CSRF token. This is useful in cases where the CSRF protection
5
+ is provided by something other than the Roda route_csrf plugin.
6
+
7
+ = Other Improvements
8
+
9
+ * When using the http_basic_auth feature, logged_in? now checks for
10
+ Basic authentication if the session is not already authenticated
11
+ and Basic authentication has not yet been checked. This increases
12
+ compatibility for applications that were using the http_basic_auth
13
+ feature in Rodauth 1.
14
+
15
+ * When creating accounts, the password field now correctly uses the
16
+ new-password autocomplete attribute instead of the current-password
17
+ autocomplete attribute.
18
+
19
+ * When using the jwt feature, Rodauth no longer checks CSRF tokens
20
+ in requests to Rodauth routes if the request submitted is a JSON
21
+ request, includes a JWT, or Rodauth has been configured in JSON-only
22
+ mode.
23
+
24
+ * When using the verify_account_grace_period feature, if there is an
25
+ unverified account without a password, do not consider the account
26
+ open. Attempting to login into the account in such a case now
27
+ shows a message letting the user know to verify the account.
28
+
29
+ * The json_response_body configuration method is now used consistently
30
+ in the jwt feature for all JSON responses. Previously, there were
31
+ some cases that did not use it.
@@ -0,0 +1,39 @@
1
+ = New Features
2
+
3
+ * When using the jwt_refresh feature, you can remove the current
4
+ refresh token when logging out by submitting the refresh token
5
+ in the logout request, the same as when submitting the refresh
6
+ token to obtain a new refresh token. You can also use a value
7
+ of "all" instead of the refresh token to remove all refresh
8
+ tokens when logging out.
9
+
10
+ * A rodauth.otp_last_use method has been added to the otp feature,
11
+ allowing you to determine when the otp was last used.
12
+
13
+ = Other Improvements
14
+
15
+ * When using multifactor authentication, rodauth.authenticated? and
16
+ rodauth.require_authentication now cache values in the session and
17
+ do not perform queries every time they are called.
18
+
19
+ * Many guides for common scenarios have been added to the
20
+ documentation. These augment Rodauth's existing comprehensive
21
+ feature documentation, which is aimed to be more of a reference
22
+ and less of a guide.
23
+
24
+ * When the verify_account_grace_period and email_auth features are
25
+ used with a multifactor authentication feature, and the
26
+ verify_account_set_password? configuration method is set to true,
27
+ Rodauth no longer raises a NoMethodError when checking if the
28
+ session was authenticated.
29
+
30
+ * In the verify_account feature, if verify_account_email_resend
31
+ returns false indicating no email was sent, an error message
32
+ is now used, instead of a success message.
33
+
34
+ * In the password_complexity feature, the password_dictionary
35
+ configuration method was previously ignored if the default
36
+ password dictionary file existed.
37
+
38
+ * Rodauth and all features that ship with it now have 100% branch
39
+ coverage.