authlogic 6.0.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/authlogic/acts_as_authentic/password.rb +1 -1
- data/lib/authlogic/crypto_providers/md5/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha1/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha256/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha512/v2.rb +1 -1
- data/lib/authlogic/errors.rb +1 -1
- data/lib/authlogic/session/base.rb +98 -43
- data/lib/authlogic/test_case/mock_cookie_jar.rb +35 -0
- data/lib/authlogic/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88e14eb91ceaf33fca0867ad9816d8ee719215bdb9f5ff26c2c4754d84c82dd8
|
4
|
+
data.tar.gz: 1dfbc1800a0fd0766bde87dfaa4a351b4b377e4240ad81aaa7d163c547d4d2a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9e01562988e0b0a1660b7fa51009d71a76c01bca17711d278fd9d5e7271c3ef0e165da9622a7049b15f45d994d108e51c6fff0689ad4afe063df62525ddc572
|
7
|
+
data.tar.gz: b0930fa9bc9d370cb71b1e502ece7885319429aff8f49039a8150621f9eb79bd9301c6e028933e156eb28f50a571a0586c23c918280a23f681bc7f45e440aa4f
|
@@ -102,7 +102,7 @@ module Authlogic
|
|
102
102
|
# The family of adaptive hash functions (BCrypt, SCrypt, PBKDF2) is the
|
103
103
|
# best choice for password storage today. We recommend SCrypt. Other
|
104
104
|
# one-way functions like SHA512 are inferior, but widely used.
|
105
|
-
#
|
105
|
+
# Reversible functions like AES256 are the worst choice, and we no
|
106
106
|
# longer support them.
|
107
107
|
#
|
108
108
|
# You can use the `transition_from_crypto_providers` option to gradually
|
@@ -20,7 +20,7 @@ module Authlogic
|
|
20
20
|
def encrypt(*tokens)
|
21
21
|
digest = tokens.flatten.join(join_token)
|
22
22
|
stretches.times { digest = Digest::MD5.digest(digest) }
|
23
|
-
digest.
|
23
|
+
digest.unpack1("H*")
|
24
24
|
end
|
25
25
|
|
26
26
|
# Does the crypted password match the tokens? Uses the same tokens that
|
@@ -43,7 +43,7 @@ module Authlogic
|
|
43
43
|
def encrypt(*tokens)
|
44
44
|
digest = tokens.flatten.join(join_token)
|
45
45
|
stretches.times { digest = Digest::SHA256.digest(digest) }
|
46
|
-
digest.
|
46
|
+
digest.unpack1("H*")
|
47
47
|
end
|
48
48
|
|
49
49
|
# Does the crypted password match the tokens? Uses the same tokens that
|
data/lib/authlogic/errors.rb
CHANGED
@@ -438,8 +438,7 @@ module Authlogic
|
|
438
438
|
|
439
439
|
class << self
|
440
440
|
attr_accessor(
|
441
|
-
:configured_password_methods
|
442
|
-
:configured_klass_methods
|
441
|
+
:configured_password_methods
|
443
442
|
)
|
444
443
|
end
|
445
444
|
attr_accessor(
|
@@ -956,6 +955,20 @@ module Authlogic
|
|
956
955
|
end
|
957
956
|
alias sign_cookie= sign_cookie
|
958
957
|
|
958
|
+
# Should the cookie be encrypted? If the controller adapter supports it, this is a
|
959
|
+
# measure to hide the contents of the cookie (e.g. persistence_token)
|
960
|
+
def encrypt_cookie(value = nil)
|
961
|
+
if value && !controller.cookies.respond_to?(:encrypted)
|
962
|
+
raise "Encrypted cookies not supported with #{controller.class}!"
|
963
|
+
end
|
964
|
+
if value && sign_cookie
|
965
|
+
raise "It is recommended to use encrypt_cookie instead of sign_cookie. " \
|
966
|
+
"You may not enable both options."
|
967
|
+
end
|
968
|
+
rw_config(:encrypt_cookie, value, false)
|
969
|
+
end
|
970
|
+
alias_method :encrypt_cookie=, :encrypt_cookie
|
971
|
+
|
959
972
|
# Works exactly like cookie_key, but for sessions. See cookie_key for more info.
|
960
973
|
#
|
961
974
|
# * <tt>Default:</tt> cookie_key
|
@@ -1060,24 +1073,10 @@ module Authlogic
|
|
1060
1073
|
# Constructor
|
1061
1074
|
# ===========
|
1062
1075
|
|
1063
|
-
# rubocop:disable Metrics/AbcSize
|
1064
1076
|
def initialize(*args)
|
1065
1077
|
@id = nil
|
1066
1078
|
self.scope = self.class.scope
|
1067
|
-
|
1068
|
-
# Creating an alias method for the "record" method based on the klass
|
1069
|
-
# name, so that we can do:
|
1070
|
-
#
|
1071
|
-
# session.user
|
1072
|
-
#
|
1073
|
-
# instead of:
|
1074
|
-
#
|
1075
|
-
# session.record
|
1076
|
-
unless self.class.configured_klass_methods
|
1077
|
-
self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
|
1078
|
-
self.class.configured_klass_methods = true
|
1079
|
-
end
|
1080
|
-
|
1079
|
+
define_record_alias_method
|
1081
1080
|
raise Activation::NotActivatedError unless self.class.activated?
|
1082
1081
|
unless self.class.configured_password_methods
|
1083
1082
|
configure_password_methods
|
@@ -1086,7 +1085,6 @@ module Authlogic
|
|
1086
1085
|
instance_variable_set("@#{password_field}", nil)
|
1087
1086
|
self.credentials = args
|
1088
1087
|
end
|
1089
|
-
# rubocop:enable Metrics/AbcSize
|
1090
1088
|
|
1091
1089
|
# Public instance methods
|
1092
1090
|
# =======================
|
@@ -1475,6 +1473,23 @@ module Authlogic
|
|
1475
1473
|
sign_cookie == true || sign_cookie == "true" || sign_cookie == "1"
|
1476
1474
|
end
|
1477
1475
|
|
1476
|
+
# If the cookie should be encrypted
|
1477
|
+
def encrypt_cookie
|
1478
|
+
return @encrypt_cookie if defined?(@encrypt_cookie)
|
1479
|
+
@encrypt_cookie = self.class.encrypt_cookie
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
# Accepts a boolean as to whether the cookie should be encrypted. If true
|
1483
|
+
# the cookie will be saved in an encrypted state.
|
1484
|
+
def encrypt_cookie=(value)
|
1485
|
+
@encrypt_cookie = value
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
# See encrypt_cookie
|
1489
|
+
def encrypt_cookie?
|
1490
|
+
encrypt_cookie == true || encrypt_cookie == "true" || encrypt_cookie == "1"
|
1491
|
+
end
|
1492
|
+
|
1478
1493
|
# The scope of the current object
|
1479
1494
|
def scope
|
1480
1495
|
@scope ||= {}
|
@@ -1492,24 +1507,21 @@ module Authlogic
|
|
1492
1507
|
# Determines if the information you provided for authentication is valid
|
1493
1508
|
# or not. If there is a problem with the information provided errors will
|
1494
1509
|
# be added to the errors object and this method will return false.
|
1510
|
+
#
|
1511
|
+
# @api public
|
1495
1512
|
def valid?
|
1496
1513
|
errors.clear
|
1497
1514
|
self.attempted_record = nil
|
1498
|
-
|
1499
|
-
run_callbacks(:before_validation)
|
1500
|
-
run_callbacks(new_session? ? :before_validation_on_create : :before_validation_on_update)
|
1515
|
+
run_the_before_validation_callbacks
|
1501
1516
|
|
1502
1517
|
# Run the `validate` callbacks, eg. `validate_by_password`.
|
1503
1518
|
# This is when `attempted_record` is set.
|
1504
1519
|
run_callbacks(:validate)
|
1505
1520
|
|
1506
1521
|
ensure_authentication_attempted
|
1507
|
-
|
1508
1522
|
if errors.empty?
|
1509
|
-
|
1510
|
-
run_callbacks(:after_validation)
|
1523
|
+
run_the_after_validation_callbacks
|
1511
1524
|
end
|
1512
|
-
|
1513
1525
|
save_record(attempted_record)
|
1514
1526
|
errors.empty?
|
1515
1527
|
end
|
@@ -1618,7 +1630,9 @@ module Authlogic
|
|
1618
1630
|
end
|
1619
1631
|
|
1620
1632
|
def cookie_jar
|
1621
|
-
if self.class.
|
1633
|
+
if self.class.encrypt_cookie
|
1634
|
+
controller.cookies.encrypted
|
1635
|
+
elsif self.class.sign_cookie
|
1622
1636
|
controller.cookies.signed
|
1623
1637
|
else
|
1624
1638
|
controller.cookies
|
@@ -1636,15 +1650,23 @@ module Authlogic
|
|
1636
1650
|
self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
|
1637
1651
|
end
|
1638
1652
|
|
1653
|
+
# @api private
|
1639
1654
|
def define_password_field_methods
|
1640
1655
|
return unless password_field
|
1641
|
-
|
1642
|
-
|
1656
|
+
define_password_field_writer_method
|
1657
|
+
define_password_field_reader_methods
|
1658
|
+
end
|
1643
1659
|
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1660
|
+
# The password should not be accessible publicly. This way forms using
|
1661
|
+
# form_for don't fill the password with the attempted password. To prevent
|
1662
|
+
# this we just create this method that is private.
|
1663
|
+
#
|
1664
|
+
# @api private
|
1665
|
+
def define_password_field_reader_methods
|
1666
|
+
unless respond_to?(password_field)
|
1667
|
+
# Deliberate no-op method, see rationale above.
|
1668
|
+
self.class.send(:define_method, password_field) {}
|
1669
|
+
end
|
1648
1670
|
self.class.class_eval(
|
1649
1671
|
<<-EOS, __FILE__, __LINE__ + 1
|
1650
1672
|
private
|
@@ -1655,6 +1677,28 @@ module Authlogic
|
|
1655
1677
|
)
|
1656
1678
|
end
|
1657
1679
|
|
1680
|
+
def define_password_field_writer_method
|
1681
|
+
unless respond_to?("#{password_field}=")
|
1682
|
+
self.class.send(:attr_writer, password_field)
|
1683
|
+
end
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
# Creating an alias method for the "record" method based on the klass
|
1687
|
+
# name, so that we can do:
|
1688
|
+
#
|
1689
|
+
# session.user
|
1690
|
+
#
|
1691
|
+
# instead of:
|
1692
|
+
#
|
1693
|
+
# session.record
|
1694
|
+
#
|
1695
|
+
# @api private
|
1696
|
+
def define_record_alias_method
|
1697
|
+
noun = klass_name.demodulize.underscore.to_sym
|
1698
|
+
return if respond_to?(noun)
|
1699
|
+
self.class.send(:alias_method, noun, :record)
|
1700
|
+
end
|
1701
|
+
|
1658
1702
|
def destroy_cookie
|
1659
1703
|
controller.cookies.delete cookie_key, domain: controller.cookie_domain
|
1660
1704
|
end
|
@@ -1700,13 +1744,8 @@ module Authlogic
|
|
1700
1744
|
|
1701
1745
|
# @api private
|
1702
1746
|
def generate_cookie_for_saving
|
1703
|
-
creds = ::Authlogic::CookieCredentials.new(
|
1704
|
-
record.persistence_token,
|
1705
|
-
record.send(record.class.primary_key),
|
1706
|
-
remember_me? ? remember_me_until : nil
|
1707
|
-
)
|
1708
1747
|
{
|
1709
|
-
value:
|
1748
|
+
value: generate_cookie_value.to_s,
|
1710
1749
|
expires: remember_me_until,
|
1711
1750
|
secure: secure,
|
1712
1751
|
httponly: httponly,
|
@@ -1715,6 +1754,14 @@ module Authlogic
|
|
1715
1754
|
}
|
1716
1755
|
end
|
1717
1756
|
|
1757
|
+
def generate_cookie_value
|
1758
|
+
::Authlogic::CookieCredentials.new(
|
1759
|
+
record.persistence_token,
|
1760
|
+
record.send(record.class.primary_key),
|
1761
|
+
remember_me? ? remember_me_until : nil
|
1762
|
+
)
|
1763
|
+
end
|
1764
|
+
|
1718
1765
|
# Returns a Proc to be executed by
|
1719
1766
|
# `ActionController::HttpAuthentication::Basic` when credentials are
|
1720
1767
|
# present in the HTTP request.
|
@@ -1893,6 +1940,18 @@ module Authlogic
|
|
1893
1940
|
attempted_record.failed_login_count = 0
|
1894
1941
|
end
|
1895
1942
|
|
1943
|
+
# @api private
|
1944
|
+
def run_the_after_validation_callbacks
|
1945
|
+
run_callbacks(new_session? ? :after_validation_on_create : :after_validation_on_update)
|
1946
|
+
run_callbacks(:after_validation)
|
1947
|
+
end
|
1948
|
+
|
1949
|
+
# @api private
|
1950
|
+
def run_the_before_validation_callbacks
|
1951
|
+
run_callbacks(:before_validation)
|
1952
|
+
run_callbacks(new_session? ? :before_validation_on_create : :before_validation_on_update)
|
1953
|
+
end
|
1954
|
+
|
1896
1955
|
# `args[0]` is the name of a model method, like
|
1897
1956
|
# `find_by_single_access_token` or `find_by_smart_case_login_field`.
|
1898
1957
|
def search_for_record(*args)
|
@@ -1930,11 +1989,7 @@ module Authlogic
|
|
1930
1989
|
end
|
1931
1990
|
|
1932
1991
|
def save_cookie
|
1933
|
-
|
1934
|
-
controller.cookies.signed[cookie_key] = generate_cookie_for_saving
|
1935
|
-
else
|
1936
|
-
controller.cookies[cookie_key] = generate_cookie_for_saving
|
1937
|
-
end
|
1992
|
+
cookie_jar[cookie_key] = generate_cookie_for_saving
|
1938
1993
|
end
|
1939
1994
|
|
1940
1995
|
# @api private
|
@@ -23,6 +23,10 @@ module Authlogic
|
|
23
23
|
def signed
|
24
24
|
@signed ||= MockSignedCookieJar.new(self)
|
25
25
|
end
|
26
|
+
|
27
|
+
def encrypted
|
28
|
+
@encrypted ||= MockEncryptedCookieJar.new(self)
|
29
|
+
end
|
26
30
|
end
|
27
31
|
|
28
32
|
# A mock of `ActionDispatch::Cookies::SignedKeyRotatingCookieJar`
|
@@ -35,6 +39,7 @@ module Authlogic
|
|
35
39
|
|
36
40
|
def initialize(parent_jar)
|
37
41
|
@parent_jar = parent_jar
|
42
|
+
parent_jar.each { |k, v| self[k] = v }
|
38
43
|
end
|
39
44
|
|
40
45
|
def [](val)
|
@@ -51,5 +56,35 @@ module Authlogic
|
|
51
56
|
@parent_jar[key] = options
|
52
57
|
end
|
53
58
|
end
|
59
|
+
|
60
|
+
class MockEncryptedCookieJar < MockCookieJar
|
61
|
+
attr_reader :parent_jar # helper for testing
|
62
|
+
|
63
|
+
def initialize(parent_jar)
|
64
|
+
@parent_jar = parent_jar
|
65
|
+
parent_jar.each { |k, v| self[k] = v }
|
66
|
+
end
|
67
|
+
|
68
|
+
def [](val)
|
69
|
+
encrypted_message = @parent_jar[val]
|
70
|
+
if encrypted_message
|
71
|
+
self.class.decrypt(encrypted_message)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def []=(key, options)
|
76
|
+
options[:value] = self.class.encrypt(options[:value])
|
77
|
+
@parent_jar[key] = options
|
78
|
+
end
|
79
|
+
|
80
|
+
# simple caesar cipher for testing
|
81
|
+
def self.encrypt(str)
|
82
|
+
str.unpack("U*").map(&:succ).pack("U*")
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.decrypt(str)
|
86
|
+
str.unpack("U*").map(&:pred).pack("U*")
|
87
|
+
end
|
88
|
+
end
|
54
89
|
end
|
55
90
|
end
|
data/lib/authlogic/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authlogic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Johnson
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-
|
13
|
+
date: 2020-05-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activemodel
|
@@ -176,14 +176,14 @@ dependencies:
|
|
176
176
|
requirements:
|
177
177
|
- - "~>"
|
178
178
|
- !ruby/object:Gem::Version
|
179
|
-
version: 0.
|
179
|
+
version: 0.80.1
|
180
180
|
type: :development
|
181
181
|
prerelease: false
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
184
|
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
|
-
version: 0.
|
186
|
+
version: 0.80.1
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
188
|
name: rubocop-performance
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|