rodauth 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ea58deac2998a11cd0cd4b17545eab5fce6fb0acd7751416fd521cbd77d6add
4
- data.tar.gz: c113c1131f5d756fd3aa5c1dbf083f40506b8822fb1c9b67537069c9e8695fba
3
+ metadata.gz: db02abed46d2dd511d07e2c8bf8640ca01f14fff595953a3c05b9a2cbe314511
4
+ data.tar.gz: 81f74322d49942d099789350c031c59227ec92b8eb6304dce9b4e15a91f2e60f
5
5
  SHA512:
6
- metadata.gz: 1fa2ce1d08a9f09e21d2fb1fe5b71ea3c6fc55181452302a35929229f0fad8c3c5d3d3324d73bee9c69daf0ff7a2d14ddbb731ef994bd3317512627233a69d28
7
- data.tar.gz: 7a188457006390730f00bc4a2ea5159c002dba66b300fd993929a5b5a491f2f4be0191c7e7c8e4b9e82b2e709b1a4e8ea8f5d335613f262671e1d68507cc2e26
6
+ metadata.gz: bda7da30406c315d6f467ac88701668c5288c93f8415bb1cffa280136cf7838a4fec81e865b8d0e607fef646df5d33a37e96f6e5e00dba2d6956757efc25ffc8
7
+ data.tar.gz: f19903ffb51eb7a87107fe0a24a33214fde275e732a6ac2a41e9bf3409f7b348c2ca8f9f87fe690d8b239fc5ae796f02a36ac32c7f615c8fca25f628d4173a80
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ === 2.4.0 (2020-09-21)
2
+
3
+ * Add session_key_prefix for more easily using separate session keys when using multiple configurations (janko) (#121)
4
+
5
+ * Add password_pepper feature for appending a secret key to passwords before they are hashed, supporting secret rotation (janko) (#119)
6
+
1
7
  === 2.3.0 (2020-08-21)
2
8
 
3
9
  * Return an error status instead of an invalid access token when trying to refresh JWT without an access token in the jwt_refresh feature (jeremyevans)
@@ -44,6 +44,7 @@ HTML and JSON API for all supported features.
44
44
  * Verify Account Grace Period (Don't require verification before login)
45
45
  * Password Grace Period (Don't require password entry if recently entered)
46
46
  * Password Complexity (More sophisticated checks)
47
+ * Password Pepper
47
48
  * Disallow Password Reuse
48
49
  * Disallow Common Passwords
49
50
  * Password Expiration
@@ -881,6 +882,7 @@ view the appropriate file in the doc directory.
881
882
  * {Password Complexity}[rdoc-ref:doc/password_complexity.rdoc]
882
883
  * {Password Expiration}[rdoc-ref:doc/password_expiration.rdoc]
883
884
  * {Password Grace Period}[rdoc-ref:doc/password_grace_period.rdoc]
885
+ * {Password Pepper}[rdoc-ref:doc/password_pepper.rdoc]
884
886
  * {Recovery Codes}[rdoc-ref:doc/recovery_codes.rdoc]
885
887
  * {Remember}[rdoc-ref:doc/remember.rdoc]
886
888
  * {Reset Password}[rdoc-ref:doc/reset_password.rdoc]
@@ -1062,6 +1064,18 @@ the name as an argument to use that configuration:
1062
1064
  r.rodauth
1063
1065
  end
1064
1066
 
1067
+ By default, alternate configurations will use the same session keys as the
1068
+ primary configuration, which may be undesirable. To ensure session state is
1069
+ separated between configurations, you can set a session key prefix for
1070
+ alternate configurations. If you are using the remember feature in both
1071
+ configurations, you may also want to set a different remember key in the
1072
+ alternate configuration:
1073
+
1074
+ plugin :rodauth, :name=>:secondary do
1075
+ session_key_prefix "secondary_"
1076
+ remember_cookie_key "_secondary_remember"
1077
+ end
1078
+
1065
1079
  === With Password Hashes Inside the Accounts Table
1066
1080
 
1067
1081
  You can use Rodauth if you are storing password hashes in the same
@@ -17,6 +17,7 @@ mark_input_fields_as_required? :: Whether input fields should be marked as requi
17
17
  prefix :: The routing prefix used for Rodauth routes. If you are calling in a routing subtree, this should be set to the root path of the subtree. This should include a leading slash if set, but not a trailing slash.
18
18
  require_bcrypt? :: Set to false to not require bcrypt, useful if using custom authentication.
19
19
  session_key :: The key in the session hash storing the primary key of the logged in account.
20
+ session_key_prefix :: The string that will be prepended to the default value for all session keys.
20
21
  skip_status_checks? :: Whether status checks should be skipped for accounts. Defaults to true unless enabling the verify_account or close_account features.
21
22
  title_instance_variable :: The instance variable to set in the Roda scope with the page title. The layout should use this instance variable if available to set the title of the page. You can use +set_title+ if setting the page title is not done through an instance variable.
22
23
 
@@ -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,22 @@
1
+ = New Features
2
+
3
+ * A password_pepper feature has been added. This allows you to use a
4
+ secret key (called a pepper) to append to passwords before hashing
5
+ and hash checking. Using this approach, if an attacker obtains the
6
+ password hash, it is unusable for cracking unless they can also
7
+ get access to the pepper.
8
+
9
+ The password_pepper feature also supports a list of previous peppers
10
+ that can be used to implement secret rotation and to support
11
+ compatibility with unpeppered passwords.
12
+
13
+ Rodauth by default uses database functions for password hash
14
+ checking on PostgreSQL, MySQL, and Microsoft SQL Server, which in
15
+ general provides more security than a password pepper, but both
16
+ approaches can be used simultaneously.
17
+
18
+ * A session_key_prefix configuration method has been added for
19
+ prefixing the values of all default session keys. This can be
20
+ useful if you are using multiple Rodauth configurations in the same
21
+ application and want to make sure the session keys for the separate
22
+ configurations do not overlap.
@@ -47,6 +47,7 @@ module Rodauth
47
47
  session_key :authenticated_by_session_key, :authenticated_by
48
48
  session_key :autologin_type_session_key, :autologin_type
49
49
  auth_value_method :prefix, ''
50
+ auth_value_method :session_key_prefix, nil
50
51
  auth_value_method :require_bcrypt?, true
51
52
  auth_value_method :mark_input_fields_as_required?, true
52
53
  auth_value_method :mark_input_fields_with_autocomplete?, true
@@ -393,9 +394,9 @@ module Rodauth
393
394
  def password_match?(password)
394
395
  if hash = get_password_hash
395
396
  if account_password_hash_column || !use_database_authentication_functions?
396
- BCrypt::Password.new(hash) == password
397
+ password_hash_match?(hash, password)
397
398
  else
398
- db.get(Sequel.function(function_name(:rodauth_valid_password_hash), account_id, BCrypt::Engine.hash_secret(password, hash)))
399
+ database_function_password_match?(:rodauth_valid_password_hash, account_id, password, hash)
399
400
  end
400
401
  end
401
402
  end
@@ -458,6 +459,14 @@ module Rodauth
458
459
 
459
460
  private
460
461
 
462
+ def database_function_password_match?(name, hash_id, password, salt)
463
+ db.get(Sequel.function(function_name(name), hash_id, BCrypt::Engine.hash_secret(password, salt)))
464
+ end
465
+
466
+ def password_hash_match?(hash, password)
467
+ BCrypt::Password.new(hash) == password
468
+ end
469
+
461
470
  def convert_token_key(key)
462
471
  if key && hmac_secret
463
472
  compute_hmac(key)
@@ -493,6 +502,7 @@ module Rodauth
493
502
  end
494
503
 
495
504
  def convert_session_key(key)
505
+ key = "#{session_key_prefix}#{key}".to_sym if session_key_prefix
496
506
  scope.opts[:sessions_convert_symbols] ? key.to_s : key
497
507
  end
498
508
 
@@ -51,11 +51,13 @@ module Rodauth
51
51
  return true if salts.empty?
52
52
 
53
53
  salts.any? do |hash_id, salt|
54
- db.get(Sequel.function(function_name(:rodauth_previous_password_hash_match), hash_id, BCrypt::Engine.hash_secret(password, salt)))
54
+ database_function_password_match?(:rodauth_previous_password_hash_match, hash_id, password, salt)
55
55
  end
56
56
  else
57
57
  # :nocov:
58
- previous_password_ds.select_map(previous_password_hash_column).any?{|hash| BCrypt::Password.new(hash) == password}
58
+ previous_password_ds.select_map(previous_password_hash_column).any? do |hash|
59
+ password_hash_match?(hash, password)
60
+ end
59
61
  # :nocov:
60
62
  end
61
63
 
@@ -0,0 +1,45 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Rodauth
4
+ Feature.define(:password_pepper, :PasswordPepper) do
5
+ depends :login_password_requirements_base
6
+
7
+ auth_value_method :password_pepper, nil
8
+ auth_value_method :previous_password_peppers, [""]
9
+ auth_value_method :password_pepper_update?, true
10
+
11
+ def password_match?(password)
12
+ if (result = super) && @previous_pepper_matched && password_pepper_update?
13
+ set_password(password)
14
+ end
15
+
16
+ result
17
+ end
18
+
19
+ private
20
+
21
+ def password_hash(password)
22
+ super(password + password_pepper.to_s)
23
+ end
24
+
25
+ def password_hash_match?(hash, password)
26
+ return super if password_pepper.nil?
27
+
28
+ return true if super(hash, password + password_pepper)
29
+
30
+ @previous_pepper_matched = previous_password_peppers.any? do |pepper|
31
+ super(hash, password + pepper)
32
+ end
33
+ end
34
+
35
+ def database_function_password_match?(name, hash_id, password, salt)
36
+ return super if password_pepper.nil?
37
+
38
+ return true if super(name, hash_id, password + password_pepper, salt)
39
+
40
+ @previous_pepper_matched = previous_password_peppers.any? do |pepper|
41
+ super(name, hash_id, password + pepper, salt)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -58,7 +58,9 @@ module Rodauth
58
58
  if [remember_remember_param_value, remember_forget_param_value, remember_disable_param_value].include?(remember)
59
59
  transaction do
60
60
  before_remember
61
+ # :nocov:
61
62
  case remember
63
+ # :nocov:
62
64
  when remember_remember_param_value
63
65
  remember_login
64
66
  when remember_forget_param_value
@@ -6,7 +6,7 @@ module Rodauth
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 3
9
+ MINOR = 4
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
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.3.0
4
+ version: 2.4.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: 2020-08-21 00:00:00.000000000 Z
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -277,6 +277,7 @@ extra_rdoc_files:
277
277
  - doc/webauthn_verify_account.rdoc
278
278
  - doc/active_sessions.rdoc
279
279
  - doc/audit_logging.rdoc
280
+ - doc/password_pepper.rdoc
280
281
  - doc/release_notes/1.17.0.txt
281
282
  - doc/release_notes/1.0.0.txt
282
283
  - doc/release_notes/1.1.0.txt
@@ -305,6 +306,7 @@ extra_rdoc_files:
305
306
  - doc/release_notes/2.1.0.txt
306
307
  - doc/release_notes/2.2.0.txt
307
308
  - doc/release_notes/2.3.0.txt
309
+ - doc/release_notes/2.4.0.txt
308
310
  files:
309
311
  - CHANGELOG
310
312
  - MIT-LICENSE
@@ -357,6 +359,7 @@ files:
357
359
  - doc/password_complexity.rdoc
358
360
  - doc/password_expiration.rdoc
359
361
  - doc/password_grace_period.rdoc
362
+ - doc/password_pepper.rdoc
360
363
  - doc/recovery_codes.rdoc
361
364
  - doc/release_notes/1.0.0.txt
362
365
  - doc/release_notes/1.1.0.txt
@@ -386,6 +389,7 @@ files:
386
389
  - doc/release_notes/2.1.0.txt
387
390
  - doc/release_notes/2.2.0.txt
388
391
  - doc/release_notes/2.3.0.txt
392
+ - doc/release_notes/2.4.0.txt
389
393
  - doc/remember.rdoc
390
394
  - doc/reset_password.rdoc
391
395
  - doc/session_expiration.rdoc
@@ -429,6 +433,7 @@ files:
429
433
  - lib/rodauth/features/password_complexity.rb
430
434
  - lib/rodauth/features/password_expiration.rb
431
435
  - lib/rodauth/features/password_grace_period.rb
436
+ - lib/rodauth/features/password_pepper.rb
432
437
  - lib/rodauth/features/recovery_codes.rb
433
438
  - lib/rodauth/features/remember.rb
434
439
  - lib/rodauth/features/reset_password.rb