devise-security 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +41 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +22 -2
- data/.ruby-version +1 -1
- data/.travis.yml +15 -3
- data/Appraisals +19 -0
- data/Gemfile +1 -0
- data/README.md +15 -10
- data/Rakefile +3 -1
- data/app/controllers/devise/paranoid_verification_code_controller.rb +1 -1
- data/app/controllers/devise/password_expired_controller.rb +1 -1
- data/app/views/devise/paranoid_verification_code/show.html.erb +2 -2
- data/app/views/devise/password_expired/show.html.erb +5 -5
- data/config/locales/de.yml +7 -7
- data/config/locales/en.yml +8 -8
- data/config/locales/es.yml +8 -8
- data/devise-security.gemspec +12 -6
- data/gemfiles/rails_4.1_stable.gemfile +8 -0
- data/gemfiles/rails_4.2_stable.gemfile +8 -0
- data/gemfiles/rails_5.0_stable.gemfile +8 -0
- data/gemfiles/rails_5.1_stable.gemfile +8 -0
- data/gemfiles/rails_5.2_rc1.gemfile +8 -0
- data/lib/devise-security/controllers/helpers.rb +2 -2
- data/lib/devise-security/hooks/session_limitable.rb +3 -3
- data/lib/devise-security/models/compatibility.rb +22 -0
- data/lib/devise-security/models/expirable.rb +13 -13
- data/lib/devise-security/models/old_password.rb +1 -1
- data/lib/devise-security/models/paranoid_verification.rb +5 -2
- data/lib/devise-security/models/password_archivable.rb +34 -38
- data/lib/devise-security/models/password_expirable.rb +1 -1
- data/lib/devise-security/models/secure_validatable.rb +16 -14
- data/lib/devise-security/models/security_questionable.rb +1 -2
- data/lib/devise-security/models/session_limitable.rb +3 -3
- data/lib/devise-security/orm/active_record.rb +1 -3
- data/lib/devise-security/patches/confirmations_controller_captcha.rb +2 -2
- data/lib/devise-security/patches/confirmations_controller_security_question.rb +2 -2
- data/lib/devise-security/patches/passwords_controller_captcha.rb +2 -2
- data/lib/devise-security/patches/passwords_controller_security_question.rb +2 -2
- data/lib/devise-security/patches/registrations_controller_captcha.rb +2 -2
- data/lib/devise-security/patches/sessions_controller_captcha.rb +3 -3
- data/lib/devise-security/patches/unlocks_controller_captcha.rb +2 -2
- data/lib/devise-security/patches/unlocks_controller_security_question.rb +2 -2
- data/lib/devise-security/rails.rb +2 -2
- data/lib/devise-security/routes.rb +2 -3
- data/lib/devise-security/schema.rb +11 -6
- data/lib/devise-security/version.rb +1 -1
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/captcha_user.rb +1 -1
- data/test/dummy/app/models/security_question_user.rb +2 -3
- data/test/dummy/app/models/user.rb +21 -4
- data/test/dummy/app/models/widget.rb +4 -0
- data/test/dummy/config/environments/test.rb +10 -2
- data/test/dummy/config/initializers/devise.rb +1 -0
- data/test/dummy/config/secrets.yml +1 -2
- data/test/dummy/db/migrate/20120508165529_create_tables.rb +9 -3
- data/test/dummy/db/migrate/20180318103603_add_expireable_columns.rb +6 -0
- data/test/dummy/db/migrate/20180318105329_add_confirmable_columns.rb +8 -0
- data/test/dummy/db/migrate/20180318105732_add_rememberable_columns.rb +5 -0
- data/test/dummy/db/migrate/20180318111336_add_recoverable_columns.rb +6 -0
- data/test/dummy/db/migrate/20180319114023_add_widget.rb +8 -0
- data/test/test_captcha_controller.rb +13 -13
- data/test/test_helper.rb +7 -0
- data/test/test_paranoid_verification.rb +2 -2
- data/test/test_password_archivable.rb +27 -13
- data/test/test_password_expirable.rb +2 -2
- data/test/test_password_expired_controller.rb +25 -10
- data/test/test_security_question_controller.rb +45 -21
- metadata +90 -13
@@ -10,13 +10,13 @@ module DeviseSecurity::Patches
|
|
10
10
|
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
|
11
11
|
|
12
12
|
if successfully_sent?(resource)
|
13
|
-
respond_with({}, :
|
13
|
+
respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
|
14
14
|
else
|
15
15
|
respond_with(resource)
|
16
16
|
end
|
17
17
|
else
|
18
18
|
flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
|
19
|
-
respond_with({}, :
|
19
|
+
respond_with({}, location: new_confirmation_path(resource_name))
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -6,13 +6,13 @@ module DeviseSecurity::Patches
|
|
6
6
|
if valid_captcha_if_defined?(params[:captcha])
|
7
7
|
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
|
8
8
|
if successfully_sent?(resource)
|
9
|
-
respond_with({}, :
|
9
|
+
respond_with({}, location: new_session_path(resource_name))
|
10
10
|
else
|
11
11
|
respond_with(resource)
|
12
12
|
end
|
13
13
|
else
|
14
14
|
flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
|
15
|
-
respond_with({}, :
|
15
|
+
respond_with({}, location: new_password_path(resource_name))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -9,13 +9,13 @@ module DeviseSecurity::Patches
|
|
9
9
|
if valid_captcha_or_security_question?(resource, params)
|
10
10
|
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
|
11
11
|
if successfully_sent?(resource)
|
12
|
-
respond_with({}, :
|
12
|
+
respond_with({}, location: new_session_path(resource_name))
|
13
13
|
else
|
14
14
|
respond_with(resource)
|
15
15
|
end
|
16
16
|
else
|
17
17
|
flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
|
18
|
-
respond_with({}, :
|
18
|
+
respond_with({}, location: new_password_path(resource_name))
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -11,11 +11,11 @@ module DeviseSecurity::Patches
|
|
11
11
|
if resource.active_for_authentication?
|
12
12
|
set_flash_message :notice, :signed_up if is_flashing_format?
|
13
13
|
sign_up(resource_name, resource)
|
14
|
-
respond_with resource, :
|
14
|
+
respond_with resource, location: after_sign_up_path_for(resource)
|
15
15
|
else
|
16
16
|
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
|
17
17
|
expire_data_after_sign_in!
|
18
|
-
respond_with resource, :
|
18
|
+
respond_with resource, location: after_inactive_sign_up_path_for(resource)
|
19
19
|
end
|
20
20
|
else
|
21
21
|
clean_up_passwords resource
|
@@ -8,16 +8,16 @@ module DeviseSecurity::Patches
|
|
8
8
|
set_flash_message(:notice, :signed_in) if is_flashing_format?
|
9
9
|
sign_in(resource_name, resource)
|
10
10
|
block.call(resource) if block
|
11
|
-
respond_with resource, :
|
11
|
+
respond_with resource, location: after_sign_in_path_for(resource)
|
12
12
|
else
|
13
13
|
flash[:alert] = t('devise.invalid_captcha') if is_flashing_format?
|
14
|
-
respond_with({}, :
|
14
|
+
respond_with({}, location: new_session_path(resource_name))
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
# for bad protected use in controller
|
19
19
|
define_method :auth_options do
|
20
|
-
{ :
|
20
|
+
{ scope: resource_name, recall: "#{controller_path}#new" }
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -6,13 +6,13 @@ module DeviseSecurity::Patches
|
|
6
6
|
if valid_captcha_if_defined?(params[:captcha])
|
7
7
|
self.resource = resource_class.send_unlock_instructions(params[resource_name])
|
8
8
|
if successfully_sent?(resource)
|
9
|
-
respond_with({}, :
|
9
|
+
respond_with({}, location: new_session_path(resource_name))
|
10
10
|
else
|
11
11
|
respond_with(resource)
|
12
12
|
end
|
13
13
|
else
|
14
14
|
flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
|
15
|
-
respond_with({}, :
|
15
|
+
respond_with({}, location: new_unlock_path(resource_name))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -9,13 +9,13 @@ module DeviseSecurity::Patches
|
|
9
9
|
if valid_captcha_or_security_question?(resource, params)
|
10
10
|
self.resource = resource_class.send_unlock_instructions(params[resource_name])
|
11
11
|
if successfully_sent?(resource)
|
12
|
-
respond_with({}, :
|
12
|
+
respond_with({}, location: new_session_path(resource_name))
|
13
13
|
else
|
14
14
|
respond_with(resource)
|
15
15
|
end
|
16
16
|
else
|
17
17
|
flash[:alert] = t('devise.invalid_security_question') if is_navigational_format?
|
18
|
-
respond_with({}, :
|
18
|
+
respond_with({}, location: new_unlock_path(resource_name))
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -5,13 +5,12 @@ module ActionDispatch::Routing
|
|
5
5
|
|
6
6
|
# route for handle expired passwords
|
7
7
|
def devise_password_expired(mapping, controllers)
|
8
|
-
resource :password_expired, :
|
8
|
+
resource :password_expired, only: [:show, :update], path: mapping.path_names[:password_expired], controller: controllers[:password_expired]
|
9
9
|
end
|
10
10
|
|
11
11
|
# route for handle paranoid verification
|
12
12
|
def devise_verification_code(mapping, controllers)
|
13
|
-
resource :paranoid_verification_code, :
|
13
|
+
resource :paranoid_verification_code, only: [:show, :update], path: mapping.path_names[:verification_code], controller: controllers[:paranoid_verification_code]
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
@@ -27,13 +27,13 @@ module DeviseSecurity
|
|
27
27
|
# create_table :old_passwords do
|
28
28
|
# t.password_archivable
|
29
29
|
# end
|
30
|
-
# add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :
|
30
|
+
# add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: :index_password_archivable
|
31
31
|
#
|
32
32
|
def password_archivable
|
33
|
-
apply_devise_schema :encrypted_password, String, :
|
33
|
+
apply_devise_schema :encrypted_password, String, limit: 128, null: false
|
34
34
|
apply_devise_schema :password_salt, String
|
35
|
-
apply_devise_schema :password_archivable_id, Integer, :
|
36
|
-
apply_devise_schema :password_archivable_type, String, :
|
35
|
+
apply_devise_schema :password_archivable_id, Integer, null: false
|
36
|
+
apply_devise_schema :password_archivable_type, String, null: false
|
37
37
|
apply_devise_schema :created_at, DateTime
|
38
38
|
end
|
39
39
|
|
@@ -49,11 +49,16 @@ module DeviseSecurity
|
|
49
49
|
#
|
50
50
|
# # or if the resource's table already exists, define a migration and put this in:
|
51
51
|
# change_table :the_resources do |t|
|
52
|
-
# t.string :unique_session_id, :
|
52
|
+
# t.string :unique_session_id, limit: 20
|
53
53
|
# end
|
54
54
|
#
|
55
55
|
def session_limitable
|
56
|
-
apply_devise_schema :unique_session_id, String, :
|
56
|
+
apply_devise_schema :unique_session_id, String, limit: 20
|
57
|
+
end
|
58
|
+
|
59
|
+
def expirable
|
60
|
+
apply_devise_schema :expired_at, DateTime
|
61
|
+
apply_devise_schema :last_activity_at, DateTime
|
57
62
|
end
|
58
63
|
end
|
59
64
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
class SecurityQuestionUser < ActiveRecord::Base
|
2
|
-
self.table_name =
|
2
|
+
self.table_name = 'users'
|
3
3
|
devise :database_authenticatable, :password_archivable, :lockable,
|
4
|
-
:paranoid_verification, :password_expirable,
|
5
|
-
:security_questionable
|
4
|
+
:paranoid_verification, :password_expirable, :security_questionable
|
6
5
|
end
|
@@ -1,5 +1,22 @@
|
|
1
|
-
class User <
|
2
|
-
|
3
|
-
|
4
|
-
:
|
1
|
+
class User < ApplicationRecord
|
2
|
+
|
3
|
+
devise :database_authenticatable,
|
4
|
+
:confirmable,
|
5
|
+
:expirable,
|
6
|
+
:lockable,
|
7
|
+
:omniauthable,
|
8
|
+
:paranoid_verification,
|
9
|
+
:password_archivable,
|
10
|
+
:password_expirable,
|
11
|
+
:recoverable,
|
12
|
+
:registerable,
|
13
|
+
:rememberable,
|
14
|
+
:secure_validatable,
|
15
|
+
:security_questionable,
|
16
|
+
:session_limitable,
|
17
|
+
:timeoutable,
|
18
|
+
:trackable,
|
19
|
+
:validatable
|
20
|
+
|
21
|
+
has_many :widgets
|
5
22
|
end
|
@@ -2,7 +2,7 @@ RailsApp::Application.configure do
|
|
2
2
|
config.cache_classes = true
|
3
3
|
config.eager_load = false
|
4
4
|
|
5
|
-
if Rails.version >
|
5
|
+
if Rails.version > '5'
|
6
6
|
config.public_file_server.enabled = true
|
7
7
|
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
|
8
8
|
else
|
@@ -15,7 +15,7 @@ RailsApp::Application.configure do
|
|
15
15
|
|
16
16
|
config.action_dispatch.show_exceptions = false
|
17
17
|
|
18
|
-
config.action_controller.allow_forgery_protection
|
18
|
+
config.action_controller.allow_forgery_protection = false
|
19
19
|
|
20
20
|
config.action_mailer.delivery_method = :test
|
21
21
|
config.action_mailer.default_url_options = { host: 'test.host' }
|
@@ -24,4 +24,12 @@ RailsApp::Application.configure do
|
|
24
24
|
I18n.enforce_available_locales = false
|
25
25
|
|
26
26
|
config.active_support.test_order = :sorted
|
27
|
+
config.log_level = :debug
|
28
|
+
if Rails.gem_version >= Gem::Version.new('4.2') && Rails.gem_version < Gem::Version.new('5.0')
|
29
|
+
config.active_record.raise_in_transactional_callbacks = true
|
30
|
+
end
|
31
|
+
if Rails.gem_version.release >= Gem::Version.new('5.2')
|
32
|
+
config.active_record.sqlite3.represent_boolean_as_integer = true
|
33
|
+
end
|
27
34
|
end
|
35
|
+
ActiveSupport::Deprecation.debug = true
|
@@ -3,6 +3,7 @@ class CreateTables < MIGRATION_CLASS
|
|
3
3
|
create_table :users do |t|
|
4
4
|
t.string :username
|
5
5
|
t.string :facebook_token
|
6
|
+
t.string :unique_session_id, :limit => 20
|
6
7
|
|
7
8
|
## Database authenticatable
|
8
9
|
t.string :email, null: false, default: ''
|
@@ -11,6 +12,8 @@ class CreateTables < MIGRATION_CLASS
|
|
11
12
|
t.datetime :password_changed_at
|
12
13
|
t.timestamps null: false
|
13
14
|
end
|
15
|
+
add_index :users, :password_changed_at
|
16
|
+
add_index :users, :email
|
14
17
|
|
15
18
|
create_table :secure_users do |t|
|
16
19
|
t.string :email
|
@@ -19,10 +22,13 @@ class CreateTables < MIGRATION_CLASS
|
|
19
22
|
end
|
20
23
|
|
21
24
|
create_table :old_passwords do |t|
|
22
|
-
t.string :encrypted_password
|
23
|
-
|
24
|
-
t.
|
25
|
+
t.string :encrypted_password, :null => false
|
26
|
+
t.string :password_salt
|
27
|
+
t.string :password_archivable_type, :null => false
|
28
|
+
t.integer :password_archivable_id, :null => false
|
29
|
+
t.datetime :created_at
|
25
30
|
end
|
31
|
+
add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
|
26
32
|
end
|
27
33
|
|
28
34
|
def self.down
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class AddConfirmableColumns < MIGRATION_CLASS
|
2
|
+
def change
|
3
|
+
add_column :users, :confirmation_token, :string
|
4
|
+
add_column :users, :confirmed_at, :datetime
|
5
|
+
add_column :users, :confirmation_sent_at, :datetime
|
6
|
+
add_column :users, :unconfirmed_email, :string
|
7
|
+
end
|
8
|
+
end
|
@@ -5,18 +5,18 @@ class TestWithCaptcha < ActionController::TestCase
|
|
5
5
|
tests Captcha::SessionsController
|
6
6
|
|
7
7
|
setup do
|
8
|
-
@request.env[
|
8
|
+
@request.env['devise.mapping'] = Devise.mappings[:captcha_user]
|
9
9
|
end
|
10
10
|
|
11
11
|
test 'When captcha is enabled, it is inserted correctly' do
|
12
12
|
post :create, params: {
|
13
13
|
captcha_user: {
|
14
|
-
email:
|
15
|
-
password:
|
14
|
+
email: 'wrong@email.com',
|
15
|
+
password: 'wrongpassword'
|
16
16
|
}
|
17
17
|
}
|
18
18
|
|
19
|
-
assert_equal
|
19
|
+
assert_equal 'The captcha input was invalid.', flash[:alert]
|
20
20
|
assert_redirected_to new_captcha_user_session_path
|
21
21
|
end
|
22
22
|
|
@@ -26,14 +26,14 @@ class TestWithCaptcha < ActionController::TestCase
|
|
26
26
|
end
|
27
27
|
|
28
28
|
post :create, params: {
|
29
|
-
captcha:
|
29
|
+
captcha: 'ABCDE',
|
30
30
|
captcha_user: {
|
31
|
-
email:
|
32
|
-
password:
|
31
|
+
email: 'wrong@email.com',
|
32
|
+
password: 'wrongpassword'
|
33
33
|
}
|
34
34
|
}
|
35
35
|
|
36
|
-
assert_equal
|
36
|
+
assert_equal 'Invalid Email or password.', flash[:alert]
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -42,17 +42,17 @@ class TestWithoutCaptcha < ActionController::TestCase
|
|
42
42
|
tests Devise::SessionsController
|
43
43
|
|
44
44
|
setup do
|
45
|
-
@request.env[
|
45
|
+
@request.env['devise.mapping'] = Devise.mappings[:user]
|
46
46
|
end
|
47
47
|
|
48
48
|
test 'When captcha is not enabled, it is not inserted' do
|
49
|
-
post :create, params: {
|
49
|
+
post :create, params: {
|
50
50
|
user: {
|
51
|
-
email:
|
52
|
-
password:
|
51
|
+
email: 'wrong@email.com',
|
52
|
+
password: 'wrongpassword'
|
53
53
|
}
|
54
54
|
}
|
55
55
|
|
56
|
-
assert_equal
|
56
|
+
assert_equal 'Invalid Email or password.', flash[:alert]
|
57
57
|
end
|
58
58
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
ENV['RAILS_ENV'] ||= 'test'
|
2
2
|
|
3
|
+
require 'simplecov'
|
3
4
|
require 'coveralls'
|
4
5
|
Coveralls.wear!
|
5
6
|
|
@@ -11,3 +12,9 @@ require 'devise-security'
|
|
11
12
|
ActiveRecord::Migration.verbose = false
|
12
13
|
ActiveRecord::Base.logger = Logger.new(nil)
|
13
14
|
ActiveRecord::Migrator.migrate(File.expand_path('../dummy/db/migrate', __FILE__))
|
15
|
+
|
16
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
17
|
+
SimpleCov.start do
|
18
|
+
add_filter 'test/dummy'
|
19
|
+
add_filter 'gemfiles'
|
20
|
+
end
|