devise-secure-password 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Changelog.md +98 -0
- data/Dockerfile +44 -0
- data/Dockerfile.prev +44 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +272 -0
- data/LICENSE.txt +21 -0
- data/README.md +382 -0
- data/Rakefile +11 -0
- data/app/controllers/devise/passwords_with_policy_controller.rb +93 -0
- data/app/views/devise/passwords_with_policy/edit.html.erb +20 -0
- data/bin/console +14 -0
- data/bin/setup +6 -0
- data/config/locales/en.yml +84 -0
- data/devise-secure-password.gemspec +57 -0
- data/docker-entrypoint.sh +6 -0
- data/gemfiles/rails_5_1.gemfile +21 -0
- data/gemfiles/rails_5_2.gemfile +22 -0
- data/lib/devise/secure_password.rb +71 -0
- data/lib/devise/secure_password/controllers/devise_helpers.rb +23 -0
- data/lib/devise/secure_password/controllers/helpers.rb +58 -0
- data/lib/devise/secure_password/grammar.rb +13 -0
- data/lib/devise/secure_password/models/password_disallows_frequent_changes.rb +62 -0
- data/lib/devise/secure_password/models/password_disallows_frequent_reuse.rb +73 -0
- data/lib/devise/secure_password/models/password_has_required_content.rb +170 -0
- data/lib/devise/secure_password/models/password_requires_regular_updates.rb +54 -0
- data/lib/devise/secure_password/models/previous_password.rb +20 -0
- data/lib/devise/secure_password/routes.rb +11 -0
- data/lib/devise/secure_password/version.rb +5 -0
- data/lib/generators/devise/secure_password/install_generator.rb +30 -0
- data/lib/generators/devise/templates/README.txt +21 -0
- data/lib/generators/devise/templates/secure_password.rb +43 -0
- data/lib/support/string/character_counter.rb +55 -0
- data/pkg/devise-secure-password-1.1.1.gem +0 -0
- metadata +429 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017-2018, Valimail, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# Devise Secure Password Extension
|
2
|
+
|
3
|
+
[![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
|
4
|
+
|
5
|
+
The __Devise Secure Password Extension__ is a user account password policy enforcement gem that can be
|
6
|
+
added to a Rails project to enforce password policies. The gem is implemented as an extension to the Rails
|
7
|
+
[devise](https://github.com/plataformatec/devise) authentication solution gem and requires that __devise__ is installed
|
8
|
+
as well.
|
9
|
+
|
10
|
+
## Build Status
|
11
|
+
|
12
|
+
| Service | rails 5.2 |
|
13
|
+
|:-----------|:-----------:|
|
14
|
+
| Circle CI | [![Circle CI](https://circleci.com/gh/ValiMail/devise-secure_password/tree/master.svg?style=shield&circle-token=cd173d5f9d2944a9b14737c2d4339b20b08565cf)]() |
|
15
|
+
|
16
|
+
## Overview
|
17
|
+
|
18
|
+
The __Devise Secure Password Extension__ is composed of the following modules:
|
19
|
+
|
20
|
+
- __password_has_required_content__: require that passwords consist of a specific number (configurable) of letters,
|
21
|
+
numbers, and special characters (symbols)
|
22
|
+
- __password_disallows_frequent_reuse__: prevent the reuse of a number (configurable) of previous passwords when a user
|
23
|
+
changes their password
|
24
|
+
- __password_disallows_frequent_changes__: prevent the user from changing their password more than once within a time
|
25
|
+
duration (configurable)
|
26
|
+
- __password_requires_regular_updates__: require that a user change their password following a time duration
|
27
|
+
(configurable)
|
28
|
+
|
29
|
+
## Compatibility
|
30
|
+
|
31
|
+
The goal of this project is to provide compatibility for officially supported stable releases of [Ruby](https://www.ruby-lang.org/en/downloads/)
|
32
|
+
and [Ruby on Rails](http://guides.rubyonrails.org/maintenance_policy.html). More specifically, the following releases
|
33
|
+
are currently supported by the __Devise Secure Password Extension__:
|
34
|
+
|
35
|
+
- Ruby on Rails: __5.2.Z__, __5.1.Z__ (current and previous stable release)
|
36
|
+
- Ruby: __2.5.1__, __2.4.4__ (current and previous stable release)
|
37
|
+
|
38
|
+
## Installation
|
39
|
+
|
40
|
+
Add this line to your application's Gemfile:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
gem 'devise', '~> 4.2'
|
44
|
+
gem 'devise-secure_password', '~> 1.0.5'
|
45
|
+
```
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
```shell
|
50
|
+
prompt> bundle
|
51
|
+
```
|
52
|
+
|
53
|
+
Or install it yourself as:
|
54
|
+
|
55
|
+
```shell
|
56
|
+
prompt> gem install devise-secure_password
|
57
|
+
```
|
58
|
+
|
59
|
+
Finally, run the generator:
|
60
|
+
|
61
|
+
```shell
|
62
|
+
prompt> rails generate devise:secure_password:install
|
63
|
+
```
|
64
|
+
|
65
|
+
## Usage
|
66
|
+
|
67
|
+
### Configuration
|
68
|
+
|
69
|
+
The __Devise Secure Password Extension__ exposes configuration parameters as outlined below. Commented out configuration
|
70
|
+
parameters reflect the default settings.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
Devise.setup do |config|
|
74
|
+
# ==> Configuration for the Devise Secure Password extension
|
75
|
+
# Module: password_has_required_content
|
76
|
+
#
|
77
|
+
# Configure password content requirements including the number of uppercase,
|
78
|
+
# lowercase, number, and special characters that are required. To configure the
|
79
|
+
# minimum and maximum length refer to the Devise config.password_length
|
80
|
+
# standard configuration parameter.
|
81
|
+
|
82
|
+
# The number of uppercase letters (latin A-Z) required in a password:
|
83
|
+
# config.password_required_uppercase_count = 1
|
84
|
+
|
85
|
+
# The number of lowercase letters (latin A-Z) required in a password:
|
86
|
+
# config.password_required_lowercase_count = 1
|
87
|
+
|
88
|
+
# The number of numbers (0-9) required in a password:
|
89
|
+
# config.password_required_number_count = 1
|
90
|
+
|
91
|
+
# The number of special characters (!@#$%^&*()_+-=[]{}|') required in a password:
|
92
|
+
# config.password_required_special_character_count = 1
|
93
|
+
|
94
|
+
# ==> Configuration for the Devise Secure Password extension
|
95
|
+
# Module: password_disallows_frequent_reuse
|
96
|
+
#
|
97
|
+
# The number of previously used passwords that can not be reused:
|
98
|
+
# config.password_previously_used_count = 8
|
99
|
+
|
100
|
+
# ==> Configuration for the Devise Secure Password extension
|
101
|
+
# Module: password_disallows_frequent_changes
|
102
|
+
# *Requires* password_disallows_frequent_reuse
|
103
|
+
#
|
104
|
+
# The minimum time that must pass between password changes:
|
105
|
+
# config.password_minimum_age = 1.days
|
106
|
+
|
107
|
+
# ==> Configuration for the Devise Secure Password extension
|
108
|
+
# Module: password_requires_regular_updates
|
109
|
+
# *Requires* password_disallows_frequent_reuse
|
110
|
+
#
|
111
|
+
# The maximum allowed age of a password:
|
112
|
+
# config.password_maximum_age = 180.days
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
>NOTE: Password policy defaults have been selected as a middle-of-the-road combination based on published
|
117
|
+
recommendations by [Microsoft](https://technet.microsoft.com/en-us/library/ff741764.aspx) and
|
118
|
+
[Carnegie Mellon University](https://www.cmu.edu/iso/governance/guidelines/password-management.html). It is up to
|
119
|
+
__YOU__ to verify the default settings and make adjustments where necessary.
|
120
|
+
|
121
|
+
Enable the __Devise Secure Password Extension__ enforcement in your Devise model(s):
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
devise :password_has_required_content, :password_disallows_frequent_reuse,
|
125
|
+
:password_disallows_frequent_changes, :password_requires_regular_updates
|
126
|
+
```
|
127
|
+
|
128
|
+
Usually, you would append these after your selection of Devise modules. So your configuration will more likely look like
|
129
|
+
the following:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
class User < ApplicationRecord
|
133
|
+
# Include default devise modules. Others available are:
|
134
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
135
|
+
devise :database_authenticatable, :registerable,
|
136
|
+
:recoverable, :rememberable, :trackable, :validatable,
|
137
|
+
:password_has_required_content, :password_disallows_frequent_reuse,
|
138
|
+
:password_disallows_frequent_changes, :password_requires_regular_updates
|
139
|
+
...
|
140
|
+
<YOUR USER MODEL CONTENT FOLLOWS>
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
>NOTE: Both `:password_disallows_frequent_changes` and `:password_requires_regular_updates` are dependent upon the
|
145
|
+
previous passwords memorization implemented by the `:password_disallows_frequent_reuse` module.
|
146
|
+
|
147
|
+
### Database migration
|
148
|
+
|
149
|
+
The following database migration needs to be applied:
|
150
|
+
|
151
|
+
```shell
|
152
|
+
prompt> rails generate migration create_previous_passwords salt:string encrypted_password:string user:references
|
153
|
+
```
|
154
|
+
|
155
|
+
Edit the resulting file to disallow null values for the hash,add indexes for both hash and user_id fields, and to also
|
156
|
+
add the timestamp (created_at, updated_at) fields:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class CreatePreviousPasswords < ActiveRecord::Migration[5.1]
|
160
|
+
def change
|
161
|
+
create_table :previous_passwords do |t|
|
162
|
+
t.string :salt, null: false
|
163
|
+
t.string :encrypted_password, null: false
|
164
|
+
t.references :user, foreign_key: true
|
165
|
+
|
166
|
+
t.timestamps
|
167
|
+
end
|
168
|
+
|
169
|
+
add_index :previous_passwords, :encrypted_password
|
170
|
+
add_index :previous_passwords, [:user_id, :created_at]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
```
|
175
|
+
|
176
|
+
And then:
|
177
|
+
|
178
|
+
```shell
|
179
|
+
prompt> bundle exec rake db:migrate
|
180
|
+
```
|
181
|
+
|
182
|
+
### Displaying errors
|
183
|
+
|
184
|
+
You will likely want to display errors, produced as a result of secure password enforcement violations, to your users.
|
185
|
+
Errors are available via the `User.errors` array and via the `devise_error_messages!` method. An example usage follows
|
186
|
+
and is taken from the default password `edit.html.erb` page:
|
187
|
+
|
188
|
+
```erb
|
189
|
+
<%= form_for(resource, as: resource_name, url: [resource_name, :password_with_policy], html: { method: :put }) do |f| %>
|
190
|
+
<% if resource.errors.full_messages.count.positive? %>
|
191
|
+
<%= devise_error_messages! %>
|
192
|
+
<% end %>
|
193
|
+
|
194
|
+
<p><%= f.label :current_password, 'Current password' %><br />
|
195
|
+
<%= f.password_field :current_password %></p>
|
196
|
+
|
197
|
+
<p><%= f.label :password, 'New password' %><br />
|
198
|
+
<%= f.password_field :password %></p>
|
199
|
+
|
200
|
+
<p><%= f.label :password_confirmation, 'Password confirmation' %><br />
|
201
|
+
<%= f.password_field :password_confirmation %></p>
|
202
|
+
|
203
|
+
<p><%= f.submit 'Update' %></p>
|
204
|
+
<% end %>
|
205
|
+
```
|
206
|
+
|
207
|
+
<a name="running-tests"></a>
|
208
|
+
|
209
|
+
## Running Tests
|
210
|
+
|
211
|
+
This document assumes that you already have a [functioning ruby install](https://rvm.io/).
|
212
|
+
|
213
|
+
### Default Rails target
|
214
|
+
|
215
|
+
The __Devise Secure Password Extension__ provides compatibility for officially supported stable releases of Ruby on
|
216
|
+
Rails. To configure and test the default target (the most-recent supported Rails release):
|
217
|
+
|
218
|
+
```bash
|
219
|
+
prompt> bundle
|
220
|
+
prompt> bundle exec rake
|
221
|
+
```
|
222
|
+
|
223
|
+
### Selecting an alternate Rails target
|
224
|
+
|
225
|
+
To determine the Ruby on Rails versions supported by this release, run the following commands:
|
226
|
+
|
227
|
+
```bash
|
228
|
+
prompt> gem install flay ruby2ruby rubocop rspec
|
229
|
+
prompt> rake test:spec:targets
|
230
|
+
|
231
|
+
Available Rails targets: 5.1, 5.2
|
232
|
+
```
|
233
|
+
|
234
|
+
Reconfigure the project by specifying the correct Gemfile when running bundler, followed by running tests:
|
235
|
+
|
236
|
+
```bash
|
237
|
+
prompt> BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle
|
238
|
+
prompt> BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake
|
239
|
+
```
|
240
|
+
|
241
|
+
The only time you need to define the `BUNDLE_GEMFILE` environment variable is when testing a non-default target.
|
242
|
+
|
243
|
+
### Testing with code coverage (SimpleCov)
|
244
|
+
|
245
|
+
SimpleCov tests are enabled by defining the `test:spec:coverage` rake task:
|
246
|
+
|
247
|
+
```bash
|
248
|
+
prompt> bundle exec rake test:spec:coverage
|
249
|
+
```
|
250
|
+
|
251
|
+
A brief summary will be output at the end of the run but a more extensive eport will be saved in the `coverage`
|
252
|
+
directory (under the top-level project directory).
|
253
|
+
|
254
|
+
### Testing with headless Chrome
|
255
|
+
|
256
|
+
You will need to install the [ChromeDriver >= v2.3.4](https://sites.google.com/a/chromium.org/chromedriver/downloads)
|
257
|
+
for testing.
|
258
|
+
|
259
|
+
```bash
|
260
|
+
prompt> brew install chromedriver
|
261
|
+
```
|
262
|
+
|
263
|
+
>NOTE: __ChromeDriver__ < 2.33 has a bug for testing clickable targets; therefore, install >= 2.3.4.
|
264
|
+
|
265
|
+
You can always install [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) by downloading and then
|
266
|
+
unpacking into the `/usr/local/bin` directory.
|
267
|
+
|
268
|
+
#### Automated screenshots on failure
|
269
|
+
|
270
|
+
The [capybara-screenshot gem](https://github.com/mattheworiordan/capybara-screenshot) supports automated screenshot
|
271
|
+
captures on failing tests but this will only take place for tests that have JavaScript enabled. You can temporarily
|
272
|
+
modify an example by setting `js: true` as in the following example:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
context 'when minimum age enforcement is enabled', js: true do
|
276
|
+
...
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
Do not submit pull requests with this setting enabled where it wasn't enabled previously.
|
281
|
+
|
282
|
+
### Testing inside the spec/rails-app-X_y_z
|
283
|
+
|
284
|
+
To debug from inside of the dummy rails-app you will need to first install the rails bin stubs and then perform a db
|
285
|
+
migration:
|
286
|
+
|
287
|
+
```bash
|
288
|
+
prompt> cd spec/rails-app-X_y_z
|
289
|
+
prompt> rake app:update:bin
|
290
|
+
prompt> RAILS_ENV=development bundle exec rake db:migrate
|
291
|
+
```
|
292
|
+
|
293
|
+
Remember, the dummy app is not meant to be a full featured rails app: there is just enough functionality to test the
|
294
|
+
gem feature set.
|
295
|
+
|
296
|
+
### Running benchmarks
|
297
|
+
|
298
|
+
Available benchmarks can be run as follows:
|
299
|
+
|
300
|
+
```bash
|
301
|
+
prompt> bundle exec rake test:benchmark
|
302
|
+
```
|
303
|
+
|
304
|
+
Benchmarks are run within an RSpec context but are not run along with other tests as benchmarks merely seek to measure
|
305
|
+
performance and not enforce set performance targets.
|
306
|
+
|
307
|
+
### Screenshots
|
308
|
+
|
309
|
+
Failing tests that invoke the JavaScript driver will result in both the failing html along with a screenshot of the
|
310
|
+
page output to be saved in the `spec/rails-app-X_y_z/tmp/capybara` snapshot directory.
|
311
|
+
|
312
|
+
>NOTE: On __circleci__ the snapshots will be captured as artifacts.
|
313
|
+
|
314
|
+
The snapshot directory will be pruned automatically between runs.
|
315
|
+
|
316
|
+
## Docker
|
317
|
+
|
318
|
+
This repository includes a [Dockerfile](https://docs.docker.com/engine/reference/builder/) to facilitate testing in and
|
319
|
+
using [Docker](https://www.docker.com/).
|
320
|
+
|
321
|
+
To start the container simply build and launch the image:
|
322
|
+
|
323
|
+
```bash
|
324
|
+
prompt> docker build -t secure-password-dev .
|
325
|
+
prompt> docker run -it --rm secure-password-dev /bin/bash
|
326
|
+
```
|
327
|
+
|
328
|
+
The above `docker run` command will start the container, connect you to the command line within the project home
|
329
|
+
directory where you can issue the tests as documented in the [Running Tests](#running-tests) section above. When you exit
|
330
|
+
the shell, the container will be removed.
|
331
|
+
|
332
|
+
### Running tests in a Docker container
|
333
|
+
|
334
|
+
The Docker container is derived from the latest [circleci/ruby](https://hub.docker.com/r/circleci/ruby/) image. It is
|
335
|
+
critical that you update the bundler inside of the Docker image as the `circleci` user (i.e. the default user) before
|
336
|
+
initiating any development work including tests.
|
337
|
+
|
338
|
+
```bash
|
339
|
+
prompt> gem update bundler
|
340
|
+
```
|
341
|
+
|
342
|
+
#### Updating test.sqlite3.db
|
343
|
+
|
344
|
+
To update or generate a `db/test/sqlite3.db` database file:
|
345
|
+
|
346
|
+
```bash
|
347
|
+
prompt> cd spec/rails-app-X_y_z
|
348
|
+
prompt> bundle install
|
349
|
+
prompt> rake app:update:bin
|
350
|
+
prompt> RAILS_ENV=test bundle exec rake db:migrate
|
351
|
+
```
|
352
|
+
|
353
|
+
## Contributing
|
354
|
+
|
355
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/valimail/devise-secure_password. This project
|
356
|
+
is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the
|
357
|
+
[Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
358
|
+
|
359
|
+
### Basic guidelines for contributors
|
360
|
+
|
361
|
+
1 Fork it
|
362
|
+
|
363
|
+
2 Create your feature branch (`git checkout -b my-new-feature`)
|
364
|
+
|
365
|
+
3 Commit your changes (`git commit -am 'Add some feature'`)
|
366
|
+
|
367
|
+
4 Push to the branch (`git push origin my-new-feature`)
|
368
|
+
|
369
|
+
5 Create new Pull Request
|
370
|
+
|
371
|
+
>NOTE: Contributions should always be based on the `master` branch. You may be asked to [rebase](https://git-scm.com/docs/git-rebase)
|
372
|
+
your contributions on the tip of the `master` branch, this is normal and is to be expected if the `master` branch has
|
373
|
+
moved ahead since your pull request was opened, discussed, and accepted.
|
374
|
+
|
375
|
+
## License
|
376
|
+
|
377
|
+
The __Devise Secure Password Extension__ gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
378
|
+
|
379
|
+
## Code of Conduct
|
380
|
+
|
381
|
+
Everyone interacting in the __Devise Secure Password Extension__ project’s codebases and issue trackers is expected to
|
382
|
+
follow the [code of conduct](https://github.com/valimail/devise-secure_password/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Devise
|
2
|
+
class PasswordsWithPolicyController < Devise::RegistrationsController
|
3
|
+
before_action :configure_permitted_parameters
|
4
|
+
|
5
|
+
def edit
|
6
|
+
self.resource = resource_class.new
|
7
|
+
resource.errors.add(:base, "#{error_string_for_password_expired}.")
|
8
|
+
render :edit
|
9
|
+
end
|
10
|
+
|
11
|
+
def update
|
12
|
+
if update_resource(resource, account_update_params)
|
13
|
+
prepare_for_redirect
|
14
|
+
redirect_to stored_location_for(scope_name) || :root
|
15
|
+
else
|
16
|
+
render :edit
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def devise_parameter_sanitizer
|
21
|
+
@devise_parameter_sanitizer ||= Devise::ParameterSanitizer.new(resource_class, resource_name, params)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def account_update_params
|
27
|
+
devise_parameter_sanitizer.sanitize(:account_update)
|
28
|
+
end
|
29
|
+
|
30
|
+
def authenticate_scope!
|
31
|
+
send(:"authenticate_#{scope_name}!")
|
32
|
+
self.resource = send("current_#{scope_name}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def alert_string_for_password_updated
|
36
|
+
I18n.t('secure_password.password_requires_regular_updates.alerts.messages.password_updated')
|
37
|
+
end
|
38
|
+
|
39
|
+
def configure_permitted_parameters
|
40
|
+
devise_parameter_sanitizer.permit(:account_update, keys: [:update_action])
|
41
|
+
end
|
42
|
+
|
43
|
+
def error_string_for_password_expired
|
44
|
+
return 'password expired' unless warden.user.class.respond_to?(:password_maximum_age)
|
45
|
+
|
46
|
+
I18n.t(
|
47
|
+
'secure_password.password_requires_regular_updates.errors.messages.password_expired',
|
48
|
+
timeframe: precise_distance_of_time_in_words(warden.user.class.password_maximum_age)
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def prepare_for_redirect
|
53
|
+
unset_devise_secure_password_expired!
|
54
|
+
flash[:notice] = alert_string_for_password_updated
|
55
|
+
bypass_sign_in resource, scope: scope_name
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_resource(resource, params)
|
59
|
+
update_action = (params[:update_action] ? params.delete(:update_action) : nil)
|
60
|
+
return false unless update_action == 'change_password'
|
61
|
+
|
62
|
+
update_password(resource, params)
|
63
|
+
|
64
|
+
# do what devise would do under normal circumstances but also be aware of
|
65
|
+
# secure_password or other validators that would be ignored by devise.
|
66
|
+
result = if resource.errors.count.zero?
|
67
|
+
resource.update(params)
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
resource.clean_up_passwords
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def update_password(resource, params)
|
77
|
+
#
|
78
|
+
# order of operations that follow is absolutely critical
|
79
|
+
#
|
80
|
+
current_password = params.delete(:current_password)
|
81
|
+
current_password_valid = resource.valid_password?(current_password)
|
82
|
+
|
83
|
+
# let our installed validator chain handle the validation work
|
84
|
+
resource.assign_attributes(params)
|
85
|
+
resource.valid?
|
86
|
+
unless current_password_valid
|
87
|
+
resource.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
88
|
+
end
|
89
|
+
|
90
|
+
resource
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|