devise_password_history 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +7 -1
- data/README.md +25 -0
- data/devise_password_history.gemspec +1 -1
- data/lib/devise_password_history/controllers/helpers.rb +41 -0
- data/lib/devise_password_history/generators/install_generator.rb +2 -0
- data/lib/devise_password_history/models/password_history.rb +27 -1
- data/lib/devise_password_history/rails.rb +7 -0
- data/lib/devise_password_history/version.rb +1 -1
- data/lib/devise_password_history.rb +12 -2
- data/test/test_helper.rb +9 -0
- metadata +10 -7
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -30,6 +30,7 @@ That generator will do three things:
|
|
|
30
30
|
1. Modifies the `config/initializers/devise.rb` file with two new config options:
|
|
31
31
|
- `config.deny_old_passwords`: turns the validations on/off
|
|
32
32
|
- `config.password_history_count`: the threshold of how many passwords to store
|
|
33
|
+
- `config.password_age`: ability to force password expiration (ex: `90.days`)
|
|
33
34
|
2. Creates an `OldPassword` polymorphic model in `app/models`
|
|
34
35
|
3. Creates the migration for the `old_passwords` table
|
|
35
36
|
|
|
@@ -44,6 +45,30 @@ any of the other extensions:
|
|
|
44
45
|
devise :database_authenticatable, :password_history
|
|
45
46
|
end
|
|
46
47
|
|
|
48
|
+
## Notes on Password Age/Expiration
|
|
49
|
+
|
|
50
|
+
By default, the `password_age` is set to `nil` (which turns this feature off).
|
|
51
|
+
If you want to use it, set it to how often you want passwords to expire, an
|
|
52
|
+
example might be `90.days`.
|
|
53
|
+
|
|
54
|
+
If a password has expired, the user will be redirected to a
|
|
55
|
+
`update_password_path` route, which defaults to `edit_admin_user_path(current_user)`.
|
|
56
|
+
You can override this in `ApplicationController` as needed.
|
|
57
|
+
|
|
58
|
+
class ApplicationController
|
|
59
|
+
# ...
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
def update_password_path
|
|
63
|
+
your_custom_route_goes_here_path
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Additionally, the filter that runs to check expired passwords is
|
|
68
|
+
`check_password_expiration`. To prevent this filter from running on the
|
|
69
|
+
controller that does the password updates, you should
|
|
70
|
+
`skip_before_filter :check_password_expiration`.
|
|
71
|
+
|
|
47
72
|
## Contributing
|
|
48
73
|
|
|
49
74
|
1. Fork it
|
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
|
10
10
|
gem.email = ["ryan@rpheath.com"]
|
|
11
11
|
gem.description = %q{Maintains password history and ensures old passwords aren't reused}
|
|
12
12
|
gem.summary = %q{Password history support for devise}
|
|
13
|
-
gem.homepage = ""
|
|
13
|
+
gem.homepage = "http://github.com/rpheath/devise_password_history"
|
|
14
14
|
|
|
15
15
|
gem.add_dependency("devise", ["~> 2.2.0"])
|
|
16
16
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module DevisePasswordHistory
|
|
2
|
+
module Controllers
|
|
3
|
+
module Helpers
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
append_before_filter :check_password_expiration
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
def check_password_expiration
|
|
12
|
+
# skip if we don't have a user
|
|
13
|
+
return if current_user.blank?
|
|
14
|
+
# skip if we're on the controller that needs
|
|
15
|
+
# to update the passwords (infinite loop otherwise)
|
|
16
|
+
return if self.class.to_s == update_password_controller.to_s
|
|
17
|
+
|
|
18
|
+
if current_user.has_password_expired?
|
|
19
|
+
flash[:alert] = expired_password_message
|
|
20
|
+
redirect_to update_password_path
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# path to update passwords (can be overridden)
|
|
25
|
+
def update_password_path
|
|
26
|
+
edit_admin_user_path(current_user)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# the controller that handles password
|
|
30
|
+
# updating (can be overridden)
|
|
31
|
+
def update_password_controller
|
|
32
|
+
"Admin::UsersController"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# flash message
|
|
36
|
+
def expired_password_message
|
|
37
|
+
"Your password has expired, please choose a new one"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -20,6 +20,8 @@ module DevisePasswordHistory
|
|
|
20
20
|
" config.password_history_count = 8\n\n" +
|
|
21
21
|
" # Toggles behavior for Deny/Allow old passwords\n" +
|
|
22
22
|
" config.deny_old_passwords = true\n\n" +
|
|
23
|
+
" # Repeatedly forces a new password based on this age\n" +
|
|
24
|
+
" # config.password_age = 90.days\n\n" +
|
|
23
25
|
"", :before => /end[\s|\n|]+\Z/
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -6,7 +6,7 @@ module Devise
|
|
|
6
6
|
extend ActiveSupport::Concern
|
|
7
7
|
|
|
8
8
|
module ClassMethods
|
|
9
|
-
Devise::Models.config(self, :password_history_count, :deny_old_passwords)
|
|
9
|
+
Devise::Models.config(self, :password_history_count, :deny_old_passwords, :password_age)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
included do
|
|
@@ -45,6 +45,32 @@ module Devise
|
|
|
45
45
|
false
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def has_password_expired?
|
|
49
|
+
# make sure this feature is turned on
|
|
50
|
+
return false if self.class.password_age.nil?
|
|
51
|
+
|
|
52
|
+
# initializing to ensure expired_stamp
|
|
53
|
+
# exists in case conditions fail below
|
|
54
|
+
expired_stamp = Time.now
|
|
55
|
+
|
|
56
|
+
if self.old_passwords.present?
|
|
57
|
+
# since we are tracking old passwords, we can get the
|
|
58
|
+
# last time the password was changed
|
|
59
|
+
password_changed_at = self.old_passwords.order(:created_at).last.created_at
|
|
60
|
+
# our expired stamp is the password age past the last password change
|
|
61
|
+
expired_stamp = password_changed_at + self.class.password_age
|
|
62
|
+
else
|
|
63
|
+
# if no old passwords exist yet, we can check against
|
|
64
|
+
# when the user was created and use that timestamp
|
|
65
|
+
if self.respond_to?(:created_at)
|
|
66
|
+
expired_stamp = self.created_at + self.class.password_age
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# are we expired?
|
|
71
|
+
!!(Time.now > expired_stamp)
|
|
72
|
+
end
|
|
73
|
+
|
|
48
74
|
protected
|
|
49
75
|
# make sure this is turned on in the Devise config
|
|
50
76
|
def should_deny_old_passwords?
|
|
@@ -14,9 +14,19 @@ module Devise
|
|
|
14
14
|
# Toggles the behavior of denying/allowing old passwords
|
|
15
15
|
mattr_accessor :deny_old_passwords
|
|
16
16
|
@@deny_old_passwords = true
|
|
17
|
+
|
|
18
|
+
# Repeatedly forces a new password based on this age
|
|
19
|
+
mattr_accessor :password_age
|
|
20
|
+
@@password_age = nil
|
|
17
21
|
end
|
|
18
22
|
|
|
19
|
-
module DevisePasswordHistory
|
|
23
|
+
module DevisePasswordHistory
|
|
24
|
+
module Controllers
|
|
25
|
+
autoload :Helpers, "devise_password_history/controllers/helpers"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
20
28
|
|
|
21
29
|
# makes this module available to the `devise` command
|
|
22
|
-
Devise.add_module :password_history, :model => "devise_password_history/models/password_history"
|
|
30
|
+
Devise.add_module :password_history, :model => "devise_password_history/models/password_history"
|
|
31
|
+
|
|
32
|
+
require "devise_password_history/rails"
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devise_password_history
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 23
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
- 1
|
|
9
8
|
- 2
|
|
10
|
-
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.2.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Ryan Heath
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2014-01-
|
|
18
|
+
date: 2014-01-25 00:00:00 -05:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -51,13 +51,16 @@ files:
|
|
|
51
51
|
- Rakefile
|
|
52
52
|
- devise_password_history.gemspec
|
|
53
53
|
- lib/devise_password_history.rb
|
|
54
|
+
- lib/devise_password_history/controllers/helpers.rb
|
|
54
55
|
- lib/devise_password_history/generators/install_generator.rb
|
|
55
56
|
- lib/devise_password_history/generators/templates/migrations/create_old_passwords.rb
|
|
56
57
|
- lib/devise_password_history/generators/templates/models/old_password.rb
|
|
57
58
|
- lib/devise_password_history/models/password_history.rb
|
|
59
|
+
- lib/devise_password_history/rails.rb
|
|
58
60
|
- lib/devise_password_history/version.rb
|
|
61
|
+
- test/test_helper.rb
|
|
59
62
|
has_rdoc: true
|
|
60
|
-
homepage:
|
|
63
|
+
homepage: http://github.com/rpheath/devise_password_history
|
|
61
64
|
licenses: []
|
|
62
65
|
|
|
63
66
|
post_install_message:
|
|
@@ -90,5 +93,5 @@ rubygems_version: 1.6.2
|
|
|
90
93
|
signing_key:
|
|
91
94
|
specification_version: 3
|
|
92
95
|
summary: Password history support for devise
|
|
93
|
-
test_files:
|
|
94
|
-
|
|
96
|
+
test_files:
|
|
97
|
+
- test/test_helper.rb
|