devise-security 0.14.1 → 0.14.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/gemfiles/rails_6.0_beta.gemfile +1 -1
- data/lib/devise-security/hooks/session_limitable.rb +12 -7
- data/lib/devise-security/models/compatibility.rb +2 -2
- data/lib/devise-security/models/compatibility/{active_record.rb → active_record_patch.rb} +12 -1
- data/lib/devise-security/models/compatibility/{mongoid.rb → mongoid_patch.rb} +11 -1
- data/lib/devise-security/models/session_limitable.rb +9 -3
- data/lib/devise-security/version.rb +1 -1
- data/test/{test_captcha_controller.rb → controllers/test_captcha_controller.rb} +0 -0
- data/test/{test_password_expired_controller.rb → controllers/test_password_expired_controller.rb} +0 -0
- data/test/{test_security_question_controller.rb → controllers/test_security_question_controller.rb} +0 -0
- data/test/dummy/app/controllers/widgets_controller.rb +6 -0
- data/test/dummy/app/models/user.rb +8 -0
- data/test/dummy/config/routes.rb +1 -0
- data/test/dummy/db/migrate/20120508165529_create_tables.rb +10 -1
- data/test/integration/test_session_limitable_workflow.rb +67 -0
- data/test/support/integration_helpers.rb +47 -0
- data/test/test_compatibility.rb +13 -0
- data/test/test_helper.rb +11 -2
- data/test/test_session_limitable.rb +31 -0
- metadata +20 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5aa65f547b5acbc4207678cda6b4af888f94f3c18a7ebb1ccd80888433cf350f
|
4
|
+
data.tar.gz: ce3b96b475d683ba121c3db9477915c44c52ac27c9244a54f5c613e76a0e86e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 540d6e0534dd9c37d28e7281ada99959d73f6afb0de030f406305e689c237afda6ea94fc3f84f4392c4a5cea2243191aa1aaae4bf0f9e77efb41a41cff2e8497
|
7
|
+
data.tar.gz: 6064b218564eb7c9b3d8b849185d4fe3bbd49c466e47716a6ee666dcbc5f02f27d7015dde4f32238c95f6189b32516afcf3101c2dea0cb0bd78e9f9bd2d70cfd
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# After each sign in, update unique_session_id.
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# not trigger it.
|
3
|
+
# After each sign in, update unique_session_id. This is only triggered when the
|
4
|
+
# user is explicitly set (with set_user) and on authentication. Retrieving the
|
5
|
+
# user from session (:fetch) does not trigger it.
|
7
6
|
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
8
7
|
if record.respond_to?(:update_unique_session_id!) && warden.authenticated?(options[:scope])
|
9
8
|
unique_session_id = Devise.friendly_token
|
@@ -12,15 +11,21 @@ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
# Each time a record is fetched from session we check if a new session from
|
16
|
-
# browser was opened for the record or not, based on a unique session
|
17
|
-
# If so, the old account is logged out and redirected to the sign in
|
14
|
+
# Each time a record is fetched from session we check if a new session from
|
15
|
+
# another browser was opened for the record or not, based on a unique session
|
16
|
+
# identifier. If so, the old account is logged out and redirected to the sign in
|
17
|
+
# page on the next request.
|
18
18
|
Warden::Manager.after_set_user only: :fetch do |record, warden, options|
|
19
19
|
scope = options[:scope]
|
20
20
|
env = warden.request.env
|
21
21
|
|
22
22
|
if record.respond_to?(:unique_session_id) && warden.authenticated?(scope) && options[:store] != false
|
23
23
|
if record.unique_session_id != warden.session(scope)['unique_session_id'] && !env['devise.skip_session_limitable']
|
24
|
+
Rails.logger.warn {
|
25
|
+
"[devise-security][session_limitable] session id mismatch: "\
|
26
|
+
"expected=#{record.unique_session_id.inspect} "\
|
27
|
+
"actual=#{warden.session(scope)['unique_session_id'].inspect}"
|
28
|
+
}
|
24
29
|
warden.raw_session.clear
|
25
30
|
warden.logout(scope)
|
26
31
|
throw :warden, scope: scope, message: :session_limited
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "compatibility/#{DEVISE_ORM}"
|
3
|
+
require_relative "compatibility/#{DEVISE_ORM}_patch"
|
4
4
|
|
5
5
|
module Devise
|
6
6
|
module Models
|
@@ -9,7 +9,7 @@ module Devise
|
|
9
9
|
# and/or older versions of ORMs.
|
10
10
|
module Compatibility
|
11
11
|
extend ActiveSupport::Concern
|
12
|
-
include "Devise::Models::Compatibility::#{DEVISE_ORM.to_s.classify}".constantize
|
12
|
+
include "Devise::Models::Compatibility::#{DEVISE_ORM.to_s.classify}Patch".constantize
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Devise
|
2
2
|
module Models
|
3
3
|
module Compatibility
|
4
|
-
|
4
|
+
|
5
|
+
class NotPersistedError < ActiveRecord::ActiveRecordError; end
|
6
|
+
|
7
|
+
module ActiveRecordPatch
|
5
8
|
extend ActiveSupport::Concern
|
6
9
|
unless Devise.activerecord51?
|
7
10
|
# When the record was saved, was the +encrypted_password+ changed?
|
@@ -23,6 +26,14 @@ module Devise
|
|
23
26
|
changed_attributes['encrypted_password'].present?
|
24
27
|
end
|
25
28
|
end
|
29
|
+
|
30
|
+
# Updates the record with the value and does not trigger validations or callbacks
|
31
|
+
# @param name [Symbol] attribute to update
|
32
|
+
# @param value [String] value to set
|
33
|
+
def update_attribute_without_validatons_or_callbacks(name, value)
|
34
|
+
update_column(name, value)
|
35
|
+
end
|
36
|
+
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Devise
|
2
2
|
module Models
|
3
3
|
module Compatibility
|
4
|
-
|
4
|
+
|
5
|
+
class NotPersistedError < Mongoid::Errors::MongoidError; end
|
6
|
+
|
7
|
+
module MongoidPatch
|
5
8
|
extend ActiveSupport::Concern
|
6
9
|
|
7
10
|
# Will saving this record change the +email+ attribute?
|
@@ -15,6 +18,13 @@ module Devise
|
|
15
18
|
def will_save_change_to_encrypted_password?
|
16
19
|
changed.include? 'encrypted_password'
|
17
20
|
end
|
21
|
+
|
22
|
+
# Updates the document with the value and does not trigger validations or callbacks
|
23
|
+
# @param name [Symbol] attribute to update
|
24
|
+
# @param value [String] value to set
|
25
|
+
def update_attribute_without_validatons_or_callbacks(name, value)
|
26
|
+
set(Hash[*[name, value]])
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|
20
30
|
end
|
@@ -12,10 +12,16 @@ module Devise
|
|
12
12
|
module SessionLimitable
|
13
13
|
extend ActiveSupport::Concern
|
14
14
|
|
15
|
+
# Update the unique_session_id on the model. This will be checked in
|
16
|
+
# the Warden after_set_user hook in {file:devise-security/hooks/session_limitable}
|
17
|
+
# @param unique_session_id [String]
|
18
|
+
# @return [void]
|
19
|
+
# @raise [Devise::Models::Compatibility::NotPersistedError] if record is unsaved
|
15
20
|
def update_unique_session_id!(unique_session_id)
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
raise Devise::Models::Compatibility::NotPersistedError, 'cannot update a new record' unless persisted?
|
22
|
+
update_attribute_without_validatons_or_callbacks(:unique_session_id, unique_session_id).tap do
|
23
|
+
Rails.logger.debug { "[devise-security][session_limitable] unique_session_id=#{unique_session_id}"}
|
24
|
+
end
|
19
25
|
end
|
20
26
|
|
21
27
|
end
|
File without changes
|
data/test/{test_password_expired_controller.rb → controllers/test_password_expired_controller.rb}
RENAMED
File without changes
|
data/test/{test_security_question_controller.rb → controllers/test_security_question_controller.rb}
RENAMED
File without changes
|
@@ -25,5 +25,13 @@ class User < ApplicationRecord
|
|
25
25
|
if DEVISE_ORM == :mongoid
|
26
26
|
require './test/dummy/app/models/mongoid/mappings'
|
27
27
|
include ::Mongoid::Mappings
|
28
|
+
|
29
|
+
def some_method_calling_mongoid
|
30
|
+
Mongoid.logger
|
31
|
+
end
|
32
|
+
elsif DEVISE_ORM == :active_record
|
33
|
+
def some_method_calling_active_record
|
34
|
+
ActiveRecord::Base.transaction {}
|
35
|
+
end
|
28
36
|
end
|
29
37
|
end
|
data/test/dummy/config/routes.rb
CHANGED
@@ -5,13 +5,22 @@ class CreateTables < MIGRATION_CLASS
|
|
5
5
|
create_table :users do |t|
|
6
6
|
t.string :username
|
7
7
|
t.string :facebook_token
|
8
|
-
|
8
|
+
|
9
|
+
# session_limitable
|
10
|
+
t.string :unique_session_id
|
9
11
|
|
10
12
|
## Database authenticatable
|
11
13
|
t.string :email, null: false, default: ''
|
12
14
|
t.string :encrypted_password, null: false, default: ''
|
13
15
|
|
14
16
|
t.datetime :password_changed_at
|
17
|
+
|
18
|
+
t.datetime :current_sign_in_at
|
19
|
+
t.datetime :last_sign_in_at
|
20
|
+
t.string :current_sign_in_ip
|
21
|
+
t.string :last_sign_in_ip
|
22
|
+
t.integer :sign_in_count, default: 0
|
23
|
+
t.integer :failed_attempts, default: 0
|
15
24
|
t.timestamps null: false
|
16
25
|
end
|
17
26
|
add_index :users, :password_changed_at
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestSessionLimitableWorkflow < ActionDispatch::IntegrationTest
|
4
|
+
include IntegrationHelpers
|
5
|
+
|
6
|
+
setup do
|
7
|
+
@user = User.create!(password: 'passWord1',
|
8
|
+
password_confirmation: 'passWord1',
|
9
|
+
email: 'bob@microsoft.com')
|
10
|
+
@user.confirm
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'failed login' do
|
14
|
+
assert_nil @user.unique_session_id
|
15
|
+
|
16
|
+
open_session do |session|
|
17
|
+
failed_sign_in(@user, session)
|
18
|
+
session.assert_response(:success)
|
19
|
+
assert_equal session.flash[:alert], I18n.t('devise.failure.invalid', authentication_keys: 'Email')
|
20
|
+
assert_nil @user.reload.unique_session_id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
test 'successful login' do
|
25
|
+
assert_nil @user.unique_session_id
|
26
|
+
|
27
|
+
open_session do |session|
|
28
|
+
sign_in(@user, session)
|
29
|
+
session.assert_redirected_to '/'
|
30
|
+
session.get widgets_path
|
31
|
+
session.assert_response(:success)
|
32
|
+
assert_equal session.response.body, 'success'
|
33
|
+
assert_not_nil @user.reload.unique_session_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'session is logged out when another session is created' do
|
38
|
+
first_session = open_session
|
39
|
+
second_session = open_session
|
40
|
+
unique_session_id = nil
|
41
|
+
|
42
|
+
first_session.tap do |session|
|
43
|
+
sign_in(@user, session)
|
44
|
+
session.assert_redirected_to '/'
|
45
|
+
session.get widgets_path
|
46
|
+
session.assert_response(:success)
|
47
|
+
assert_equal session.response.body, 'success'
|
48
|
+
unique_session_id = @user.reload.unique_session_id
|
49
|
+
assert_not_nil unique_session_id
|
50
|
+
end
|
51
|
+
|
52
|
+
second_session.tap do |session|
|
53
|
+
sign_in(@user, session)
|
54
|
+
session.assert_redirected_to '/'
|
55
|
+
session.get widgets_path
|
56
|
+
session.assert_response(:success)
|
57
|
+
assert_equal session.response.body, 'success'
|
58
|
+
assert_not_equal unique_session_id, @user.reload.unique_session_id
|
59
|
+
end
|
60
|
+
|
61
|
+
first_session.tap do |session|
|
62
|
+
session.get widgets_path
|
63
|
+
session.assert_redirected_to new_user_session_path
|
64
|
+
assert_equal session.flash[:alert], I18n.t('devise.failure.session_limited')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module IntegrationHelpers
|
2
|
+
# login the user. This will exercise all the Warden Hooks
|
3
|
+
# @param user [User]
|
4
|
+
# @param session [ActionDispatch::Integration::Session]
|
5
|
+
# @return [void]
|
6
|
+
# @note accounts for differences in the integration test API between rails versions
|
7
|
+
def sign_in(user, session)
|
8
|
+
if Rails.gem_version > Gem::Version.new('5.0')
|
9
|
+
session.post new_user_session_path, params: {
|
10
|
+
user: {
|
11
|
+
email: user.email,
|
12
|
+
password: user.password
|
13
|
+
}
|
14
|
+
}
|
15
|
+
else
|
16
|
+
session.post new_user_session_path, {
|
17
|
+
user: {
|
18
|
+
email: user.email,
|
19
|
+
password: user.password
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# attempt to login the user with a bad password. This will exercise all the Warden Hooks
|
26
|
+
# @param user [User]
|
27
|
+
# @param session [ActionDispatch::Integration::Session]
|
28
|
+
# @return [void]
|
29
|
+
# @note accounts for differences in the integration test API between rails versions
|
30
|
+
def failed_sign_in(user, session)
|
31
|
+
if Rails.gem_version > Gem::Version.new('5.0')
|
32
|
+
session.post new_user_session_path, params: {
|
33
|
+
user: {
|
34
|
+
email: user.email,
|
35
|
+
password: 'bad-password'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
else
|
39
|
+
session.post new_user_session_path, {
|
40
|
+
user: {
|
41
|
+
email: user.email,
|
42
|
+
password: 'bad-password'
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestCompatibility < ActiveSupport::TestCase
|
4
|
+
test 'can access ActiveRecord namespace' do
|
5
|
+
skip unless DEVISE_ORM == :active_record
|
6
|
+
assert_nothing_raised { User.new.some_method_calling_active_record }
|
7
|
+
end
|
8
|
+
|
9
|
+
test 'can access Mongoid namespace' do
|
10
|
+
skip unless DEVISE_ORM == :mongoid
|
11
|
+
assert_nothing_raised { User.new.some_method_calling_mongoid }
|
12
|
+
end
|
13
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -5,9 +5,17 @@ ENV['RAILS_ENV'] ||= 'test'
|
|
5
5
|
require 'simplecov'
|
6
6
|
SimpleCov.start do
|
7
7
|
add_filter 'gemfiles'
|
8
|
+
add_filter 'test/dummy/db'
|
9
|
+
add_group 'ActiveRecord', 'active_record'
|
10
|
+
add_group 'Expirable', /(?<!password_)expirable/
|
11
|
+
add_group 'Mongoid', 'mongoid'
|
12
|
+
add_group 'Paranoid Verifiable', 'paranoid_verification'
|
13
|
+
add_group 'Password Archivable', /password_archivable|old_password/
|
14
|
+
add_group 'Password Expirable', /password_expirable|password_expired/
|
15
|
+
add_group 'Secure Validateable', 'secure_validatable'
|
16
|
+
add_group 'Security Questionable', 'security_question'
|
17
|
+
add_group 'Session Limitable', 'session_limitable'
|
8
18
|
add_group 'Tests', 'test'
|
9
|
-
add_group 'Password Archivable', 'password_archivable'
|
10
|
-
add_group 'Password Expirable', 'password_expirable'
|
11
19
|
end
|
12
20
|
|
13
21
|
if ENV['CI']
|
@@ -23,6 +31,7 @@ require 'rails/test_help'
|
|
23
31
|
require 'devise-security'
|
24
32
|
require 'database_cleaner'
|
25
33
|
require "orm/#{DEVISE_ORM}"
|
34
|
+
require 'support/integration_helpers'
|
26
35
|
|
27
36
|
class Minitest::Test
|
28
37
|
def before_setup
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestSessionLimitable < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
test '#update_unique_session_id!(value) updates valid record' do
|
6
|
+
user = User.create! password: 'passWord1', password_confirmation: 'passWord1', email: 'bob@microsoft.com'
|
7
|
+
assert user.persisted?
|
8
|
+
assert_nil user.unique_session_id
|
9
|
+
user.update_unique_session_id!('unique_value')
|
10
|
+
user.reload
|
11
|
+
assert_equal user.unique_session_id, 'unique_value'
|
12
|
+
end
|
13
|
+
|
14
|
+
test '#update_unique_session_id!(value) updates invalid record atomically' do
|
15
|
+
user = User.create! password: 'passWord1', password_confirmation: 'passWord1', email: 'bob@microsoft.com'
|
16
|
+
assert user.persisted?
|
17
|
+
user.email = ''
|
18
|
+
assert user.invalid?
|
19
|
+
assert_nil user.unique_session_id
|
20
|
+
user.update_unique_session_id!('unique_value')
|
21
|
+
user.reload
|
22
|
+
assert_equal user.email, 'bob@microsoft.com'
|
23
|
+
assert_equal user.unique_session_id, 'unique_value'
|
24
|
+
end
|
25
|
+
|
26
|
+
test '#update_unique_session_id!(value) raises an exception on an unpersisted record' do
|
27
|
+
user = User.create
|
28
|
+
assert !user.persisted?
|
29
|
+
assert_raises(Devise::Models::Compatibility::NotPersistedError) { user.update_unique_session_id!('unique_value') }
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-security
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Scholl
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2019-
|
15
|
+
date: 2019-05-21 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rails
|
@@ -293,8 +293,8 @@ files:
|
|
293
293
|
- lib/devise-security/hooks/session_limitable.rb
|
294
294
|
- lib/devise-security/models/active_record/old_password.rb
|
295
295
|
- lib/devise-security/models/compatibility.rb
|
296
|
-
- lib/devise-security/models/compatibility/
|
297
|
-
- lib/devise-security/models/compatibility/
|
296
|
+
- lib/devise-security/models/compatibility/active_record_patch.rb
|
297
|
+
- lib/devise-security/models/compatibility/mongoid_patch.rb
|
298
298
|
- lib/devise-security/models/database_authenticatable_patch.rb
|
299
299
|
- lib/devise-security/models/expirable.rb
|
300
300
|
- lib/devise-security/models/mongoid/old_password.rb
|
@@ -324,11 +324,15 @@ files:
|
|
324
324
|
- lib/devise-security/version.rb
|
325
325
|
- lib/generators/devise_security/install_generator.rb
|
326
326
|
- lib/generators/templates/devise-security.rb
|
327
|
+
- test/controllers/test_captcha_controller.rb
|
328
|
+
- test/controllers/test_password_expired_controller.rb
|
329
|
+
- test/controllers/test_security_question_controller.rb
|
327
330
|
- test/dummy/Rakefile
|
328
331
|
- test/dummy/app/controllers/application_controller.rb
|
329
332
|
- test/dummy/app/controllers/captcha/sessions_controller.rb
|
330
333
|
- test/dummy/app/controllers/foos_controller.rb
|
331
334
|
- test/dummy/app/controllers/security_question/unlocks_controller.rb
|
335
|
+
- test/dummy/app/controllers/widgets_controller.rb
|
332
336
|
- test/dummy/app/models/.gitkeep
|
333
337
|
- test/dummy/app/models/application_record.rb
|
334
338
|
- test/dummy/app/models/application_user_record.rb
|
@@ -390,19 +394,20 @@ files:
|
|
390
394
|
- test/dummy/lib/shared_user_without_email.rb
|
391
395
|
- test/dummy/lib/shared_user_without_omniauth.rb
|
392
396
|
- test/dummy/lib/shared_verification_fields.rb
|
397
|
+
- test/integration/test_session_limitable_workflow.rb
|
393
398
|
- test/orm/active_record.rb
|
394
399
|
- test/orm/mongoid.rb
|
400
|
+
- test/support/integration_helpers.rb
|
395
401
|
- test/support/mongoid.yml
|
396
|
-
- test/
|
402
|
+
- test/test_compatibility.rb
|
397
403
|
- test/test_complexity_validator.rb
|
398
404
|
- test/test_helper.rb
|
399
405
|
- test/test_install_generator.rb
|
400
406
|
- test/test_paranoid_verification.rb
|
401
407
|
- test/test_password_archivable.rb
|
402
408
|
- test/test_password_expirable.rb
|
403
|
-
- test/test_password_expired_controller.rb
|
404
409
|
- test/test_secure_validatable.rb
|
405
|
-
- test/
|
410
|
+
- test/test_session_limitable.rb
|
406
411
|
homepage: https://github.com/devise-security/devise-security
|
407
412
|
licenses:
|
408
413
|
- MIT
|
@@ -428,11 +433,15 @@ signing_key:
|
|
428
433
|
specification_version: 4
|
429
434
|
summary: Security extension for devise
|
430
435
|
test_files:
|
436
|
+
- test/controllers/test_captcha_controller.rb
|
437
|
+
- test/controllers/test_password_expired_controller.rb
|
438
|
+
- test/controllers/test_security_question_controller.rb
|
431
439
|
- test/dummy/Rakefile
|
432
440
|
- test/dummy/app/controllers/application_controller.rb
|
433
441
|
- test/dummy/app/controllers/captcha/sessions_controller.rb
|
434
442
|
- test/dummy/app/controllers/foos_controller.rb
|
435
443
|
- test/dummy/app/controllers/security_question/unlocks_controller.rb
|
444
|
+
- test/dummy/app/controllers/widgets_controller.rb
|
436
445
|
- test/dummy/app/models/.gitkeep
|
437
446
|
- test/dummy/app/models/application_record.rb
|
438
447
|
- test/dummy/app/models/application_user_record.rb
|
@@ -494,16 +503,17 @@ test_files:
|
|
494
503
|
- test/dummy/lib/shared_user_without_email.rb
|
495
504
|
- test/dummy/lib/shared_user_without_omniauth.rb
|
496
505
|
- test/dummy/lib/shared_verification_fields.rb
|
506
|
+
- test/integration/test_session_limitable_workflow.rb
|
497
507
|
- test/orm/active_record.rb
|
498
508
|
- test/orm/mongoid.rb
|
509
|
+
- test/support/integration_helpers.rb
|
499
510
|
- test/support/mongoid.yml
|
500
|
-
- test/
|
511
|
+
- test/test_compatibility.rb
|
501
512
|
- test/test_complexity_validator.rb
|
502
513
|
- test/test_helper.rb
|
503
514
|
- test/test_install_generator.rb
|
504
515
|
- test/test_paranoid_verification.rb
|
505
516
|
- test/test_password_archivable.rb
|
506
517
|
- test/test_password_expirable.rb
|
507
|
-
- test/test_password_expired_controller.rb
|
508
518
|
- test/test_secure_validatable.rb
|
509
|
-
- test/
|
519
|
+
- test/test_session_limitable.rb
|