devise-security 0.12.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +3 -1
  3. data/README.md +199 -65
  4. data/app/controllers/devise/paranoid_verification_code_controller.rb +28 -12
  5. data/app/controllers/devise/password_expired_controller.rb +34 -10
  6. data/app/views/devise/paranoid_verification_code/show.html.erb +4 -4
  7. data/app/views/devise/password_expired/show.html.erb +6 -6
  8. data/config/locales/bg.yml +42 -0
  9. data/config/locales/by.yml +50 -0
  10. data/config/locales/cs.yml +46 -0
  11. data/config/locales/de.yml +33 -7
  12. data/config/locales/en.yml +26 -1
  13. data/config/locales/es.yml +31 -6
  14. data/config/locales/fa.yml +42 -0
  15. data/config/locales/fr.yml +42 -0
  16. data/config/locales/hi.yml +43 -0
  17. data/config/locales/it.yml +36 -4
  18. data/config/locales/ja.yml +42 -0
  19. data/config/locales/nl.yml +42 -0
  20. data/config/locales/pt.yml +42 -0
  21. data/config/locales/ru.yml +50 -0
  22. data/config/locales/tr.yml +42 -0
  23. data/config/locales/uk.yml +50 -0
  24. data/config/locales/zh_CN.yml +42 -0
  25. data/config/locales/zh_TW.yml +42 -0
  26. data/lib/devise-security/controllers/helpers.rb +74 -51
  27. data/lib/devise-security/hooks/expirable.rb +6 -4
  28. data/lib/devise-security/hooks/paranoid_verification.rb +3 -3
  29. data/lib/devise-security/hooks/password_expirable.rb +5 -3
  30. data/lib/devise-security/hooks/session_limitable.rb +31 -14
  31. data/lib/devise-security/models/active_record/old_password.rb +5 -0
  32. data/lib/devise-security/models/compatibility/active_record_patch.rb +41 -0
  33. data/lib/devise-security/models/compatibility/mongoid_patch.rb +32 -0
  34. data/lib/devise-security/models/compatibility.rb +8 -15
  35. data/lib/devise-security/models/database_authenticatable_patch.rb +20 -10
  36. data/lib/devise-security/models/expirable.rb +14 -7
  37. data/lib/devise-security/models/mongoid/old_password.rb +21 -0
  38. data/lib/devise-security/models/paranoid_verification.rb +4 -2
  39. data/lib/devise-security/models/password_archivable.rb +19 -8
  40. data/lib/devise-security/models/password_expirable.rb +103 -48
  41. data/lib/devise-security/models/secure_validatable.rb +69 -12
  42. data/lib/devise-security/models/security_questionable.rb +2 -0
  43. data/lib/devise-security/models/session_limitable.rb +19 -2
  44. data/lib/devise-security/orm/mongoid.rb +7 -0
  45. data/lib/devise-security/patches/controller_captcha.rb +2 -0
  46. data/lib/devise-security/patches/controller_security_question.rb +3 -1
  47. data/lib/devise-security/patches.rb +16 -8
  48. data/lib/devise-security/rails.rb +2 -0
  49. data/lib/devise-security/routes.rb +4 -3
  50. data/lib/devise-security/validators/password_complexity_validator.rb +62 -0
  51. data/lib/devise-security/version.rb +3 -1
  52. data/lib/devise-security.rb +23 -11
  53. data/lib/generators/devise_security/install_generator.rb +6 -6
  54. data/lib/generators/templates/devise_security.rb +52 -0
  55. data/test/{test_captcha_controller.rb → controllers/test_captcha_controller.rb} +2 -0
  56. data/test/controllers/test_paranoid_verification_code_controller.rb +133 -0
  57. data/test/controllers/test_password_expired_controller.rb +164 -0
  58. data/test/controllers/test_security_question_controller.rb +66 -0
  59. data/test/dummy/Rakefile +3 -1
  60. data/test/dummy/app/assets/config/manifest.js +3 -0
  61. data/test/dummy/app/controllers/application_controller.rb +2 -0
  62. data/test/dummy/app/controllers/captcha/sessions_controller.rb +2 -0
  63. data/test/dummy/app/controllers/overrides/paranoid_verification_code_controller.rb +7 -0
  64. data/test/dummy/app/controllers/overrides/password_expired_controller.rb +17 -0
  65. data/test/dummy/app/controllers/security_question/unlocks_controller.rb +2 -0
  66. data/test/dummy/app/controllers/widgets_controller.rb +9 -0
  67. data/test/dummy/app/models/application_record.rb +10 -2
  68. data/test/dummy/app/models/application_user_record.rb +12 -0
  69. data/test/dummy/app/models/captcha_user.rb +7 -2
  70. data/test/dummy/app/models/mongoid/confirmable_fields.rb +15 -0
  71. data/test/dummy/app/models/mongoid/database_authenticable_fields.rb +18 -0
  72. data/test/dummy/app/models/mongoid/expirable_fields.rb +13 -0
  73. data/test/dummy/app/models/mongoid/lockable_fields.rb +15 -0
  74. data/test/dummy/app/models/mongoid/mappings.rb +15 -0
  75. data/test/dummy/app/models/mongoid/omniauthable_fields.rb +13 -0
  76. data/test/dummy/app/models/mongoid/paranoid_verification_fields.rb +12 -0
  77. data/test/dummy/app/models/mongoid/password_archivable_fields.rb +11 -0
  78. data/test/dummy/app/models/mongoid/password_expirable_fields.rb +12 -0
  79. data/test/dummy/app/models/mongoid/recoverable_fields.rb +13 -0
  80. data/test/dummy/app/models/mongoid/registerable_fields.rb +21 -0
  81. data/test/dummy/app/models/mongoid/rememberable_fields.rb +12 -0
  82. data/test/dummy/app/models/mongoid/secure_validatable_fields.rb +13 -0
  83. data/test/dummy/app/models/mongoid/security_questionable_fields.rb +15 -0
  84. data/test/dummy/app/models/mongoid/session_limitable_fields.rb +12 -0
  85. data/test/dummy/app/models/mongoid/timeoutable_fields.rb +11 -0
  86. data/test/dummy/app/models/mongoid/trackable_fields.rb +16 -0
  87. data/test/dummy/app/models/mongoid/validatable_fields.rb +9 -0
  88. data/test/dummy/app/models/paranoid_verification_user.rb +26 -0
  89. data/test/dummy/app/models/password_expired_user.rb +26 -0
  90. data/test/dummy/app/models/security_question_user.rb +9 -4
  91. data/test/dummy/app/models/user.rb +16 -1
  92. data/test/dummy/app/models/widget.rb +4 -0
  93. data/test/dummy/app/mongoid/admin.rb +31 -0
  94. data/test/dummy/app/mongoid/one_user.rb +58 -0
  95. data/test/dummy/app/mongoid/shim.rb +25 -0
  96. data/test/dummy/app/mongoid/user_on_engine.rb +41 -0
  97. data/test/dummy/app/mongoid/user_on_main_app.rb +41 -0
  98. data/test/dummy/app/mongoid/user_with_validations.rb +37 -0
  99. data/test/dummy/app/mongoid/user_without_email.rb +38 -0
  100. data/test/dummy/config/application.rb +13 -11
  101. data/test/dummy/config/boot.rb +3 -1
  102. data/test/dummy/config/environment.rb +3 -1
  103. data/test/dummy/config/environments/test.rb +6 -13
  104. data/test/dummy/config/initializers/devise.rb +6 -3
  105. data/test/dummy/config/initializers/migration_class.rb +3 -6
  106. data/test/dummy/config/locales/en.yml +10 -0
  107. data/test/dummy/config/mongoid.yml +6 -0
  108. data/test/dummy/config/routes.rb +8 -3
  109. data/test/dummy/config.ru +3 -1
  110. data/test/dummy/db/migrate/20120508165529_create_tables.rb +17 -6
  111. data/test/dummy/db/migrate/20150402165590_add_verification_columns.rb +2 -0
  112. data/test/dummy/db/migrate/20150407162345_add_verification_attempt_column.rb +2 -0
  113. data/test/dummy/db/migrate/20160320162345_add_security_questions_fields.rb +2 -0
  114. data/test/dummy/db/migrate/20180318103603_add_expireable_columns.rb +2 -0
  115. data/test/dummy/db/migrate/20180318105329_add_confirmable_columns.rb +2 -0
  116. data/test/dummy/db/migrate/20180318105732_add_rememberable_columns.rb +2 -0
  117. data/test/dummy/db/migrate/20180318111336_add_recoverable_columns.rb +2 -0
  118. data/test/dummy/db/migrate/20180319114023_add_widget.rb +2 -0
  119. data/test/dummy/lib/shared_expirable_columns.rb +15 -0
  120. data/test/dummy/lib/shared_security_questions_fields.rb +17 -0
  121. data/test/dummy/lib/shared_user.rb +43 -0
  122. data/test/dummy/lib/shared_user_with_password_verification.rb +13 -0
  123. data/test/dummy/lib/shared_user_without_omniauth.rb +24 -0
  124. data/test/dummy/lib/shared_verification_fields.rb +16 -0
  125. data/test/dummy/log/test.log +45240 -0
  126. data/test/i18n_test.rb +22 -0
  127. data/test/integration/test_paranoid_verification_code_workflow.rb +53 -0
  128. data/test/integration/test_password_expirable_workflow.rb +53 -0
  129. data/test/integration/test_session_limitable_workflow.rb +69 -0
  130. data/test/orm/active_record.rb +15 -0
  131. data/test/orm/mongoid.rb +13 -0
  132. data/test/support/integration_helpers.rb +35 -0
  133. data/test/support/mongoid.yml +6 -0
  134. data/test/test_compatibility.rb +15 -0
  135. data/test/test_complexity_validator.rb +282 -0
  136. data/test/test_database_authenticatable_patch.rb +146 -0
  137. data/test/test_helper.rb +41 -9
  138. data/test/test_install_generator.rb +20 -3
  139. data/test/test_paranoid_verification.rb +10 -9
  140. data/test/test_password_archivable.rb +37 -13
  141. data/test/test_password_expirable.rb +72 -9
  142. data/test/test_secure_validatable.rb +289 -55
  143. data/test/test_secure_validatable_overrides.rb +185 -0
  144. data/test/test_session_limitable.rb +57 -0
  145. data/test/tmp/config/initializers/devise_security.rb +52 -0
  146. data/test/tmp/config/locales/devise.security_extension.by.yml +50 -0
  147. data/test/tmp/config/locales/devise.security_extension.cs.yml +46 -0
  148. data/test/tmp/config/locales/devise.security_extension.de.yml +42 -0
  149. data/test/tmp/config/locales/devise.security_extension.en.yml +42 -0
  150. data/test/tmp/config/locales/devise.security_extension.es.yml +42 -0
  151. data/test/tmp/config/locales/devise.security_extension.fa.yml +42 -0
  152. data/test/tmp/config/locales/devise.security_extension.fr.yml +42 -0
  153. data/test/tmp/config/locales/devise.security_extension.hi.yml +43 -0
  154. data/test/tmp/config/locales/devise.security_extension.it.yml +42 -0
  155. data/test/tmp/config/locales/devise.security_extension.ja.yml +42 -0
  156. data/test/tmp/config/locales/devise.security_extension.nl.yml +42 -0
  157. data/test/tmp/config/locales/devise.security_extension.pt.yml +42 -0
  158. data/test/tmp/config/locales/devise.security_extension.ru.yml +50 -0
  159. data/test/tmp/config/locales/devise.security_extension.tr.yml +42 -0
  160. data/test/tmp/config/locales/devise.security_extension.uk.yml +50 -0
  161. data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +42 -0
  162. data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +42 -0
  163. metadata +290 -124
  164. data/.circleci/config.yml +0 -41
  165. data/.document +0 -5
  166. data/.gitignore +0 -40
  167. data/.rubocop.yml +0 -63
  168. data/.ruby-version +0 -1
  169. data/.travis.yml +0 -25
  170. data/Appraisals +0 -19
  171. data/Gemfile +0 -3
  172. data/Rakefile +0 -28
  173. data/devise-security.gemspec +0 -44
  174. data/gemfiles/rails_4.1_stable.gemfile +0 -8
  175. data/gemfiles/rails_4.2_stable.gemfile +0 -8
  176. data/gemfiles/rails_5.0_stable.gemfile +0 -8
  177. data/gemfiles/rails_5.1_stable.gemfile +0 -8
  178. data/gemfiles/rails_5.2_rc1.gemfile +0 -8
  179. data/lib/devise-security/models/old_password.rb +0 -4
  180. data/lib/devise-security/orm/active_record.rb +0 -18
  181. data/lib/devise-security/patches/confirmations_controller_captcha.rb +0 -21
  182. data/lib/devise-security/patches/confirmations_controller_security_question.rb +0 -24
  183. data/lib/devise-security/patches/passwords_controller_captcha.rb +0 -20
  184. data/lib/devise-security/patches/passwords_controller_security_question.rb +0 -23
  185. data/lib/devise-security/patches/registrations_controller_captcha.rb +0 -33
  186. data/lib/devise-security/patches/sessions_controller_captcha.rb +0 -24
  187. data/lib/devise-security/patches/unlocks_controller_captcha.rb +0 -20
  188. data/lib/devise-security/patches/unlocks_controller_security_question.rb +0 -23
  189. data/lib/devise-security/schema.rb +0 -64
  190. data/lib/generators/templates/devise-security.rb +0 -38
  191. data/test/dummy/app/controllers/foos_controller.rb +0 -0
  192. data/test/dummy/app/models/.gitkeep +0 -0
  193. data/test/dummy/app/models/secure_user.rb +0 -3
  194. data/test/test_password_expired_controller.rb +0 -44
  195. data/test/test_security_question_controller.rb +0 -84
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ccd3b9a01ec2f531013bbed8d14cbf3131f2630d2c2d1a56d119268f1aa696c
4
- data.tar.gz: f9305b860b267fd4f49dc724864d1d822c1e4d0f952be56f78d02d1c6b1a1b3c
3
+ metadata.gz: 30c17693a3331769b786cf6925dcce0b62087a894960309ad316189613b62291
4
+ data.tar.gz: defa2b29a2d67e7615062ab6bea7518b37b6f24ed4735016a4fca4ef860ffbd0
5
5
  SHA512:
6
- metadata.gz: f176d4afaee6b712cc7fa83c234cca6f286729f8a03660c33d10cf5cd363f49f70e56440f3e9e960f275ef4f7b2a846f60984af73e46e55f73266b431314cee1
7
- data.tar.gz: 00e810e6e1c6c1845cc67d534206378c111499f09bb849a8d4129b20bc4c52a89b9261cfaf07ec7bb243995cc016f50f26c99eba29a9c1c148b3d9ec8b6632c5
6
+ metadata.gz: 54fa56d5e200c73e329d1f07eb1845ce2be695ffb4afa20f475d624fb6615f1583a161c8eec8fa5f84643b957a0d9e4d4d653d5f5071f7b73784bf843a520a70
7
+ data.tar.gz: 891fcf2b29571ee6fca9d667ddbc211cf27a5ba64e6048b33d3f63a6f395e02ef88d51a6c35da3bfe761b42c04bf1a57e118ae9bb46ebb22212eb85f9a0b3179
data/LICENSE.txt CHANGED
@@ -1,4 +1,6 @@
1
- Copyright (c) 2011 Marco Scholl
1
+ Copyright (c) 2017-2022 Dillon Welch & Kevin Olbrich.
2
+
3
+ Copyright (c) 2011-2017 Marco Scholl
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,30 +1,45 @@
1
1
  # Devise Security
2
2
 
3
- [![Build Status](https://travis-ci.org/devise-security/devise-security.svg?branch=master)](https://travis-ci.org/devise-security/devise-security)
3
+ [![Build Status](https://github.com/devise-security/devise-security/actions/workflows/test_suite.yml/badge.svg?branch=master)](https://github.com/devise-security/devise-security/actions/workflows/test_suite.yml)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/devise-security/devise-security/badge.svg?branch=master)](https://coveralls.io/github/devise-security/devise-security?branch=master)
5
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/ace7cd003a0db8bffa5a/maintainability)](https://codeclimate.com/github/devise-security/devise-security/maintainability)
6
6
 
7
- A [Devise](https://github.com/plataformatec/devise) extension to add additional security features required by modern web applications. Forked from [Devise Security Extension](https://github.com/phatworx/devise_security_extension)
7
+ A [Devise](https://github.com/heartcombo/devise) extension to add additional
8
+ security features required by modern web applications. Forked from
9
+ [Devise Security Extension](https://github.com/phatworx/devise_security_extension)
8
10
 
9
11
  It is composed of 7 additional Devise modules:
10
12
 
11
- * `:password_expirable` - passwords will expire after a configured time (and will need an update). You will most likely want to use `:password_expirable` together with the `:password_archivable` module to [prevent the current expired password being reused](https://github.com/phatworx/devise_security_extension/issues/175) immediately as the new password.
12
- * `:secure_validatable` - better way to validate a model (email, stronger password validation). Don't use with Devise `:validatable` module!
13
- * `:password_archivable` - save used passwords in an `old_passwords` table for history checks (don't be able to use a formerly used password)
14
- * `:session_limitable` - ensures, that there is only one session usable per account at once
15
- * `:expirable` - expires a user account after x days of inactivity (default 90 days)
16
- * `:security_questionable` - as accessible substitution for captchas (security question with captcha fallback)
17
- * `:paranoid_verification` - admin can generate verification code that user needs to fill in otherwise he wont be able to use the application.
13
+ - `:password_expirable` - passwords will expire after a configured time (and
14
+ will need to be changed by the user). You will most likely want to use
15
+ `:password_expirable` together with the `:password_archivable` module to
16
+ [prevent the current expired password from being reused](https://github.com/phatworx/devise_security_extension/issues/175)
17
+ immediately as the new password.
18
+ - `:secure_validatable` - better way to validate a model (email, stronger
19
+ password validation). Don't use with Devise `:validatable` module!
20
+ - `:password_archivable` - save used passwords in an `old_passwords` table for
21
+ history checks (prevent reusing passwords)
22
+ - `:session_limitable` - ensures, that there is only one session usable per
23
+ account at once
24
+ - `:expirable` - expires a user account after x days of inactivity (default 90
25
+ days)
26
+ - `:security_questionable` - as accessible substitution for captchas (security
27
+ question with captcha fallback)
28
+ - `:paranoid_verification` - admin can generate verification code that user
29
+ needs to fill in otherwise he won't be able to use the application.
18
30
 
19
31
  Configuration and database schema for each module below.
20
32
 
21
33
  ## Additional features
22
34
 
23
- * **captcha support** for `sign_up`, `sign_in`, `recover` and `unlock` (to make automated mass creation and brute forcing of accounts harder)
35
+ **captcha support** for `sign_up`, `sign_in`, `recover` and `unlock` (to make
36
+ automated mass creation and brute forcing of accounts harder)
24
37
 
25
38
  ## Getting started
26
39
 
27
- Devise Security works with Devise on Rails 4.1 onwards. You can add it to your Gemfile after you successfully set up Devise (see [Devise documentation](https://github.com/plataformatec/devise)) with:
40
+ Devise Security works with Devise on Rails >= 5.2. You can add it to your
41
+ Gemfile after you successfully set up Devise (see
42
+ [Devise documentation](https://github.com/heartcombo/devise)) with:
28
43
 
29
44
  ```ruby
30
45
  gem 'devise-security'
@@ -38,18 +53,27 @@ After you installed Devise Security you need to run the generator:
38
53
  rails generate devise_security:install
39
54
  ```
40
55
 
41
- The generator adds optional configurations to `config/initializers/devise-security.rb`. Enable
42
- the modules you wish to use in the initializer you are ready to add Devise Security modules on top of Devise modules to any of your Devise models:
56
+ The generator adds optional configurations to
57
+ `config/initializers/devise_security.rb`. Enable the modules you wish to use in
58
+ the initializer you are ready to add Devise Security modules on top of Devise
59
+ modules to any of your Devise models:
43
60
 
44
61
  ```ruby
45
62
  devise :password_expirable, :secure_validatable, :password_archivable, :session_limitable, :expirable
46
63
  ```
47
64
 
48
- for `:secure_validatable` you need to add
65
+ ### E-mail Validation
49
66
 
50
- ```ruby
51
- gem 'rails_email_validator'
52
- ```
67
+ For `:secure_validatable` you need to have a way to validate an e-mail. There
68
+ are multiple libraries that support this, and even a way built into Ruby!
69
+
70
+ - (Recommended) Ruby built-in `URI::MailTo::EMAIL_REGEXP` constant
71
+ > Note: This method would require a `email_validation` method to be defined in
72
+ > order to hook into the `validates` method defined here.
73
+ - [email_address](https://github.com/afair/email_address) gem
74
+ - [valid_email2](https://github.com/micke/valid_email2) gem
75
+ - [rails_email_validator](https://github.com/phatworx/rails_email_validator) gem
76
+ (deprecated)
53
77
 
54
78
  ## Configuration
55
79
 
@@ -58,11 +82,16 @@ Devise.setup do |config|
58
82
  # ==> Security Extension
59
83
  # Configure security extension for devise
60
84
 
61
- # Should the password expire (e.g 3.months)
62
- # config.expire_password_after = 3.months
85
+ # Password expires after a configurable time (in seconds).
86
+ # Or expire passwords on demand by setting this configuration to `true`
87
+ # Use `user.need_change_password!` to expire a password.
88
+ # Setting the configuration to `false` will completely disable expiration checks.
89
+ # config.expire_password_after = 3.months | true | false
63
90
 
64
- # Need 1 char of A-Z, a-z and 0-9
65
- # config.password_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/
91
+ # Need 1 char each of: A-Z, a-z, 0-9, and a punctuation mark or symbol
92
+ # You may use "digits" in place of "digit" and "symbols" in place of
93
+ # "symbol" based on your preference
94
+ # config.password_complexity = { digit: 1, lower: 1, symbol: 1, upper: 1 }
66
95
 
67
96
  # Number of old passwords in archive
68
97
  # config.password_archiving_count = 5
@@ -97,34 +126,84 @@ Devise.setup do |config|
97
126
  # ==> Configuration for :expirable
98
127
  # Time period for account expiry from last_activity_at
99
128
  # config.expire_after = 90.days
129
+
130
+ # Allow passwords to be equal to email (false, true)
131
+ # config.allow_passwords_equal_to_email = false
132
+
133
+ # paranoid_verification will regenerate verification code after failed attempt
134
+ # config.paranoid_code_regenerate_after_attempt = 10
100
135
  end
101
136
  ```
102
137
 
103
- ## Captcha-Support
104
- The captcha support depends on [EasyCaptcha](https://github.com/phatworx/easy_captcha). See further documentation there.
138
+ ## Other ORMs
105
139
 
106
- ### Installation
140
+ Devise-security supports [Mongoid](https://rubygems.org/gems/mongoid) as an
141
+ alternative ORM to active_record. To use this ORM, add this to your `Gemfile`.
107
142
 
108
- 1. Add EasyCaptcha to your `Gemfile` with
109
143
  ```ruby
110
- gem 'easy_captcha'
144
+ gem 'mongoid'
111
145
  ```
112
- 2. Run the initializer
146
+
147
+ And then ensure that the environment variable `DEVISE_ORM=mongoid` is set.
148
+
149
+ For local development you will need to have MongoDB installed locally.
150
+
151
+ ```bash
152
+ brew install mongodb
153
+ ```
154
+
155
+ ### Rails App setup example with Mongoid
156
+
113
157
  ```ruby
114
- rails generate easy_captcha:install
158
+ # inside config/application.rb
159
+ require File.expand_path('../boot', __FILE__)
160
+ #...
161
+ DEVISE_ORM=:mongoid
162
+
163
+ # Require the gems listed in Gemfile, including any gems
164
+ # you've limited to :test, :development, or :production.
165
+ Bundler.require(*Rails.groups)
166
+
167
+ module MyApp
168
+ class Application < Rails::Application
169
+ #...
170
+ end
171
+ end
115
172
  ```
173
+
174
+ ## Captcha-Support
175
+
176
+ The captcha support depends on
177
+ [EasyCaptcha](https://github.com/phatworx/easy_captcha). See further
178
+ documentation there.
179
+
180
+ ### Installation
181
+
182
+ 1. Add EasyCaptcha to your `Gemfile` with
183
+
184
+ ```ruby
185
+ gem 'easy_captcha'
186
+ ```
187
+
188
+ 2. Run the initializer
189
+
190
+ ```ruby
191
+ rails generate easy_captcha:install
192
+ ```
193
+
116
194
  3. Enable captcha - see "Configuration" of Devise Security above.
117
- 4. Add the captcha in the generated devise views for each controller you have activated
118
- ```erb
119
- <p><%= captcha_tag %></p>
120
- <p><%= text_field_tag :captcha %></p>
121
- ```
195
+ 4. Add the captcha in the generated devise views for each controller you have
196
+ activated.
122
197
 
123
- ## Schema
198
+ ```erb
199
+ <p><%= captcha_tag %></p>
200
+ <p><%= text_field_tag :captcha %></p>
201
+ ```
124
202
 
125
- Note: Unlike Devise, devise-security does not currently support mongoid. Pull requests are welcome!
203
+ ## Schema
126
204
 
127
205
  ### Password expirable
206
+
128
207
  ```ruby
129
208
  create_table :the_resources do |t|
130
209
  # other devise fields
@@ -134,7 +213,11 @@ end
134
213
  add_index :the_resources, :password_changed_at
135
214
  ```
136
215
 
216
+ Note: setting `password_changed_at` to `nil` will require the user to change
217
+ their password.
218
+
137
219
  ### Password archivable
220
+
138
221
  ```ruby
139
222
  create_table :old_passwords do |t|
140
223
  t.string :encrypted_password, null: false
@@ -143,19 +226,35 @@ create_table :old_passwords do |t|
143
226
  t.string :password_salt # Optional. bcrypt stores the salt in the encrypted password field so this column may not be necessary.
144
227
  t.datetime :created_at
145
228
  end
146
- add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: :index_password_archivable
229
+ add_index :old_passwords, [:password_archivable_type, :password_archivable_id], name: 'index_password_archivable'
147
230
  ```
148
231
 
149
232
  ### Session limitable
233
+
150
234
  ```ruby
151
235
  create_table :the_resources do |t|
152
236
  # other devise fields
153
237
 
154
- t.string :unique_session_id, limit: 20
238
+ t.string :unique_session_id
155
239
  end
156
240
  ```
157
241
 
242
+ #### Bypassing session limitable
243
+
244
+ Sometimes it's useful to impersonate a user without authentication (e.g.
245
+ [administrator impersonating a user](https://github.com/heartcombo/devise/wiki/How-To:-Sign-in-as-another-user-if-you-are-an-admin)),
246
+ in this case the `session_limitable` strategy will log out the user, and if the
247
+ user logs in while the administrator is still logged in, the administrator will
248
+ be logged out.
249
+
250
+ For such cases the following can be used:
251
+
252
+ ```ruby
253
+ sign_in(User.find(params[:id]), scope: :user, skip_session_limitable: true)
254
+ ```
255
+
158
256
  ### Expirable
257
+
159
258
  ```ruby
160
259
  create_table :the_resources do |t|
161
260
  # other devise fields
@@ -168,6 +267,7 @@ add_index :the_resources, :expired_at
168
267
  ```
169
268
 
170
269
  ### Paranoid verifiable
270
+
171
271
  ```ruby
172
272
  create_table :the_resources do |t|
173
273
  # other devise fields
@@ -180,7 +280,7 @@ add_index :the_resources, :paranoid_verification_code
180
280
  add_index :the_resources, :paranoid_verified_at
181
281
  ```
182
282
 
183
- [Documentation for Paranoid Verifiable module]( https://github.com/devise-security/devise-security/wiki/Paranoid-Verification)
283
+ [Documentation for Paranoid Verifiable module](https://github.com/devise-security/devise-security/wiki/Paranoid-Verification)
184
284
 
185
285
  ### Security questionable
186
286
 
@@ -207,7 +307,6 @@ SecurityQuestion.create! locale: :de, name: 'Was ist Ihr Lieblingstier?'
207
307
  SecurityQuestion.create! locale: :de, name: 'Was ist Ihr Lieblings-Reiseland?'
208
308
  ```
209
309
 
210
-
211
310
  ```ruby
212
311
  add_column :the_resources, :security_question_id, :integer
213
312
  add_column :the_resources, :security_question_answer, :string
@@ -226,43 +325,78 @@ end
226
325
 
227
326
  ## Requirements
228
327
 
229
- * Devise (https://github.com/plataformatec/devise)
230
- * Rails 4.1 onwards (http://github.com/rails/rails)
231
- * recommendations:
232
- * `autocomplete-off` (http://github.com/phatworx/autocomplete-off)
233
- * `easy_captcha` (http://github.com/phatworx/easy_captcha)
234
- * `rails_email_validator` (http://github.com/phatworx/rails_email_validator)
235
-
328
+ - Devise (<https://github.com/heartcombo/devise>)
329
+ - Rails 5.2 onwards (<http://github.com/rails/rails>)
330
+ - recommendations:
331
+ - `autocomplete-off` (<http://github.com/phatworx/autocomplete-off>)
332
+ - `easy_captcha` (<http://github.com/phatworx/easy_captcha>)
333
+ - `mongodb` (<https://www.mongodb.com/>)
334
+ - `rvm` (<https://rvm.io/>)
236
335
 
237
336
  ## Todo
238
337
 
239
- * see the github issues (feature requests)
338
+ - see the github issues (feature requests)
240
339
 
241
340
  ## History
242
- * 0.1 expire passwords
243
- * 0.2 strong password validation
244
- * 0.3 password archivable with validation
245
- * 0.4 captcha support for sign_up, sign_in, recover and unlock
246
- * 0.5 session_limitable module
247
- * 0.6 expirable module
248
- * 0.7 security questionable module for recover and unlock
249
- * 0.8 Support for Rails 4 (+ variety of patches)
250
- * 0.11 Support for Rails 5. Forked to allow project maintenance and features
341
+
342
+ - 0.1 expire passwords
343
+ - 0.2 strong password validation
344
+ - 0.3 password archivable with validation
345
+ - 0.4 captcha support for sign_up, sign_in, recover and unlock
346
+ - 0.5 session_limitable module
347
+ - 0.6 expirable module
348
+ - 0.7 security questionable module for recover and unlock
349
+ - 0.8 Support for Rails 4 (+ variety of patches)
350
+ - 0.11 Support for Rails 5. Forked to allow project maintenance and features
351
+
352
+ See also
353
+ [Github Releases](https://github.com/devise-security/devise-security/releases)
251
354
 
252
355
  ## Maintainers
253
356
 
254
- * Nate Bird (https://github.com/natebird)
357
+ - Nate Bird (<https://github.com/natebird>)
358
+ - Kevin Olbrich (<http://github.com/olbrich>)
359
+ - Dillon Welch (<http://github.com/oniofchaos>)
255
360
 
256
361
  ## Contributing to devise-security
257
362
 
258
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
259
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
260
- * Fork the project
261
- * Start a feature/bugfix branch
262
- * Commit and push until you are happy with your contribution
263
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
264
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
363
+ - Check out the latest master to make sure the feature hasn't been implemented
364
+ or the bug hasn't been fixed yet
365
+ - Check out the issue tracker to make sure someone already hasn't requested it
366
+ and/or contributed it
367
+ - Fork the project
368
+ - Start a feature/bugfix branch
369
+ - Commit and push until you are happy with your contribution
370
+ - Make sure to add tests for it. This is important so I don't break it in a
371
+ future version unintentionally.
372
+ - Please try not to mess with the Rakefile, version, or history. If you want to
373
+ have your own version, or is otherwise necessary, that is fine, but please
374
+ isolate to its own commit so I can cherry-pick around it.
375
+
376
+ ## Running tests
377
+
378
+ Standard tests can be invoked using `rake`. To run the tests against the
379
+ `mongoid` ORM, use `DEVISE_ORM=mongoid rake` while `mongodb` is running.
380
+
381
+ ## Maintenance Policy
382
+
383
+ We are committed to maintaining support for `devise-security` for all normal or
384
+ security maintenance versions of the Ruby language
385
+ [as listed here](https://www.ruby-lang.org/en/downloads/branches/), and for the
386
+ Ruby on Rails framework
387
+ [as per their maintenance policy](https://rubyonrails.org/maintenance/).
388
+
389
+ To avoid introducing bugs caused by backwardly incompatible Ruby
390
+ language features, it is highly recommended that all development work be done
391
+ using the oldest supported Ruby version. The contents of the `.ruby-version`
392
+ file should reflect this.
265
393
 
266
394
  ## Copyright
267
395
 
268
- Copyright (c) 2011-2017 Marco Scholl. See LICENSE.txt for further details.
396
+ Copyright (c) 2017-2023 Dillon Welch & Kevin Olbrich.
397
+
398
+ Copyright (c) 2011-2017 Marco Scholl as the project [`devise_security_extension`](https://github.com/phatworx/devise_security_extension).
399
+
400
+ This repo was created as a fork from [b2ee978a](https://github.com/phatworx/devise_security_extension/commit/b2ee978af7d49f0fb0e7271c6ac074dfb4d39353).
401
+
402
+ See LICENSE.txt for further details.
@@ -1,13 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Devise::ParanoidVerificationCodeController < DeviseController
4
+ before_action :verify_requested_format!
2
5
  skip_before_action :handle_paranoid_verification
3
- prepend_before_action :authenticate_scope!, only: [:show, :update]
6
+ before_action :skip_paranoid_verification, only: %i[show update]
7
+ prepend_before_action :authenticate_scope!, only: %i[show update]
4
8
 
5
9
  def show
6
- if !resource.nil? && resource.need_paranoid_verification?
7
- respond_with(resource)
8
- else
9
- redirect_to :root
10
- end
10
+ respond_with(resource)
11
11
  end
12
12
 
13
13
  def update
@@ -15,20 +15,36 @@ class Devise::ParanoidVerificationCodeController < DeviseController
15
15
  warden.session(scope)['paranoid_verify'] = false
16
16
  set_flash_message :notice, :updated
17
17
  bypass_sign_in resource, scope: scope
18
- redirect_to stored_location_for(scope) || :root
18
+ respond_with({}, location: after_paranoid_verification_code_update_path_for(resource))
19
19
  else
20
20
  respond_with(resource, action: :show)
21
21
  end
22
22
  end
23
23
 
24
+ # Allows you to customize where the user is redirected to after the update action
25
+ # successfully completes.
26
+ #
27
+ # Defaults to the request's original path, and then `root` if that is `nil`.
28
+ #
29
+ # @param resource [ActiveModel::Model] Devise `resource` model for logged in user.
30
+ #
31
+ # @return [String, Symbol] The path that the user will be redirected to.
32
+ def after_paranoid_verification_code_update_path_for(_resource)
33
+ stored_location_for(scope) || :root
34
+ end
35
+
24
36
  private
25
37
 
38
+ def skip_paranoid_verification
39
+ return if !resource.nil? && resource.need_paranoid_verification?
40
+
41
+ redirect_to :root
42
+ end
43
+
26
44
  def resource_params
27
- if params.respond_to?(:permit)
28
- params.require(resource_name).permit(:paranoid_verification_code)
29
- else
30
- params[scope].slice(:paranoid_verification_code)
31
- end
45
+ permitted_params = %i[paranoid_verification_code]
46
+
47
+ params.require(resource_name).permit(*permitted_params)
32
48
  end
33
49
 
34
50
  def scope
@@ -1,40 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Devise::PasswordExpiredController < DeviseController
4
+ before_action :verify_requested_format!
2
5
  skip_before_action :handle_password_change
3
- before_action :skip_password_change, only: [:show, :update]
4
- prepend_before_action :authenticate_scope!, only: [:show, :update]
6
+ before_action :skip_password_change, only: %i[show update]
7
+ prepend_before_action :authenticate_scope!, only: %i[show update]
5
8
 
6
9
  def show
7
10
  respond_with(resource)
8
11
  end
9
12
 
13
+ # Update the password stored on the `resource`.
14
+ # @note if a common data format like :json or :xml are requested
15
+ # this will respond with a 204 No Content and set the Location header.
16
+ # Useful for dealing with APIs when JS clients would otherwise automatically
17
+ # follow the redirect, which can be problematic.
18
+ # @see https://stackoverflow.com/questions/228225/prevent-redirection-of-xmlhttprequest
19
+ # @see https://github.com/axios/axios/issues/932#issuecomment-307390761
20
+ # @see https://github.com/devise-security/devise-security/pull/111
10
21
  def update
11
22
  resource.extend(Devise::Models::DatabaseAuthenticatablePatch)
12
- if resource.update_with_password(resource_params)
23
+ resource.update_with_password(resource_params)
24
+
25
+ yield resource if block_given?
26
+
27
+ if resource.errors.empty?
13
28
  warden.session(scope)['password_expired'] = false
14
29
  set_flash_message :notice, :updated
15
30
  bypass_sign_in resource, scope: scope
16
- redirect_to stored_location_for(scope) || :root
31
+ respond_with({}, location: after_password_expired_update_path_for(resource))
17
32
  else
18
33
  clean_up_passwords(resource)
19
34
  respond_with(resource, action: :show)
20
35
  end
21
36
  end
22
37
 
38
+ # Allows you to customize where the user is sent to after the update action
39
+ # successfully completes.
40
+ #
41
+ # Defaults to the request's original path, and then `root` if that is `nil`.
42
+ #
43
+ # @param resource [ActiveModel::Model] Devise `resource` model for logged in user.
44
+ #
45
+ # @return [String, Symbol] The path that the user will be sent to.
46
+ def after_password_expired_update_path_for(_resource)
47
+ stored_location_for(scope) || :root
48
+ end
49
+
23
50
  private
24
51
 
25
52
  def skip_password_change
26
53
  return if !resource.nil? && resource.need_change_password?
54
+
27
55
  redirect_to :root
28
56
  end
29
57
 
30
58
  def resource_params
31
- permitted_params = [:current_password, :password, :password_confirmation]
59
+ permitted_params = %i[current_password password password_confirmation]
32
60
 
33
- if params.respond_to?(:permit)
34
- params.require(resource_name).permit(*permitted_params)
35
- else
36
- params[scope].slice(*permitted_params)
37
- end
61
+ params.require(resource_name).permit(*permitted_params)
38
62
  end
39
63
 
40
64
  def scope
@@ -1,10 +1,10 @@
1
- <h2>Submit verification code</h2>
1
+ <h2>t('.submit_verification_code')</h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: [resource_name, :paranoid_verification_code], html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render partial: 'devise/shared/error_messages' %>
5
5
 
6
- <p><%= f.label :paranoid_verification_code, 'Verification code' %><br />
6
+ <p><%= f.label :paranoid_verification_code, t('.verification_code') %><br />
7
7
  <%= f.text_field :paranoid_verification_code, value: '' %></p>
8
8
 
9
- <p><%= f.submit 'Submit' %></p>
9
+ <p><%= f.submit t('.submit') %></p>
10
10
  <% end %>
@@ -1,16 +1,16 @@
1
- <h2>Renew your password</h2>
1
+ <h2><%= t('.renew_your_password') %></h2>
2
2
 
3
3
  <%= form_for(resource, as: resource_name, url: [resource_name, :password_expired], html: { method: :put }) do |f| %>
4
- <%= devise_error_messages! %>
4
+ <%= render partial: 'devise/shared/error_messages' %>
5
5
 
6
- <p><%= f.label :current_password, 'Current password' %><br />
6
+ <p><%= f.label :current_password, t('.current_password') %><br />
7
7
  <%= f.password_field :current_password %></p>
8
8
 
9
- <p><%= f.label :password, 'New password' %><br />
9
+ <p><%= f.label :password, t('.new_password') %><br />
10
10
  <%= f.password_field :password %></p>
11
11
 
12
- <p><%= f.label :password_confirmation, 'Confirm new password' %><br />
12
+ <p><%= f.label :password_confirmation, t('.new_password_confirmation') %><br />
13
13
  <%= f.password_field :password_confirmation %></p>
14
14
 
15
- <p><%= f.submit 'Change my password' %></p>
15
+ <p><%= f.submit t('.change_my_password') %></p>
16
16
  <% end %>
@@ -0,0 +1,42 @@
1
+ bg:
2
+ errors:
3
+ messages:
4
+ taken_in_past: 'е използвана и преди.'
5
+ equal_to_current_password: 'трябва да е различна от настоящата парола.'
6
+ equal_to_email: 'трябва да е различна от e-mail адреса.'
7
+ password_complexity:
8
+ digit:
9
+ one: трябва да съдържа поне една цифра
10
+ other: трябва да съдържа %{count} цифри
11
+ lower:
12
+ one: трябва да съдържа поне една малка буква
13
+ other: трябва да съдържа поне %{count} малки букви
14
+ symbol:
15
+ one: трябва да съдържа поне един пунктоационен знак или символ
16
+ other: трябва да съдържа поне %{count} пунктоационни знака или символи
17
+ upper:
18
+ one: трябва да съдържа поне една главна буква
19
+ other: трябва да съдържа поне %{count} главни букви
20
+ devise:
21
+ invalid_captcha: 'Кодът е грешен.'
22
+ invalid_security_question: 'Отговора на тайния въпрос е грешен.'
23
+ paranoid_verify:
24
+ code_required: 'Моля въведете кода, който нашия екип по поддръжката Ви е предоставил'
25
+ paranoid_verification_code:
26
+ updated: Кодът за потвърждение е приет
27
+ show:
28
+ submit_verification_code: Изпрати код за потвърждение
29
+ verification_code: Код за потвърждение
30
+ submit: Изпрати
31
+ password_expired:
32
+ updated: 'Вашата нова парола е запазена.'
33
+ change_required: 'Вашата парола е изтекла. Моля подновете паролата си.'
34
+ show:
35
+ renew_your_password: Подновете паролата си
36
+ current_password: Настояща парола
37
+ new_password: Нова парола
38
+ new_password_confirmation: Потвърждение на нова парола
39
+ change_my_password: Промени паролата ми
40
+ failure:
41
+ session_limited: 'Вашето потребителско име и парола са използвани в друг браузър. Моля влезте отново за да продължите в този браузър.'
42
+ expired: 'Вашия акаунт е затворен поради неактивност. Моля свържете се с администратор.'