devise-pwned_password 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +89 -61
- data/lib/devise/pwned_password/model.rb +15 -4
- data/lib/devise/pwned_password/version.rb +1 -1
- metadata +36 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 366fc1a14fb5abd102a74ce7a814219815c3ab764ae7c2d3c14296fb72679f76
|
4
|
+
data.tar.gz: 682e24df4e1a6cbf674c58c34cac5a16f4a233d351f52f7400aa8f35a83e7f72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89f437434e88bc07874002f0baed66f210a15e4a7b9fa3d4377d4c9005c63d3b5a9f5476bf8ccb63ced1d34e81c1f8d3ab7d9f2137d332e6d3557fe4dad53456
|
7
|
+
data.tar.gz: de00ba890a8edad1bdac2281332f72570521794616666bd0efa1b50d0f138dbec1d852ba8de1639822caf7a8743130efe5318a8c94db57a2b48d97fac75e95aa
|
data/README.md
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
# Devise::PwnedPassword
|
2
|
-
Devise extension that checks user passwords against the PwnedPasswords dataset https://haveibeenpwned.com/Passwords
|
2
|
+
Devise extension that checks user passwords against the PwnedPasswords dataset (https://haveibeenpwned.com/Passwords).
|
3
3
|
|
4
|
-
|
4
|
+
Checks for compromised ("pwned") passwords in 2 different places/ways:
|
5
|
+
1. As a standard model validation using [pwned](https://github.com/philnash/pwned). This:
|
6
|
+
- prevents new users from being created (signing up) with a compromised password
|
7
|
+
- prevents existing users from changing their password to a password that is known to be compromised
|
8
|
+
2. (Optionally) Whenever a user signs in, checks if their current password is compromised and shows a warning if it is.
|
5
9
|
|
6
|
-
https://github.com/HCLarsen/devise-uncommon_password
|
10
|
+
Based on [devise-uncommon_password](https://github.com/HCLarsen/devise-uncommon_password).
|
7
11
|
|
8
|
-
Recently the HaveIBeenPwned API has moved to
|
12
|
+
Recently the HaveIBeenPwned API has moved to an [authenticated/paid model](https://www.troyhunt.com/authentication-and-the-have-i-been-pwned-api/), but this does not affect the PwnedPasswords API; no payment or authentication is required.
|
9
13
|
|
10
14
|
|
11
15
|
## Usage
|
12
|
-
Add the
|
16
|
+
Add the `:pwned_password` module to your existing Devise model.
|
13
17
|
|
14
18
|
```ruby
|
15
19
|
class AdminUser < ApplicationRecord
|
16
|
-
devise :database_authenticatable,
|
20
|
+
devise :database_authenticatable,
|
17
21
|
:recoverable, :rememberable, :trackable, :validatable, :pwned_password
|
18
22
|
end
|
19
23
|
```
|
@@ -25,6 +29,8 @@ PwnedPasswords dataset:
|
|
25
29
|
Password has previously appeared in a data breach and should never be used. Please choose something harder to guess.
|
26
30
|
```
|
27
31
|
|
32
|
+
## Configuration
|
33
|
+
|
28
34
|
You can customize this error message by modifying the `devise` YAML file.
|
29
35
|
|
30
36
|
```yml
|
@@ -35,13 +41,71 @@ en:
|
|
35
41
|
pwned_password: "has previously appeared in a data breach and should never be used. If you've ever used it anywhere before, change it immediately!"
|
36
42
|
```
|
37
43
|
|
38
|
-
|
44
|
+
By default passwords are rejected if they appear at all in the data set.
|
45
|
+
Optionally, you can add the following snippet to `config/initializers/devise.rb`
|
46
|
+
if you want the error message to be displayed only when the password is present
|
47
|
+
a certain number of times in the data set:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# Minimum number of times a pwned password must exist in the data set in order
|
51
|
+
# to be reject.
|
52
|
+
config.min_password_matches = 10
|
53
|
+
```
|
54
|
+
|
55
|
+
By default responses from the PwnedPasswords API are timed out after 5 seconds
|
56
|
+
to reduce potential latency problems.
|
57
|
+
Optionally, you can add the following snippet to `config/initializers/devise.rb`
|
58
|
+
to control the timeout settings:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
config.pwned_password_open_timeout = 1
|
62
|
+
config.pwned_password_read_timeout = 2
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
### How to warn existing users when they sign in
|
67
|
+
|
68
|
+
You can optionally warn existing users when they sign in if they are using a password from the PwnedPasswords dataset.
|
69
|
+
|
70
|
+
To enable this, you _must_ override `after_sign_in_path_for`, like this:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# app/controllers/application_controller.rb
|
74
|
+
|
75
|
+
def after_sign_in_path_for(resource)
|
76
|
+
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
77
|
+
super
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
For an [Active Admin](https://github.com/activeadmin/activeadmin) application the following monkey patch is needed:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# config/initializers/active_admin_devise_sessions_controller.rb
|
85
|
+
class ActiveAdmin::Devise::SessionsController
|
86
|
+
def after_sign_in_path_for(resource)
|
87
|
+
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
To prevent the default call to the HaveIBeenPwned API on user sign-in (only
|
94
|
+
really useful if you're going to check `pwned?` after sign-in as used above),
|
95
|
+
add the following to `config/initializers/devise.rb`:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
config.pwned_password_check_on_sign_in = false
|
99
|
+
```
|
100
|
+
|
101
|
+
#### Customize warning message
|
39
102
|
|
103
|
+
The default message is:
|
40
104
|
```
|
41
105
|
Your password has previously appeared in a data breach and should never be used. We strongly recommend you change your password.
|
42
106
|
```
|
43
107
|
|
44
|
-
You can customize this message by modifying the `devise`
|
108
|
+
You can customize this message by modifying the `devise.en.yml` locale file.
|
45
109
|
|
46
110
|
```yml
|
47
111
|
# config/locales/devise.en.yml
|
@@ -51,22 +115,15 @@ en:
|
|
51
115
|
warn_pwned: "Your password has previously appeared in a data breach and should never be used. We strongly recommend you change your password everywhere you have used it."
|
52
116
|
```
|
53
117
|
|
54
|
-
|
55
|
-
Optionally, you can add the following snippet to `config/initializers/devise.rb`
|
56
|
-
if you want the error message to be displayed only when the password is present
|
57
|
-
a certain number of times in the data set:
|
118
|
+
#### Customize the warning threshold
|
58
119
|
|
59
|
-
|
60
|
-
# Minimum number of times a pwned password must exist in the data set in order
|
61
|
-
# to be reject.
|
62
|
-
config.min_password_matches = 10
|
63
|
-
```
|
120
|
+
By default the same value, `config.min_password_matches` is used as the threshold for rejecting a passwords for _new_ user sign-ups and for warning existing users.
|
64
121
|
|
65
|
-
|
66
|
-
Optionally, you can add the following snippet to `config/initializers/devise.rb`
|
67
|
-
if you want to use different thresholds for rejecting the password and warning
|
122
|
+
If you want to use different thresholds for rejecting the password and warning
|
68
123
|
the user (for example you may only want to reject passwords that are common but
|
69
|
-
warn if the password occurs at all in the list)
|
124
|
+
warn if the password occurs at all in the list), you can set a different value for each.
|
125
|
+
|
126
|
+
To change the threshold used for the warning _only_, add to `config/initializers/devise.rb`
|
70
127
|
|
71
128
|
```ruby
|
72
129
|
# Minimum number of times a pwned password must exist in the data set in order
|
@@ -74,15 +131,11 @@ warn if the password occurs at all in the list):
|
|
74
131
|
config.min_password_matches_warn = 1
|
75
132
|
```
|
76
133
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
```ruby
|
83
|
-
config.pwned_password_open_timeout = 1
|
84
|
-
config.pwned_password_read_timeout = 2
|
85
|
-
```
|
134
|
+
Note: If you do have a different warning threshold, that threshold will also be used
|
135
|
+
when a user changes their password (added as an _error_!) so that they don't
|
136
|
+
continue to be warned if they choose another password that is in the pwned list
|
137
|
+
but occurs with a frequency below the main threshold that is used for *new*
|
138
|
+
user registrations (`config.min_password_matches`).
|
86
139
|
|
87
140
|
### Disabling in test environments
|
88
141
|
|
@@ -107,32 +160,6 @@ And then execute:
|
|
107
160
|
$ bundle install
|
108
161
|
```
|
109
162
|
|
110
|
-
Optionally, if you also want to warn existing users when they sign in, override `after_sign_in_path_for`
|
111
|
-
```ruby
|
112
|
-
def after_sign_in_path_for(resource)
|
113
|
-
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
114
|
-
super
|
115
|
-
end
|
116
|
-
```
|
117
|
-
|
118
|
-
This should generally be added in ```app/controllers/application_controller.rb``` for a rails app. For an Active Admin application the following monkey patch is needed.
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
# config/initializers/active_admin_devise_sessions_controller.rb
|
122
|
-
class ActiveAdmin::Devise::SessionsController
|
123
|
-
def after_sign_in_path_for(resource)
|
124
|
-
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
125
|
-
super
|
126
|
-
end
|
127
|
-
end
|
128
|
-
```
|
129
|
-
|
130
|
-
To prevent the default call to the HaveIBeenPwned API on user sign in, add the following to `config/initializers/devise.rb`:
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
config.pwned_password_check_on_sign_in = false
|
134
|
-
```
|
135
|
-
|
136
163
|
## Considerations
|
137
164
|
|
138
165
|
A few things to consider/understand when using this gem:
|
@@ -144,18 +171,19 @@ A few things to consider/understand when using this gem:
|
|
144
171
|
to a third party. More implementation details and important caveats can be
|
145
172
|
found in https://blog.cloudflare.com/validating-leaked-passwords-with-k-anonymity/
|
146
173
|
|
147
|
-
* This puts an external API in the request path of users signing up to your
|
148
|
-
|
149
|
-
|
174
|
+
* This puts an external API in the request path of users signing up to your application. This could
|
175
|
+
potentially add some latency to this operation. The gem is designed to silently swallows errors if
|
176
|
+
the PwnedPasswords service is unavailable, allowing users to use compromised passwords during the
|
177
|
+
time when it is unavailable.
|
150
178
|
|
151
179
|
## Contributing
|
152
180
|
|
153
|
-
To contribute
|
181
|
+
To contribute:
|
154
182
|
|
155
183
|
* Check the [issue tracker](https://github.com/michaelbanfield/devise-pwned_password/issues) and [pull requests](https://github.com/michaelbanfield/devise-pwned_password/pulls) for anything similar
|
156
184
|
* Fork the repository
|
157
185
|
* Make your changes
|
158
|
-
* Run bin/test to make sure the unit tests still run
|
186
|
+
* Run `bin/test` to make sure the unit tests still run
|
159
187
|
* Send a pull request
|
160
188
|
|
161
189
|
## License
|
@@ -14,7 +14,8 @@ module Devise
|
|
14
14
|
extend ActiveSupport::Concern
|
15
15
|
|
16
16
|
included do
|
17
|
-
validate :not_pwned_password,
|
17
|
+
validate :not_pwned_password,
|
18
|
+
if: Devise.activerecord51? ? :will_save_change_to_encrypted_password? : :encrypted_password_changed?
|
18
19
|
end
|
19
20
|
|
20
21
|
module ClassMethods
|
@@ -46,9 +47,20 @@ module Devise
|
|
46
47
|
pwned_password = Pwned::Password.new(password.to_s, options)
|
47
48
|
begin
|
48
49
|
@pwned_count = pwned_password.pwned_count
|
49
|
-
@pwned = @pwned_count >= (
|
50
|
+
@pwned = @pwned_count >= (
|
51
|
+
if persisted?
|
52
|
+
# If you do have a different warning threshold, that threshold will also be used
|
53
|
+
# when a user changes their password so that they don't continue to be warned if they
|
54
|
+
# choose another password that is in the pwned list but occurs with a frequency below
|
55
|
+
# the main threshold that is used for *new* user registrations.
|
56
|
+
self.class.min_password_matches_warn || self.class.min_password_matches
|
57
|
+
else
|
58
|
+
self.class.min_password_matches
|
59
|
+
end
|
60
|
+
)
|
50
61
|
return @pwned
|
51
62
|
rescue Pwned::Error
|
63
|
+
# This deliberately silently swallows errors and returns false (valid) if there was an error. Most apps won't want to tie the ability to sign up users to the availability of a third-party API.
|
52
64
|
return false
|
53
65
|
end
|
54
66
|
|
@@ -58,9 +70,8 @@ module Devise
|
|
58
70
|
private
|
59
71
|
|
60
72
|
def not_pwned_password
|
61
|
-
# This deliberately fails silently on 500's etc. Most apps wont want to tie the ability to sign up customers to the availability of a third party API
|
62
73
|
if password_pwned?(password)
|
63
|
-
errors.add(:password, :pwned_password)
|
74
|
+
errors.add(:password, :pwned_password, count: @pwned_count)
|
64
75
|
end
|
65
76
|
end
|
66
77
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-pwned_password
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Banfield
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -39,21 +39,21 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: byebug
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: capybara
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 5.1.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.1.2
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rubocop
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,20 @@ dependencies:
|
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: 0.52.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sqlite3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: Devise extension that checks user passwords against the PwnedPasswords
|
84
112
|
dataset https://haveibeenpwned.com/Passwords.
|
85
113
|
email:
|