devise_session_expirable 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +34 -6
- data/VERSION +1 -1
- data/devise_session_expirable.gemspec +106 -0
- data/lib/devise_session_expirable.rb +18 -0
- data/lib/devise_session_expirable/hook.rb +59 -0
- data/lib/devise_session_expirable/model.rb +77 -0
- data/test/integration/session_expirable_test.rb +152 -0
- data/test/models/session_expirable_test.rb +46 -0
- data/test/orm/active_record.rb +9 -0
- data/test/rails_app/Rakefile +10 -0
- data/test/rails_app/app/active_record/admin.rb +6 -0
- data/test/rails_app/app/active_record/shim.rb +2 -0
- data/test/rails_app/app/active_record/user.rb +6 -0
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +6 -0
- data/test/rails_app/app/controllers/admins_controller.rb +11 -0
- data/test/rails_app/app/controllers/application_controller.rb +9 -0
- data/test/rails_app/app/controllers/home_controller.rb +4 -0
- data/test/rails_app/app/controllers/users_controller.rb +23 -0
- data/test/rails_app/app/helpers/application_helper.rb +3 -0
- data/test/rails_app/app/views/admins/index.html.erb +1 -0
- data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
- data/test/rails_app/app/views/home/index.html.erb +1 -0
- data/test/rails_app/app/views/layouts/application.html.erb +24 -0
- data/test/rails_app/app/views/users/index.html.erb +1 -0
- data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
- data/test/rails_app/config.ru +4 -0
- data/test/rails_app/config/application.rb +41 -0
- data/test/rails_app/config/boot.rb +8 -0
- data/test/rails_app/config/database.yml +18 -0
- data/test/rails_app/config/environment.rb +5 -0
- data/test/rails_app/config/environments/development.rb +18 -0
- data/test/rails_app/config/environments/production.rb +33 -0
- data/test/rails_app/config/environments/test.rb +33 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/devise.rb +171 -0
- data/test/rails_app/config/initializers/inflections.rb +2 -0
- data/test/rails_app/config/initializers/secret_token.rb +2 -0
- data/test/rails_app/config/routes.rb +26 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +47 -0
- data/test/rails_app/lib/shared_admin.rb +25 -0
- data/test/rails_app/lib/shared_user.rb +22 -0
- data/test/rails_app/public/404.html +26 -0
- data/test/rails_app/public/422.html +26 -0
- data/test/rails_app/public/500.html +26 -0
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/rails_app/script/rails +10 -0
- data/test/support/assertions.rb +18 -0
- data/test/support/helpers.rb +68 -0
- data/test/support/integration.rb +89 -0
- data/test/support/webrat/integrations/rails.rb +28 -0
- data/test/test_helper.rb +33 -0
- metadata +52 -3
data/README.rdoc
CHANGED
@@ -25,13 +25,41 @@ does not support invalidation of authentication tokens from the
|
|
25
25
|
devise +token_authenticatable+ module when a request with a valid
|
26
26
|
authentication token is accompanied by an expired session.
|
27
27
|
|
28
|
-
==
|
28
|
+
== Configuration
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
Add +devise_session_expirable+ to your Gemfile:
|
31
|
+
|
32
|
+
gem 'devise_session_expirable'
|
33
|
+
|
34
|
+
Include +:session_expirable+ in your devise user model declaration:
|
35
|
+
|
36
|
+
class User < ActiveRecord::Base
|
37
|
+
devise :database_authenticatable, :session_expirable # ...
|
38
|
+
end
|
39
|
+
|
40
|
+
Then update the Devise initializer:
|
41
|
+
|
42
|
+
Devise.setup do |config|
|
43
|
+
# ...
|
44
|
+
config.timeout_in = 15.minutes
|
45
|
+
config.default_last_request_at = Time.parse('2013-02-16T00:00:00Z')
|
46
|
+
# ...
|
47
|
+
end
|
48
|
+
|
49
|
+
== Migrating from non-expiring sessions
|
50
|
+
|
51
|
+
The +default_last_request_at+ option is intended to enable a less
|
52
|
+
disruptive migration if sessions without timestamps have already been
|
53
|
+
issued. The configured value will be used in place of the timestamp
|
54
|
+
for sessions which don't have one.
|
55
|
+
|
56
|
+
If +default_last_request_at+ is configured, it should be set to a fixed
|
57
|
+
date/time, ideally matching the time of deployment. If set to a dynamic
|
58
|
+
time (e.g. Time.now), the lifetime of sessions without timestamps will
|
59
|
+
be extended every time Rails is initialized.
|
60
|
+
|
61
|
+
After the +timeout_in+ interval passes, any legacy sessions will have
|
62
|
+
expired and +default_last_request_at+ can be unset.
|
35
63
|
|
36
64
|
== Alternatives
|
37
65
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "devise_session_expirable"
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Riley Lynch"]
|
12
|
+
s.date = "2013-02-16"
|
13
|
+
s.description = "devise_session_expirable is an enhanced version of devise's timeoutable module that ensures that no session is allowed to last forever."
|
14
|
+
s.email = "oss+expirable@teleological.net"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"devise_session_expirable.gemspec",
|
27
|
+
"lib/devise_session_expirable.rb",
|
28
|
+
"lib/devise_session_expirable/hook.rb",
|
29
|
+
"lib/devise_session_expirable/model.rb",
|
30
|
+
"test/integration/session_expirable_test.rb",
|
31
|
+
"test/models/session_expirable_test.rb",
|
32
|
+
"test/orm/active_record.rb",
|
33
|
+
"test/rails_app/Rakefile",
|
34
|
+
"test/rails_app/app/active_record/admin.rb",
|
35
|
+
"test/rails_app/app/active_record/shim.rb",
|
36
|
+
"test/rails_app/app/active_record/user.rb",
|
37
|
+
"test/rails_app/app/controllers/admins/sessions_controller.rb",
|
38
|
+
"test/rails_app/app/controllers/admins_controller.rb",
|
39
|
+
"test/rails_app/app/controllers/application_controller.rb",
|
40
|
+
"test/rails_app/app/controllers/home_controller.rb",
|
41
|
+
"test/rails_app/app/controllers/users_controller.rb",
|
42
|
+
"test/rails_app/app/helpers/application_helper.rb",
|
43
|
+
"test/rails_app/app/views/admins/index.html.erb",
|
44
|
+
"test/rails_app/app/views/admins/sessions/new.html.erb",
|
45
|
+
"test/rails_app/app/views/home/index.html.erb",
|
46
|
+
"test/rails_app/app/views/layouts/application.html.erb",
|
47
|
+
"test/rails_app/app/views/users/index.html.erb",
|
48
|
+
"test/rails_app/app/views/users/sessions/new.html.erb",
|
49
|
+
"test/rails_app/config.ru",
|
50
|
+
"test/rails_app/config/application.rb",
|
51
|
+
"test/rails_app/config/boot.rb",
|
52
|
+
"test/rails_app/config/database.yml",
|
53
|
+
"test/rails_app/config/environment.rb",
|
54
|
+
"test/rails_app/config/environments/development.rb",
|
55
|
+
"test/rails_app/config/environments/production.rb",
|
56
|
+
"test/rails_app/config/environments/test.rb",
|
57
|
+
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
58
|
+
"test/rails_app/config/initializers/devise.rb",
|
59
|
+
"test/rails_app/config/initializers/inflections.rb",
|
60
|
+
"test/rails_app/config/initializers/secret_token.rb",
|
61
|
+
"test/rails_app/config/routes.rb",
|
62
|
+
"test/rails_app/db/migrate/20100401102949_create_tables.rb",
|
63
|
+
"test/rails_app/lib/shared_admin.rb",
|
64
|
+
"test/rails_app/lib/shared_user.rb",
|
65
|
+
"test/rails_app/public/404.html",
|
66
|
+
"test/rails_app/public/422.html",
|
67
|
+
"test/rails_app/public/500.html",
|
68
|
+
"test/rails_app/public/favicon.ico",
|
69
|
+
"test/rails_app/script/rails",
|
70
|
+
"test/support/assertions.rb",
|
71
|
+
"test/support/helpers.rb",
|
72
|
+
"test/support/integration.rb",
|
73
|
+
"test/support/webrat/integrations/rails.rb",
|
74
|
+
"test/test_helper.rb"
|
75
|
+
]
|
76
|
+
s.homepage = "http://github.com/teleological/devise_session_expirable"
|
77
|
+
s.licenses = ["MIT"]
|
78
|
+
s.require_paths = ["lib"]
|
79
|
+
s.rubygems_version = "1.8.23"
|
80
|
+
s.summary = "Strict timeouts for devise-authenticated sessions"
|
81
|
+
|
82
|
+
if s.respond_to? :specification_version then
|
83
|
+
s.specification_version = 3
|
84
|
+
|
85
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
86
|
+
s.add_runtime_dependency(%q<activesupport>, ["~> 3.2.12"])
|
87
|
+
s.add_runtime_dependency(%q<devise>, [">= 2.2.3"])
|
88
|
+
s.add_development_dependency(%q<bundler>, [">= 1.2.4"])
|
89
|
+
s.add_development_dependency(%q<jeweler>, [">= 1.8.4"])
|
90
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
91
|
+
else
|
92
|
+
s.add_dependency(%q<activesupport>, ["~> 3.2.12"])
|
93
|
+
s.add_dependency(%q<devise>, [">= 2.2.3"])
|
94
|
+
s.add_dependency(%q<bundler>, [">= 1.2.4"])
|
95
|
+
s.add_dependency(%q<jeweler>, [">= 1.8.4"])
|
96
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
97
|
+
end
|
98
|
+
else
|
99
|
+
s.add_dependency(%q<activesupport>, ["~> 3.2.12"])
|
100
|
+
s.add_dependency(%q<devise>, [">= 2.2.3"])
|
101
|
+
s.add_dependency(%q<bundler>, [">= 1.2.4"])
|
102
|
+
s.add_dependency(%q<jeweler>, [">= 1.8.4"])
|
103
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'devise'
|
5
|
+
|
6
|
+
module Devise #:nodoc:
|
7
|
+
|
8
|
+
mattr_accessor :default_last_request_at
|
9
|
+
@default_last_request_at = nil
|
10
|
+
|
11
|
+
add_module :session_expirable,
|
12
|
+
:model => 'devise_session_expirable/model'
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module DeviseSessionExpirable #:nodoc:
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
# Each time the user record is fetched from a session, the record is
|
3
|
+
# consulted (via +#session_expired?+) to determine if the
|
4
|
+
# +last_request_at+ time in the session is valid, or if the session
|
5
|
+
# should be considered as having timed out. This validation is not
|
6
|
+
# performed if +devise.skip_timeout+ is set in the rack environment.
|
7
|
+
#
|
8
|
+
# If the session is deemed to have timed out, the record is logged out
|
9
|
+
# of the session and a +:timeout+ message is thrown, invoking the
|
10
|
+
# +FailureApp+.
|
11
|
+
#
|
12
|
+
# Unlike the Devise +timeoutable+ module, devise_session_expirable does
|
13
|
+
# not support invalidation of authentication tokens from the devise
|
14
|
+
# +token_authenticatable+ module when a request with a valid
|
15
|
+
# authentication token is accompanied by an expired session.
|
16
|
+
|
17
|
+
Warden::Manager.after_fetch do |record, warden, options|
|
18
|
+
scope = options[:scope]
|
19
|
+
env = warden.request.env
|
20
|
+
|
21
|
+
puts "after fetch"
|
22
|
+
|
23
|
+
if record &&
|
24
|
+
record.respond_to?(:session_expired?) &&
|
25
|
+
warden.authenticated?(scope) &&
|
26
|
+
options[:store] != false &&
|
27
|
+
!env['devise.skip_timeout']
|
28
|
+
|
29
|
+
last_request_at = warden.session(scope)['last_request_at']
|
30
|
+
if record.session_expired?(last_request_at)
|
31
|
+
puts "expired!"
|
32
|
+
warden.logout(scope)
|
33
|
+
throw :warden, :scope => scope, :message => :timeout
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Each time the user record is set, the +last_request_at+ time
|
39
|
+
# is updated in the scoped session. This update is not performed if
|
40
|
+
# devise.skip_trackable is set in the rack environment.
|
41
|
+
|
42
|
+
Warden::Manager.after_set_user do |record, warden, options|
|
43
|
+
scope = options[:scope]
|
44
|
+
env = warden.request.env
|
45
|
+
|
46
|
+
puts "after set_user"
|
47
|
+
|
48
|
+
if record &&
|
49
|
+
record.respond_to?(:session_expired?) &&
|
50
|
+
warden.authenticated?(scope) &&
|
51
|
+
options[:store] != false &&
|
52
|
+
!env['devise.skip_trackable']
|
53
|
+
|
54
|
+
puts "reset"
|
55
|
+
|
56
|
+
warden.session(scope)['last_request_at'] = Time.now.utc
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'devise_session_expirable/hook'
|
3
|
+
|
4
|
+
module Devise #:nodoc:
|
5
|
+
module Models #:nodoc:
|
6
|
+
|
7
|
+
# SessionExpirable verifies whether a user session has expired
|
8
|
+
# via the +#session_expired?+ method.
|
9
|
+
#
|
10
|
+
# == Options
|
11
|
+
#
|
12
|
+
# SessionExpirable adds the following options to devise_for:
|
13
|
+
#
|
14
|
+
# * +timeout_in+: lifetime in seconds of an inactive user session
|
15
|
+
# * +default_last_request_at+: age to assume for sessions with nil +last_request_at+
|
16
|
+
#
|
17
|
+
# == Examples
|
18
|
+
#
|
19
|
+
# user.session_expired?(30.minutes.ago)
|
20
|
+
#
|
21
|
+
|
22
|
+
module SessionExpirable
|
23
|
+
|
24
|
+
extend ActiveSupport::Concern
|
25
|
+
|
26
|
+
# Accepts the time a session was last used and compares it
|
27
|
+
# to the oldest valid +last_request_at+ date for a session.
|
28
|
+
# If nil or any other falsy value is passed and the
|
29
|
+
# +default_last_request_at+ option is configured, the configured
|
30
|
+
# value will be used for the comparison.
|
31
|
+
#
|
32
|
+
# Supports the Devise +rememberable+ module by deferring to
|
33
|
+
# +#remember_expired?+ if the +remember_created_at+ attribute
|
34
|
+
# is set.
|
35
|
+
|
36
|
+
def session_expired?(last_access)
|
37
|
+
puts "last_access #{last_access}"
|
38
|
+
puts "timeout_in #{timeout_in}"
|
39
|
+
puts "deadline #{timeout_in.ago}"
|
40
|
+
puts !timeout_in.nil? && (!last_access || last_access <= timeout_in.ago)
|
41
|
+
|
42
|
+
last_access ||= default_last_request_at
|
43
|
+
return false if remember_exists_and_not_expired?
|
44
|
+
!timeout_in.nil? && (!last_access || last_access <= timeout_in.ago)
|
45
|
+
end
|
46
|
+
|
47
|
+
def timeout_in
|
48
|
+
self.class.timeout_in
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_last_request_at
|
52
|
+
self.class.default_last_request_at
|
53
|
+
end
|
54
|
+
|
55
|
+
#:nodoc:
|
56
|
+
def self.required_fields(klass); []; end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def remember_exists_and_not_expired?
|
61
|
+
return false unless respond_to?(:remember_expired?)
|
62
|
+
remember_created_at && !remember_expired?
|
63
|
+
end
|
64
|
+
|
65
|
+
module ClassMethods #:nodoc:
|
66
|
+
|
67
|
+
Devise::Models.config self,
|
68
|
+
:timeout_in,
|
69
|
+
:default_last_request_at
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SessionExpirableIntegrationTest < ActionDispatch::IntegrationTest
|
4
|
+
|
5
|
+
def last_request_at
|
6
|
+
@controller.user_session['last_request_at']
|
7
|
+
end
|
8
|
+
|
9
|
+
test 'set last request at in user session after each request' do
|
10
|
+
sign_in_as_user
|
11
|
+
old_last_request = last_request_at
|
12
|
+
assert_not_nil last_request_at
|
13
|
+
|
14
|
+
get users_path
|
15
|
+
assert_not_nil last_request_at
|
16
|
+
assert_not_equal old_last_request, last_request_at
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'set last request at in user session after each request is skipped if tracking is disabled' do
|
20
|
+
sign_in_as_user
|
21
|
+
old_last_request = last_request_at
|
22
|
+
assert_not_nil last_request_at
|
23
|
+
|
24
|
+
get users_path, {}, 'devise.skip_trackable' => true
|
25
|
+
assert_equal old_last_request, last_request_at
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'does not time out user session before default limit time' do
|
29
|
+
sign_in_as_user
|
30
|
+
assert_response :success
|
31
|
+
assert warden.authenticated?(:user)
|
32
|
+
|
33
|
+
get users_path
|
34
|
+
assert_response :success
|
35
|
+
assert warden.authenticated?(:user)
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'session without last_request_at is not honored' do
|
39
|
+
user = sign_in_as_user
|
40
|
+
assert_response :success
|
41
|
+
assert warden.authenticated?(:user)
|
42
|
+
|
43
|
+
get clear_timeout_user_path(user)
|
44
|
+
|
45
|
+
get users_path
|
46
|
+
assert_redirected_to users_path
|
47
|
+
assert_not warden.authenticated?(:user)
|
48
|
+
end
|
49
|
+
|
50
|
+
test 'time out user session after default limit time' do
|
51
|
+
user = sign_in_as_user
|
52
|
+
get expire_user_path(user)
|
53
|
+
assert_not_nil last_request_at
|
54
|
+
|
55
|
+
get users_path
|
56
|
+
assert_redirected_to users_path
|
57
|
+
assert_not warden.authenticated?(:user)
|
58
|
+
end
|
59
|
+
|
60
|
+
test 'time out is not triggered on sign out' do
|
61
|
+
user = sign_in_as_user
|
62
|
+
get expire_user_path(user)
|
63
|
+
|
64
|
+
get destroy_user_session_path
|
65
|
+
|
66
|
+
assert_response :redirect
|
67
|
+
assert_redirected_to root_path
|
68
|
+
follow_redirect!
|
69
|
+
assert_contain 'Signed out successfully'
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'time out is not triggered on sign in' do
|
73
|
+
user = sign_in_as_user
|
74
|
+
get expire_user_path(user)
|
75
|
+
|
76
|
+
post "/users/sign_in", :email => user.email, :password => "123456"
|
77
|
+
|
78
|
+
assert_response :redirect
|
79
|
+
follow_redirect!
|
80
|
+
assert_contain 'You are signed in'
|
81
|
+
end
|
82
|
+
|
83
|
+
test 'admin does not explode on time out' do
|
84
|
+
admin = sign_in_as_admin
|
85
|
+
get expire_admin_path(admin)
|
86
|
+
|
87
|
+
Admin.send :define_method, :reset_authentication_token! do
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
get admins_path
|
93
|
+
assert_redirected_to admins_path
|
94
|
+
assert_not warden.authenticated?(:admin)
|
95
|
+
ensure
|
96
|
+
Admin.send(:remove_method, :reset_authentication_token!)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
test 'user configured timeout limit' do
|
101
|
+
swap Devise, :timeout_in => 8.minutes do
|
102
|
+
user = sign_in_as_user
|
103
|
+
|
104
|
+
get users_path
|
105
|
+
assert_not_nil last_request_at
|
106
|
+
assert_response :success
|
107
|
+
assert warden.authenticated?(:user)
|
108
|
+
|
109
|
+
get expire_user_path(user)
|
110
|
+
get users_path
|
111
|
+
assert_redirected_to users_path
|
112
|
+
assert_not warden.authenticated?(:user)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
test 'error message with i18n' do
|
117
|
+
store_translations :en, :devise => {
|
118
|
+
:failure => { :user => { :timeout => 'Session expired!' } }
|
119
|
+
} do
|
120
|
+
user = sign_in_as_user
|
121
|
+
|
122
|
+
get expire_user_path(user)
|
123
|
+
get root_path
|
124
|
+
follow_redirect!
|
125
|
+
assert_contain 'Session expired!'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'error message with i18n with double redirect' do
|
130
|
+
store_translations :en, :devise => {
|
131
|
+
:failure => { :user => { :timeout => 'Session expired!' } }
|
132
|
+
} do
|
133
|
+
user = sign_in_as_user
|
134
|
+
|
135
|
+
get expire_user_path(user)
|
136
|
+
get users_path
|
137
|
+
follow_redirect!
|
138
|
+
follow_redirect!
|
139
|
+
assert_contain 'Session expired!'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
test 'time out not triggered if remembered' do
|
144
|
+
user = sign_in_as_user :remember_me => true
|
145
|
+
get expire_user_path(user)
|
146
|
+
assert_not_nil last_request_at
|
147
|
+
|
148
|
+
get users_path
|
149
|
+
assert_response :success
|
150
|
+
assert warden.authenticated?(:user)
|
151
|
+
end
|
152
|
+
end
|