uber_login 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/uber_login/configuration.rb +23 -0
- data/lib/uber_login/cookie_manager.rb +39 -61
- data/lib/uber_login/session_manager.rb +38 -0
- data/lib/uber_login/storage.rb +31 -0
- data/lib/uber_login/token_encoder.rb +36 -0
- data/lib/uber_login/token_validator.rb +28 -0
- data/lib/uber_login/version.rb +1 -1
- data/lib/uber_login.rb +58 -36
- data/spec/cookie_manager_spec.rb +48 -76
- data/spec/session_manager_spec.rb +80 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/storage_spec.rb +0 -0
- data/spec/token_encoder_spec.rb +58 -0
- data/spec/token_validator_spec.rb +66 -0
- data/spec/uber_login_spec.rb +101 -72
- metadata +13 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NjcyNWVjZmViMmQ3ZTY4MDljODFjYjAxZDc2YmY5YmE4ZDEyNjhiZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZDg0ZTA4MzZkODQ4ZThjN2FkOTYyNjllMTk5MDY1ZmUxZDdlN2NmYg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NWFjODkyYjYwN2FlNDFkY2I0NTUwZDZlMmIyMGJhMzRiNTg5MGM1YmY0YzVj
|
10
|
+
M2Y0YTBhY2U0NjNkNThiMDg4MDJlYjM4NjAwNWUxNzcxYTc0N2E1MjdmZDZh
|
11
|
+
NmQzYWNkN2Q0YzhhODNlYmQ2ZmNmYTNmMzZjZGRlMzdhNmNkMTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MTJmMWI1MDhjODQzMWZlNWEzYjk2YzQxMTYxYzc3MGEzNWMyNDM5ZWU2MTc1
|
14
|
+
NDM0ZjQ2OGVhMjgxMzlkN2QyZGJlNThhODNiMDNmOWFjYTI1ZWU5MjVmMWVk
|
15
|
+
ZjlmOWI5N2JjMGJmYmY0MjdmNGNiODkzZjc0YWZkMzg2OGZiZTU=
|
@@ -2,14 +2,37 @@
|
|
2
2
|
# Use this class in app/config/initializers to change configuration parameters.
|
3
3
|
module UberLogin
|
4
4
|
class Configuration
|
5
|
+
# Allow the same user to login on many different devices.
|
6
|
+
# This is only effective if strong_sessions is +true+. Otherwise it only affects persistent logins.
|
7
|
+
# Defaults to +true+
|
5
8
|
attr_accessor :allow_multiple_login
|
9
|
+
|
10
|
+
# The validity of a login token (be it a cookie or session token). Tokens whose age is larger than that are
|
11
|
+
# considered expired and not valid.
|
12
|
+
# Defaults to +nil+ (no expiration)
|
6
13
|
attr_accessor :token_expiration
|
14
|
+
|
15
|
+
# A token is considered valid only if brought by the same IP address to which it was assigned.
|
16
|
+
# This would provide a very effective solution against Cookie sniffing, unless it would affect legitimate users a
|
17
|
+
# lot. 99% of ISPs will change user IP on each connecition. Also mobile devices might change IP many times in a
|
18
|
+
# hour. Setting this to true may disconnect many mobile users each minute.
|
19
|
+
# Only decently usable in a private network where all IPs are static (or if you're really paranoid).
|
20
|
+
# Defaults to +false+
|
7
21
|
attr_accessor :tie_tokens_to_ip
|
8
22
|
|
23
|
+
# Non persistent sessions are saved to the database too. On each request the session token is checked against the
|
24
|
+
# database just like the cookies one. It won't refresh it, however.
|
25
|
+
# This allows you to do nice things, like logging out users, just by removing the token from the database. Or having
|
26
|
+
# a full list of open sessions of any kind on any device.
|
27
|
+
# Even though this is strongly suggested to be +true+, it might impact performance, issuing a query on almost
|
28
|
+
# each page load. Be sure to index :uid and :sequence together on the +login_tokens+ table.
|
29
|
+
attr_accessor :strong_sessions
|
30
|
+
|
9
31
|
def initialize
|
10
32
|
self.allow_multiple_login = true
|
11
33
|
self.token_expiration = nil
|
12
34
|
self.tie_tokens_to_ip = false
|
35
|
+
self.strong_sessions = true
|
13
36
|
end
|
14
37
|
end
|
15
38
|
|
@@ -1,66 +1,44 @@
|
|
1
|
+
require 'uber_login/storage'
|
2
|
+
require 'uber_login/token_encoder'
|
3
|
+
require 'uber_login/token_validator'
|
4
|
+
|
1
5
|
##
|
2
6
|
# This class handles the +:uid+ and +:ulogin+ cookies
|
3
7
|
# It builds and sets the cookies, clears them, checks for their validity.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
def sequence_and_token
|
42
|
-
@cookies[:ulogin].split(':')
|
43
|
-
end
|
44
|
-
|
45
|
-
def sequence
|
46
|
-
sequence_and_token[0]
|
47
|
-
end
|
48
|
-
|
49
|
-
def token
|
50
|
-
sequence_and_token[1]
|
51
|
-
end
|
52
|
-
|
53
|
-
# Validity checks
|
54
|
-
|
55
|
-
def token_match(row)
|
56
|
-
BCrypt::Password.new(row.token) == token
|
57
|
-
end
|
58
|
-
|
59
|
-
def ip_equality(row)
|
60
|
-
row.ip_address == @request.remote_ip
|
61
|
-
end
|
62
|
-
|
63
|
-
def expiration(row)
|
64
|
-
row.updated_at >= Time.now - UberLogin.configuration.token_expiration
|
8
|
+
module UberLogin
|
9
|
+
class CookieManager
|
10
|
+
def initialize(cookies, request)
|
11
|
+
@cookies = cookies
|
12
|
+
@request = request
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Sets the +:uid+ and +:ulogin+ cookies for next login
|
17
|
+
def persistent_login(uid, composite)
|
18
|
+
@cookies.permanent[:uid] = uid
|
19
|
+
@cookies.permanent[:ulogin] = TokenEncoder.encode_array composite
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Clears +:uid+ and +:ulogin+ cookies
|
24
|
+
def clear
|
25
|
+
@cookies.delete :uid
|
26
|
+
@cookies.delete :ulogin
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns true if cookies are considered valid from TokenEncoder validation rules
|
31
|
+
def valid?
|
32
|
+
token_row = Storage.find_composite(@cookies[:uid], @cookies[:ulogin])
|
33
|
+
TokenValidator.new(TokenEncoder.token(@cookies[:ulogin]), @request).valid?(token_row)
|
34
|
+
rescue
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Returns true if the +:uid+ and +:ulogin+ cookies are set
|
40
|
+
def login_cookies?
|
41
|
+
@cookies[:uid] and @cookies[:ulogin]
|
42
|
+
end
|
65
43
|
end
|
66
44
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'uber_login/storage'
|
2
|
+
require 'uber_login/token_encoder'
|
3
|
+
require 'uber_login/token_validator'
|
4
|
+
|
5
|
+
##
|
6
|
+
# This class handles the +:uid+ and +:ulogin+ session variables
|
7
|
+
# It builds and sets the session variables, clears them, checks for their validity.
|
8
|
+
module UberLogin
|
9
|
+
class SessionManager
|
10
|
+
def initialize(session, request)
|
11
|
+
@session = session
|
12
|
+
@request = request
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Sets the +:uid+ and +:ulogin+ session variables
|
17
|
+
def login(uid, composite)
|
18
|
+
@session[:uid] = uid
|
19
|
+
@session[:ulogin] = TokenEncoder.encode_array(composite) if UberLogin.configuration.strong_sessions
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Clears +:uid+ and +:ulogin+ session variables
|
24
|
+
def clear
|
25
|
+
@session.delete :uid
|
26
|
+
@session.delete :ulogin
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns true if the session is considered valid from TokenEncoder validation rules
|
31
|
+
def valid?
|
32
|
+
token_row = Storage.find_composite(@session[:uid], @session[:ulogin])
|
33
|
+
TokenValidator.new(TokenEncoder.token(@session[:ulogin]), @request).valid?(token_row)
|
34
|
+
rescue
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module UberLogin
|
2
|
+
class Storage
|
3
|
+
class << self
|
4
|
+
def find(uid, sequence)
|
5
|
+
LoginToken.find_by(uid: uid, sequence: sequence)
|
6
|
+
end
|
7
|
+
|
8
|
+
def find_composite(uid, composite)
|
9
|
+
find(uid, TokenEncoder.sequence(composite))
|
10
|
+
rescue # composite might invalid if cookies are tampered
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def build(uid, composite)
|
15
|
+
LoginToken.new(
|
16
|
+
uid: uid,
|
17
|
+
sequence: TokenEncoder.sequence(composite),
|
18
|
+
token: TokenEncoder.token_hash(composite)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_all(uid)
|
23
|
+
LoginToken.destroy_all(uid: uid)
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete_all_but(uid, composite)
|
27
|
+
# TODO: How to make this ORM agnostic?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module UberLogin
|
4
|
+
class TokenEncoder
|
5
|
+
class << self
|
6
|
+
def generate
|
7
|
+
# 9 and 21 are both multiple of 3, so we do not get base64 padding (==)
|
8
|
+
[ SecureRandom.urlsafe_base64(9), SecureRandom.base64(21) ]
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode(sequence, token)
|
12
|
+
encode_array [ sequence, token ]
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode_array(composite_array)
|
16
|
+
composite_array.join(':')
|
17
|
+
end
|
18
|
+
|
19
|
+
def decode(composite)
|
20
|
+
composite.split(':')
|
21
|
+
end
|
22
|
+
|
23
|
+
def sequence(composite)
|
24
|
+
decode(composite)[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
def token(composite)
|
28
|
+
decode(composite)[1]
|
29
|
+
end
|
30
|
+
|
31
|
+
def token_hash(composite)
|
32
|
+
BCrypt::Password.create(token(composite)).to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module UberLogin
|
2
|
+
class TokenValidator
|
3
|
+
def initialize(token, request)
|
4
|
+
@token = token
|
5
|
+
@request = request
|
6
|
+
@validity_checks = [ :token_match ]
|
7
|
+
@validity_checks << :ip_equality if UberLogin.configuration.tie_tokens_to_ip
|
8
|
+
@validity_checks << :expiration if UberLogin.configuration.token_expiration
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?(row)
|
12
|
+
@validity_checks.all? { |check| send(check, row) }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def token_match(row)
|
17
|
+
BCrypt::Password.new(row.token) == @token
|
18
|
+
end
|
19
|
+
|
20
|
+
def ip_equality(row)
|
21
|
+
row.ip_address == @request.remote_ip
|
22
|
+
end
|
23
|
+
|
24
|
+
def expiration(row)
|
25
|
+
row.updated_at >= Time.now - UberLogin.configuration.token_expiration
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/uber_login/version.rb
CHANGED
data/lib/uber_login.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'uber_login/version'
|
2
2
|
require 'uber_login/cookie_manager'
|
3
3
|
require 'uber_login/configuration'
|
4
|
+
require 'uber_login/session_manager'
|
4
5
|
require 'securerandom'
|
5
6
|
require 'bcrypt'
|
6
7
|
require 'user_agent'
|
@@ -8,7 +9,10 @@ require 'user_agent'
|
|
8
9
|
module UberLogin
|
9
10
|
##
|
10
11
|
# Returns the logged in user.
|
11
|
-
# If session[+:uid+] is set
|
12
|
+
# If session[+:uid+] is set:
|
13
|
+
# * if strong sessions are enabled, it checks for session[+:ulogin+] and tests its value against the database
|
14
|
+
# * if strong sessions are not enabled, it only returns the corresponding +User+
|
15
|
+
#
|
12
16
|
# If session[+:uid+] is NOT set but cookies[+:uid+] and cookies[+:ulogin+] ARE:
|
13
17
|
# * It dissects +:ulogin+ into Sequence and Token
|
14
18
|
# * Looks for a LoginToken from UID and Sequence
|
@@ -26,24 +30,31 @@ module UberLogin
|
|
26
30
|
# Logs in the given +user+
|
27
31
|
# If +remember+ is true all the needed cookies are set.
|
28
32
|
# session[+:uid+] is set to user.id
|
33
|
+
# If strong sessions are enabled session[+:ulogin+] is set to the same value that cookies[+:ulogin+] would have
|
29
34
|
def login(user, remember = false)
|
30
35
|
logout_all unless UberLogin.configuration.allow_multiple_login
|
31
36
|
|
32
|
-
|
33
|
-
|
37
|
+
if strong_sessions or remember
|
38
|
+
composite = generate_and_save_token(user.id)
|
39
|
+
cookie_manager.persistent_login(user.id, composite) if remember
|
40
|
+
else
|
41
|
+
composite = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
session_manager.login(user.id, composite)
|
34
45
|
end
|
35
46
|
|
36
47
|
##
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
48
|
+
# If sequence is nil it clears the current session and if remember cookies are in place they're cleared
|
49
|
+
# and corresponding token removed from the database.
|
50
|
+
# If sequence is not nil it only removes the sequence and token from the database.
|
40
51
|
def logout(sequence = nil)
|
41
|
-
if sequence
|
42
|
-
delete_from_database
|
43
|
-
|
44
|
-
session.delete(:uid)
|
45
|
-
delete_from_database if cookies[:uid]
|
52
|
+
if sequence.nil? or sequence == current_sequence
|
53
|
+
delete_from_database if cookies[:uid] or strong_sessions
|
54
|
+
session_manager.clear
|
46
55
|
cookie_manager.clear
|
56
|
+
else
|
57
|
+
delete_from_database(sequence)
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
@@ -51,8 +62,8 @@ module UberLogin
|
|
51
62
|
# Deletes all "remember me" session for this user from whatever device
|
52
63
|
# he/she has ever used to login.
|
53
64
|
def logout_all
|
54
|
-
|
55
|
-
|
65
|
+
Storage.delete_all session[:uid]
|
66
|
+
session_manager.clear
|
56
67
|
cookie_manager.clear
|
57
68
|
end
|
58
69
|
|
@@ -61,11 +72,19 @@ module UberLogin
|
|
61
72
|
@cookie_manager ||= CookieManager.new(cookies, request)
|
62
73
|
end
|
63
74
|
|
75
|
+
def session_manager
|
76
|
+
@session_manager ||= SessionManager.new(session, request)
|
77
|
+
end
|
78
|
+
|
64
79
|
# See +current_user+
|
65
80
|
def current_user_uncached
|
66
|
-
|
67
|
-
|
68
|
-
|
81
|
+
if session[:uid]
|
82
|
+
logout if strong_sessions and !session_manager.valid?
|
83
|
+
else
|
84
|
+
login_from_cookies if cookie_manager.login_cookies?
|
85
|
+
end
|
86
|
+
|
87
|
+
User.find(session[:uid]) rescue nil
|
69
88
|
end
|
70
89
|
|
71
90
|
##
|
@@ -74,6 +93,7 @@ module UberLogin
|
|
74
93
|
if cookie_manager.valid?
|
75
94
|
session[:uid] = cookies[:uid]
|
76
95
|
generate_new_token
|
96
|
+
session[:ulogin] = cookies[:ulogin]
|
77
97
|
session[:uid]
|
78
98
|
else
|
79
99
|
cookie_manager.clear
|
@@ -86,7 +106,8 @@ module UberLogin
|
|
86
106
|
# Sets the user cookies to match the new values
|
87
107
|
def generate_new_token
|
88
108
|
delete_from_database
|
89
|
-
|
109
|
+
composite = generate_and_save_token(cookies[:uid])
|
110
|
+
cookie_manager.persistent_login(cookies[:uid], composite)
|
90
111
|
end
|
91
112
|
|
92
113
|
##
|
@@ -96,21 +117,16 @@ module UberLogin
|
|
96
117
|
#
|
97
118
|
# +:sequence+ is used to choose between all possible user login tokens
|
98
119
|
# +:token+ is stored +bcrypt+ed in the database and then compared on login
|
99
|
-
def
|
100
|
-
sequence, token =
|
101
|
-
|
102
|
-
|
120
|
+
def generate_and_save_token(uid)
|
121
|
+
sequence, token = TokenEncoder.generate
|
122
|
+
save_to_database(uid, sequence, token)
|
123
|
+
[ sequence, token ]
|
103
124
|
end
|
104
125
|
|
105
126
|
##
|
106
127
|
# Creates a LoginToken based on the +uid+, +sequence+ and hashed +token+
|
107
|
-
def save_to_database
|
108
|
-
token_row =
|
109
|
-
uid: cookies[:uid],
|
110
|
-
sequence: cookie_manager.sequence,
|
111
|
-
token: cookie_manager.hashed_token
|
112
|
-
)
|
113
|
-
|
128
|
+
def save_to_database(uid, sequence, token)
|
129
|
+
token_row = Storage.build(uid, TokenEncoder.encode(sequence, token))
|
114
130
|
set_user_data token_row
|
115
131
|
|
116
132
|
token_row.save!
|
@@ -119,15 +135,13 @@ module UberLogin
|
|
119
135
|
##
|
120
136
|
# Removes a LoginToken with current +uid+ and given +sequence+
|
121
137
|
# If +sequence+ is nil it is taken from the cookies.
|
138
|
+
#
|
139
|
+
# A token might have already been destroyed from another client with the intent of disconnecting
|
140
|
+
# the current session.
|
122
141
|
def delete_from_database(sequence = nil)
|
123
|
-
sequence = sequence ||
|
124
|
-
token =
|
125
|
-
token.destroy
|
126
|
-
end
|
127
|
-
|
128
|
-
def generate_sequence_and_token
|
129
|
-
# 9 and 21 are both multiple of 3, so we do not get base64 padding (==)
|
130
|
-
[ SecureRandom.base64(9), SecureRandom.base64(21) ]
|
142
|
+
sequence = sequence || current_sequence
|
143
|
+
token = Storage.find(cookies[:uid] || session[:uid], sequence)
|
144
|
+
token.destroy if token
|
131
145
|
end
|
132
146
|
|
133
147
|
def set_user_data(row)
|
@@ -137,4 +151,12 @@ module UberLogin
|
|
137
151
|
row.os = user_agent.os if row.respond_to? :os=
|
138
152
|
row.browser = user_agent.browser + ' ' + user_agent.version if row.respond_to? :browser=
|
139
153
|
end
|
154
|
+
|
155
|
+
def strong_sessions
|
156
|
+
UberLogin.configuration.strong_sessions
|
157
|
+
end
|
158
|
+
|
159
|
+
def current_sequence
|
160
|
+
TokenEncoder.sequence(cookies[:ulogin] || session[:ulogin])
|
161
|
+
end
|
140
162
|
end
|
data/spec/cookie_manager_spec.rb
CHANGED
@@ -1,60 +1,54 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe CookieManager do
|
4
|
-
let(:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
before { LoginToken.stub(:find_by).and_return fake_token }
|
16
|
-
|
17
|
-
it 'always executes token_match' do
|
18
|
-
expect(cookie_manager).to receive(:token_match)
|
19
|
-
cookie_manager.valid?
|
20
|
-
end
|
3
|
+
describe UberLogin::CookieManager do
|
4
|
+
let(:user) { double(id: 100) }
|
5
|
+
let(:controller) { ApplicationController.new }
|
6
|
+
let(:session) { controller.session }
|
7
|
+
let(:cookies) { controller.cookies }
|
8
|
+
let(:cookie_manager) { UberLogin::CookieManager.new(cookies, FakeRequest.new) }
|
9
|
+
|
10
|
+
describe '#persistent_login' do
|
11
|
+
it 'sets the :uid cookie' do
|
12
|
+
cookie_manager.persistent_login(100, [ 'dead', 'beef' ])
|
13
|
+
expect(cookies[:uid]).to eq 100
|
14
|
+
end
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
it 'sets the :ulogin cookie' do
|
17
|
+
cookie_manager.persistent_login(100, [ 'dead', 'beef' ])
|
18
|
+
expect(cookies[:ulogin]).to eq 'dead:beef'
|
19
|
+
end
|
20
|
+
end
|
26
21
|
|
27
|
-
|
28
|
-
|
22
|
+
describe '#clear' do
|
23
|
+
before { controller.login(user, true) }
|
29
24
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
25
|
+
it 'deletes the :uid cookie' do
|
26
|
+
cookie_manager.clear
|
27
|
+
expect(cookies[:uid]).to be_nil
|
28
|
+
end
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
it 'deletes the :ulogin cookie' do
|
31
|
+
cookie_manager.clear
|
32
|
+
expect(cookies[:ulogin]).to be_nil
|
33
|
+
end
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
36
|
+
describe '#valid?' do
|
37
|
+
before { controller.login(user, true) }
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
cookie_manager.valid?
|
47
|
-
end
|
48
|
-
end
|
39
|
+
context 'User id and sequence combination is found' do
|
40
|
+
before { UberLogin::Storage.stub(:find_composite).and_return user }
|
49
41
|
|
50
42
|
context 'all checks return true' do
|
43
|
+
before { UberLogin::TokenValidator.any_instance.stub(:valid?).and_return true }
|
44
|
+
|
51
45
|
it 'returns true' do
|
52
46
|
expect(cookie_manager.valid?).to be_true
|
53
47
|
end
|
54
48
|
end
|
55
49
|
|
56
50
|
context 'any check fails' do
|
57
|
-
before {
|
51
|
+
before { UberLogin::TokenValidator.any_instance.stub(:valid?).and_return false }
|
58
52
|
|
59
53
|
it 'returns false' do
|
60
54
|
expect(cookie_manager.valid?).to be_false
|
@@ -63,7 +57,7 @@ describe CookieManager do
|
|
63
57
|
end
|
64
58
|
|
65
59
|
context 'User id and sequence combination is not found' do
|
66
|
-
before {
|
60
|
+
before { UberLogin::Storage.stub(:find).and_return nil }
|
67
61
|
|
68
62
|
it 'returns false' do
|
69
63
|
expect(cookie_manager.valid?).to be_false
|
@@ -71,45 +65,23 @@ describe CookieManager do
|
|
71
65
|
end
|
72
66
|
end
|
73
67
|
|
74
|
-
describe '#
|
75
|
-
before {
|
68
|
+
describe '#login_cookies?' do
|
69
|
+
before { controller.login(user, true) }
|
76
70
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
it 'returns false if tokens are not matched' do
|
83
|
-
row = double(token: BCrypt::Password.create('s3cr3t', cost: 1))
|
84
|
-
expect(cookie_manager.token_match(row)).to be_false
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe '#ip_equality' do
|
89
|
-
before { FakeRequest.any_instance.stub(:remote_ip).and_return '10.10.10.10' }
|
90
|
-
|
91
|
-
it 'returns true if IPs are equal' do
|
92
|
-
row = double(ip_address: '10.10.10.10')
|
93
|
-
expect(cookie_manager.ip_equality(row)).to be_true
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'returns false if IPs are different' do
|
97
|
-
row = double(ip_address: '192.168.1.1')
|
98
|
-
expect(cookie_manager.ip_equality(row)).to be_false
|
71
|
+
context 'both cookies are set' do
|
72
|
+
it 'returns true' do
|
73
|
+
expect(cookie_manager.login_cookies?).to be_true
|
74
|
+
end
|
99
75
|
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe '#expiration' do
|
103
|
-
before { UberLogin.configuration.token_expiration = 86400 }
|
104
76
|
|
105
|
-
it 'returns
|
106
|
-
|
107
|
-
expect(cookie_manager.
|
77
|
+
it 'returns false if uid is missing' do
|
78
|
+
cookies.delete :uid
|
79
|
+
expect(cookie_manager.login_cookies?).to be_false
|
108
80
|
end
|
109
81
|
|
110
|
-
it 'returns false if
|
111
|
-
|
112
|
-
expect(cookie_manager.
|
82
|
+
it 'returns false if ulogin is missing' do
|
83
|
+
cookies.delete :ulogin
|
84
|
+
expect(cookie_manager.login_cookies?).to be_false
|
113
85
|
end
|
114
86
|
end
|
115
87
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UberLogin::SessionManager do
|
4
|
+
let(:user) { double(id: 100) }
|
5
|
+
let(:controller) { ApplicationController.new }
|
6
|
+
let(:session) { controller.session }
|
7
|
+
let(:cookies) { controller.cookies }
|
8
|
+
let(:session_manager) { UberLogin::SessionManager.new(session, FakeRequest.new) }
|
9
|
+
|
10
|
+
describe '#login' do
|
11
|
+
it 'sets the :uid variable' do
|
12
|
+
session_manager.login(100, [ 'dead', 'beef' ])
|
13
|
+
expect(session[:uid]).to eq 100
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'strong_sessions are not enabled' do
|
17
|
+
before { UberLogin.configuration.strong_sessions = false }
|
18
|
+
|
19
|
+
it 'does not set the :ulogin cookie' do
|
20
|
+
session_manager.login(100, [ 'dead', 'beef' ])
|
21
|
+
expect(session[:ulogin]).to be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'strong_sessions are enabled' do
|
26
|
+
before { UberLogin.configuration.strong_sessions = true }
|
27
|
+
|
28
|
+
it 'sets the :ulogin cookie' do
|
29
|
+
session_manager.login(100, [ 'dead', 'beef' ])
|
30
|
+
expect(session[:ulogin]).to_not be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#clear' do
|
36
|
+
before { controller.login(user, true) }
|
37
|
+
|
38
|
+
it 'deletes the :uid variable' do
|
39
|
+
session_manager.clear
|
40
|
+
expect(session[:uid]).to be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'deletes the :ulogin variable' do
|
44
|
+
session_manager.clear
|
45
|
+
expect(session[:ulogin]).to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#valid?' do
|
50
|
+
before { controller.login(user, true) }
|
51
|
+
|
52
|
+
context 'User id and sequence combination is found' do
|
53
|
+
before { UberLogin::Storage.stub(:find_composite).and_return user }
|
54
|
+
|
55
|
+
context 'all checks return true' do
|
56
|
+
before { UberLogin::TokenValidator.any_instance.stub(:valid?).and_return true }
|
57
|
+
|
58
|
+
it 'returns true' do
|
59
|
+
expect(session_manager.valid?).to be_true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'any check fails' do
|
64
|
+
before { UberLogin::TokenValidator.any_instance.stub(:valid?).and_return false }
|
65
|
+
|
66
|
+
it 'returns false' do
|
67
|
+
expect(session_manager.valid?).to be_false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'User id and sequence combination is not found' do
|
73
|
+
before { UberLogin::Storage.stub(:find).and_return nil }
|
74
|
+
|
75
|
+
it 'returns false' do
|
76
|
+
expect(session_manager.valid?).to be_false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -63,6 +63,10 @@ class LoginToken
|
|
63
63
|
new
|
64
64
|
end
|
65
65
|
|
66
|
+
def self.destroy_all(hash)
|
67
|
+
|
68
|
+
end
|
69
|
+
|
66
70
|
def updated_at
|
67
71
|
Time.now - 100
|
68
72
|
end
|
@@ -78,6 +82,6 @@ class User
|
|
78
82
|
end
|
79
83
|
|
80
84
|
def self.find(id)
|
81
|
-
User.new(id: id)
|
85
|
+
id ? User.new(id: id) : nil
|
82
86
|
end
|
83
87
|
end
|
File without changes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe UberLogin::TokenEncoder do
|
2
|
+
describe '#generate' do
|
3
|
+
it 'returns an array of size 2' do
|
4
|
+
expect(UberLogin::TokenEncoder.generate.size).to eq 2
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '#encode' do
|
9
|
+
it 'retuns a string' do
|
10
|
+
expect(UberLogin::TokenEncoder.encode('what', 'ever').class).to eq String
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns the two arguments separated by colons' do
|
14
|
+
expect(UberLogin::TokenEncoder.encode('what', 'ever')).to eq 'what:ever'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#encode_array' do
|
19
|
+
it 'retuns a string' do
|
20
|
+
expect(UberLogin::TokenEncoder.encode_array([ 'what', 'ever' ]).class).to eq String
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the two arguments separated by colons' do
|
24
|
+
expect(UberLogin::TokenEncoder.encode_array([ 'what', 'ever' ])).to eq 'what:ever'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#decode' do
|
29
|
+
it 'returns an array of size 2' do
|
30
|
+
expect(UberLogin::TokenEncoder.decode('dead:beef').size).to eq 2
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns the two elements of the token' do
|
34
|
+
expect(UberLogin::TokenEncoder.decode('what:ever')).to eq [ 'what', 'ever' ]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#sequence' do
|
39
|
+
it 'returns the first part of the token' do
|
40
|
+
expect(UberLogin::TokenEncoder.sequence('what:ever')).to eq 'what'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#token' do
|
45
|
+
it 'returns the second part of the token' do
|
46
|
+
expect(UberLogin::TokenEncoder.token('what:ever')).to eq 'ever'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#token_hash' do
|
51
|
+
it 'returns the second part of the token as a hash' do
|
52
|
+
token = UberLogin::TokenEncoder.token('what:ever')
|
53
|
+
hash = UberLogin::TokenEncoder.token_hash('what:ever')
|
54
|
+
|
55
|
+
expect(BCrypt::Password.new(hash)).to eq token
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe UberLogin::TokenValidator do
|
4
|
+
let(:token_validator) { UberLogin::TokenValidator.new('secret', FakeRequest.new) }
|
5
|
+
let(:fake_token) {
|
6
|
+
LoginToken.new(
|
7
|
+
token: BCrypt::Password.create("beef"),
|
8
|
+
ip_address: '192.168.1.1'
|
9
|
+
)
|
10
|
+
}
|
11
|
+
|
12
|
+
describe '#valid?' do
|
13
|
+
it 'always executes token_match' do
|
14
|
+
expect(token_validator).to receive(:token_match)
|
15
|
+
token_validator.valid?(fake_token)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'does not run ip_equality by default' do
|
19
|
+
expect(token_validator).to_not receive(:ip_equality)
|
20
|
+
token_validator.valid?(fake_token)
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'if IP are tied to tokens' do
|
24
|
+
before { UberLogin.configuration.tie_tokens_to_ip = true }
|
25
|
+
let(:token_validator) { UberLogin::TokenValidator.new('secret', FakeRequest.new) }
|
26
|
+
|
27
|
+
it 'executes ip_equality' do
|
28
|
+
token_validator.stub(:token_match).and_return true
|
29
|
+
expect(token_validator).to receive(:ip_equality)
|
30
|
+
token_validator.valid?(fake_token)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does not run expiration by default' do
|
35
|
+
expect(token_validator).to_not receive(:expiration)
|
36
|
+
token_validator.valid?(fake_token)
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'if tokens do expire' do
|
40
|
+
before { UberLogin.configuration.token_expiration = 86400 }
|
41
|
+
let(:token_validator) { UberLogin::TokenValidator.new('secret', FakeRequest.new) }
|
42
|
+
|
43
|
+
it 'executes expiration' do
|
44
|
+
token_validator.stub(:token_match).and_return true
|
45
|
+
expect(token_validator).to receive(:expiration)
|
46
|
+
token_validator.valid?(fake_token)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'all checks return true' do
|
51
|
+
before { Array.any_instance.stub(:all?).and_return true }
|
52
|
+
|
53
|
+
it 'returns true' do
|
54
|
+
expect(token_validator.valid?(fake_token)).to be_true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'any check fails' do
|
59
|
+
before { Array.any_instance.stub(:all?).and_return false }
|
60
|
+
|
61
|
+
it 'returns false' do
|
62
|
+
expect(token_validator.valid?(fake_token)).to be_false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/spec/uber_login_spec.rb
CHANGED
@@ -12,6 +12,34 @@ describe UberLogin do
|
|
12
12
|
controller.login(user)
|
13
13
|
expect(session[:uid]).to eq 100
|
14
14
|
end
|
15
|
+
|
16
|
+
context 'sessions have stored tokens' do
|
17
|
+
before { UberLogin.configuration.strong_sessions = true }
|
18
|
+
|
19
|
+
it 'saves a token to database' do
|
20
|
+
expect_any_instance_of(LoginToken).to receive :save!
|
21
|
+
controller.login(user)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'sets session[:ulogin]' do
|
25
|
+
controller.login(user)
|
26
|
+
expect(session[:ulogin]).to_not be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'sessions do not have stored tokens' do
|
31
|
+
before { UberLogin.configuration.strong_sessions = false }
|
32
|
+
|
33
|
+
it 'does not save a token to database' do
|
34
|
+
expect_any_instance_of(LoginToken).to_not receive :save!
|
35
|
+
controller.login(user)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'does not set session[:ulogin]' do
|
39
|
+
controller.login(user)
|
40
|
+
expect(session[:ulogin]).to be_nil
|
41
|
+
end
|
42
|
+
end
|
15
43
|
end
|
16
44
|
|
17
45
|
context 'remember is true' do
|
@@ -27,7 +55,7 @@ describe UberLogin do
|
|
27
55
|
|
28
56
|
it 'sets the ulogin cookie' do
|
29
57
|
controller.login(user, true)
|
30
|
-
expect(cookies[:ulogin]).to match(/[a-z0-
|
58
|
+
expect(cookies[:ulogin]).to match(/[a-z0-9_\-]+:[a-z0-9+\/]+/i)
|
31
59
|
end
|
32
60
|
|
33
61
|
it 'sets both cookies as persistent' do
|
@@ -37,37 +65,40 @@ describe UberLogin do
|
|
37
65
|
end
|
38
66
|
|
39
67
|
context 'only one session is allowed per user' do
|
40
|
-
before { UberLogin
|
68
|
+
before { UberLogin.configuration.allow_multiple_login = false }
|
41
69
|
|
42
70
|
it 'clears all the other tokens' do
|
43
|
-
|
71
|
+
expect(LoginToken).to receive :destroy_all
|
44
72
|
controller.login(user)
|
45
73
|
end
|
46
74
|
end
|
47
75
|
end
|
48
76
|
|
49
77
|
describe '#logout' do
|
78
|
+
before { controller.login(user, true) }
|
79
|
+
|
50
80
|
context 'sequence is nil' do
|
51
81
|
it 'deletes session[:uid]' do
|
52
|
-
controller.login(user)
|
53
82
|
controller.logout
|
54
83
|
expect(session[:uid]).to be_nil
|
55
84
|
end
|
56
85
|
|
57
|
-
|
58
|
-
|
86
|
+
it 'deletes session[:ulogin]' do
|
87
|
+
controller.logout
|
88
|
+
expect(session[:ulogin]).to be_nil
|
89
|
+
end
|
59
90
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
91
|
+
it 'deletes cookies[:uid]' do
|
92
|
+
controller.logout
|
93
|
+
expect(cookies[:uid]).to be_nil
|
94
|
+
end
|
64
95
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
96
|
+
it 'deletes cookies[:ulogin]' do
|
97
|
+
controller.logout
|
98
|
+
expect(cookies[:ulogin]).to be_nil
|
99
|
+
end
|
70
100
|
|
101
|
+
context 'persistent login was made' do
|
71
102
|
it 'deletes a LoginToken row' do
|
72
103
|
expect {
|
73
104
|
controller.logout
|
@@ -76,9 +107,37 @@ describe UberLogin do
|
|
76
107
|
end
|
77
108
|
end
|
78
109
|
|
79
|
-
context 'sequence is
|
80
|
-
|
110
|
+
context 'sequence is equal to current user sequence' do
|
111
|
+
it 'deletes session[:uid]' do
|
112
|
+
controller.logout(UberLogin::TokenEncoder.sequence(cookies[:ulogin]))
|
113
|
+
expect(session[:uid]).to be_nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'deletes session[:ulogin]' do
|
117
|
+
controller.logout(UberLogin::TokenEncoder.sequence(cookies[:ulogin]))
|
118
|
+
expect(session[:ulogin]).to be_nil
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'deletes cookies[:uid]' do
|
122
|
+
controller.logout(UberLogin::TokenEncoder.sequence(cookies[:ulogin]))
|
123
|
+
expect(cookies[:uid]).to be_nil
|
124
|
+
end
|
81
125
|
|
126
|
+
it 'deletes cookies[:ulogin]' do
|
127
|
+
controller.logout(UberLogin::TokenEncoder.sequence(cookies[:ulogin]))
|
128
|
+
expect(cookies[:ulogin]).to be_nil
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'persistent login was made' do
|
132
|
+
it 'deletes a LoginToken row' do
|
133
|
+
expect {
|
134
|
+
controller.logout(UberLogin::TokenEncoder.sequence(cookies[:ulogin]))
|
135
|
+
}.to change{ LoginToken.count }.by -1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'sequence is not nil' do
|
82
141
|
it 'does not clear session[:uid]' do
|
83
142
|
controller.logout('sequence')
|
84
143
|
expect(session[:uid]).to_not be_nil
|
@@ -103,72 +162,42 @@ describe UberLogin do
|
|
103
162
|
end
|
104
163
|
|
105
164
|
describe '#logout_all' do
|
165
|
+
before { controller.login(user, true) }
|
166
|
+
|
106
167
|
it 'deletes session[:uid]' do
|
107
|
-
controller.login(user)
|
108
168
|
controller.logout_all
|
109
169
|
expect(session[:uid]).to be_nil
|
110
170
|
end
|
111
171
|
|
112
|
-
it 'deletes session[:
|
172
|
+
it 'deletes session[:ulogin]' do
|
113
173
|
controller.logout_all
|
114
|
-
expect(session[:
|
174
|
+
expect(session[:ulogin]).to be_nil
|
115
175
|
end
|
116
176
|
|
117
|
-
it 'deletes
|
177
|
+
it 'deletes cookies[:uid]' do
|
118
178
|
controller.logout_all
|
119
179
|
expect(cookies[:uid]).to be_nil
|
120
|
-
expect(cookies[:ulogin]).to be_nil
|
121
180
|
end
|
122
181
|
|
123
|
-
it 'deletes
|
124
|
-
expect_any_instance_of(LoginToken).to receive :destroy
|
182
|
+
it 'deletes cookies[:ulogin]' do
|
125
183
|
controller.logout_all
|
184
|
+
expect(cookies[:ulogin]).to be_nil
|
126
185
|
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
before {
|
131
|
-
cookies[:uid] = "100"
|
132
|
-
cookies[:ulogin] = "dead:beef"
|
133
|
-
}
|
134
|
-
|
135
|
-
it 'saves the triplet to the database' do
|
136
|
-
expect_any_instance_of(LoginToken).to receive(:save!)
|
137
|
-
controller.send('save_to_database')
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
describe '#set_user_data' do
|
142
|
-
let(:row) { LoginToken.new }
|
143
|
-
|
144
|
-
context 'the token table has an "ip_address" field' do
|
145
|
-
it 'sets the field to the client IP' do
|
146
|
-
expect(row).to receive(:ip_address=).with('192.168.1.1')
|
147
|
-
controller.send('set_user_data', row)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context 'the token table has an "os" field' do
|
152
|
-
it 'sets the field to the client Operating System' do
|
153
|
-
expect(row).to receive(:os=).with('Linux x86_64')
|
154
|
-
controller.send('set_user_data', row)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
context 'the token table has a "browser" field' do
|
159
|
-
it 'sets the field to the client Browser and version' do
|
160
|
-
expect(row).to receive(:browser=).with('Chrome 32.0.1667.0')
|
161
|
-
controller.send('set_user_data', row)
|
162
|
-
end
|
186
|
+
it 'deletes any token associated with the user' do
|
187
|
+
expect(LoginToken).to receive :destroy_all
|
188
|
+
controller.logout_all
|
163
189
|
end
|
164
190
|
end
|
165
191
|
|
166
|
-
describe '#
|
192
|
+
describe '#current_user' do
|
167
193
|
context 'session[:uid] is set' do
|
168
|
-
before {
|
194
|
+
before {
|
195
|
+
session[:uid] = 100
|
196
|
+
session[:ulogin] = 'dead:beef'
|
197
|
+
}
|
169
198
|
|
170
199
|
it 'returns an user object with that uid' do
|
171
|
-
expect(controller.
|
200
|
+
expect(controller.current_user.id).to eq 100
|
172
201
|
end
|
173
202
|
end
|
174
203
|
|
@@ -182,38 +211,38 @@ describe UberLogin do
|
|
182
211
|
}
|
183
212
|
|
184
213
|
context 'the cookies are valid' do
|
185
|
-
before { CookieManager.any_instance.stub(:valid?).and_return true }
|
214
|
+
before { UberLogin::CookieManager.any_instance.stub(:valid?).and_return true }
|
186
215
|
|
187
216
|
it 'returns an user object with that uid' do
|
188
|
-
expect(controller.
|
217
|
+
expect(controller.current_user.id).to eq "100"
|
189
218
|
end
|
190
219
|
|
191
220
|
it 'deletes the token from the database' do
|
192
221
|
expect_any_instance_of(LoginToken).to receive(:destroy)
|
193
|
-
controller.
|
222
|
+
controller.current_user
|
194
223
|
end
|
195
224
|
|
196
225
|
it 'creates a new token for the next login' do
|
197
226
|
expect_any_instance_of(LoginToken).to receive(:save!)
|
198
|
-
controller.
|
227
|
+
controller.current_user
|
199
228
|
end
|
200
229
|
|
201
230
|
it 'refreshes the cookie' do
|
202
|
-
controller.
|
231
|
+
controller.current_user
|
203
232
|
expect(cookies[:uid]).to eq "100"
|
204
233
|
expect(cookies[:ulogin]).to_not eq "whatever:beef"
|
205
234
|
end
|
206
235
|
end
|
207
236
|
|
208
237
|
context 'the cookies are not valid' do
|
209
|
-
before { CookieManager.any_instance.stub(:valid?).and_return false }
|
238
|
+
before { UberLogin::CookieManager.any_instance.stub(:valid?).and_return false }
|
210
239
|
|
211
240
|
it 'returns nil' do
|
212
|
-
expect(controller.
|
241
|
+
expect(controller.current_user).to be_nil
|
213
242
|
end
|
214
243
|
|
215
244
|
it 'clears the cookies for this user' do
|
216
|
-
controller.
|
245
|
+
controller.current_user
|
217
246
|
expect(cookies[:uid]).to be_nil
|
218
247
|
expect(cookies[:ulogin]).to be_nil
|
219
248
|
end
|
@@ -222,7 +251,7 @@ describe UberLogin do
|
|
222
251
|
|
223
252
|
context 'cookies are not set' do
|
224
253
|
it 'returns nil' do
|
225
|
-
expect(controller.
|
254
|
+
expect(controller.current_user).to be_nil
|
226
255
|
end
|
227
256
|
end
|
228
257
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uber_login
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Francesco Boffa
|
@@ -32,11 +32,19 @@ extra_rdoc_files: []
|
|
32
32
|
files:
|
33
33
|
- lib/uber_login.rb
|
34
34
|
- lib/uber_login/cookie_manager.rb
|
35
|
+
- lib/uber_login/token_validator.rb
|
36
|
+
- lib/uber_login/token_encoder.rb
|
37
|
+
- lib/uber_login/storage.rb
|
35
38
|
- lib/uber_login/version.rb
|
39
|
+
- lib/uber_login/session_manager.rb
|
36
40
|
- lib/uber_login/configuration.rb
|
41
|
+
- spec/token_encoder_spec.rb
|
42
|
+
- spec/storage_spec.rb
|
37
43
|
- spec/spec_helper.rb
|
38
44
|
- spec/cookie_manager_spec.rb
|
39
45
|
- spec/uber_login_spec.rb
|
46
|
+
- spec/session_manager_spec.rb
|
47
|
+
- spec/token_validator_spec.rb
|
40
48
|
homepage: https://github.com/AlfaOmega08/uber_login
|
41
49
|
licenses:
|
42
50
|
- MIT
|
@@ -65,7 +73,11 @@ summary: Tired of rewriting the login, logout and current_user methods for the m
|
|
65
73
|
This gem will solve all of this problems and still leave you the control over your
|
66
74
|
application.
|
67
75
|
test_files:
|
76
|
+
- spec/token_encoder_spec.rb
|
77
|
+
- spec/storage_spec.rb
|
68
78
|
- spec/spec_helper.rb
|
69
79
|
- spec/cookie_manager_spec.rb
|
70
80
|
- spec/uber_login_spec.rb
|
81
|
+
- spec/session_manager_spec.rb
|
82
|
+
- spec/token_validator_spec.rb
|
71
83
|
has_rdoc:
|