devise_password_expirable 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +6 -0
- data/README.md +3 -0
- data/Rakefile +1 -0
- data/app/controllers/devise/password_expired_controller.rb +38 -0
- data/app/views/devise/password_expired/show.html.erb +16 -0
- data/config/locales/en.yml +9 -0
- data/devise_password_expirable.gemspec +26 -0
- data/lib/devise_password_expirable.rb +32 -0
- data/lib/devise_password_expirable/controllers/helpers.rb +50 -0
- data/lib/devise_password_expirable/hooks/password_expirable.rb +5 -0
- data/lib/devise_password_expirable/models/password_expirable.rb +57 -0
- data/lib/devise_password_expirable/rails.rb +7 -0
- data/lib/devise_password_expirable/routes.rb +13 -0
- data/lib/devise_password_expirable/schema.rb +24 -0
- data/lib/devise_password_expirable/version.rb +3 -0
- data/lib/generators/devise_expire_passwords/install_generator.rb +23 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
data.tar.gz: 580d34c38ff0183b3a09f42988a1c77441df2945
|
4
|
+
metadata.gz: 55c8b247f7f7a72167a97d4d5320bbc86d05271d
|
5
|
+
SHA512:
|
6
|
+
data.tar.gz: 37da798f6da4020241ad192e3d1c0f7bb644dfcc6b63e8167b345c31dccb32627221dadbaf515e0240a6fafa79a7de50a7c4ce93d3462f369838b6ad4c59f0e7
|
7
|
+
metadata.gz: aade38df02cfb36229bb7c4993786e1e6fdfe9cc4b73f88bb517bd103551515e0d222e102003eeb485a0ffff31a412750380f0d7001a93a51bd89b4474c18e24
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Devise::PasswordExpiredController < DeviseController
|
2
|
+
skip_before_filter :handle_password_change
|
3
|
+
prepend_before_filter :authenticate_scope!, :only => [:show, :update]
|
4
|
+
|
5
|
+
def show
|
6
|
+
if not resource.nil? and resource.need_change_password?
|
7
|
+
respond_with(resource)
|
8
|
+
else
|
9
|
+
redirect_to :root
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
14
|
+
if resource.update_with_password(resource_params)
|
15
|
+
warden.session(scope)[:password_expired] = false
|
16
|
+
set_flash_message :notice, :updated
|
17
|
+
sign_in scope, resource, :bypass => true
|
18
|
+
redirect_to stored_location_for(scope) || :root
|
19
|
+
else
|
20
|
+
clean_up_passwords(resource)
|
21
|
+
respond_with(resource, action: :show)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def resource_params
|
27
|
+
params.require(resource_name).permit!
|
28
|
+
end
|
29
|
+
|
30
|
+
def scope
|
31
|
+
resource_name.to_sym
|
32
|
+
end
|
33
|
+
|
34
|
+
def authenticate_scope!
|
35
|
+
send(:"authenticate_#{resource_name}!")
|
36
|
+
self.resource = send("current_#{resource_name}")
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h2>Renew your password</h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, :as => resource_name, :url => [resource_name, :password_expired], :html => { :method => :put }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<p><%= f.label :current_password, "Current password" %><br />
|
7
|
+
<%= f.password_field :current_password %></p>
|
8
|
+
|
9
|
+
<p><%= f.label :password, "New password" %><br />
|
10
|
+
<%= f.password_field :password %></p>
|
11
|
+
|
12
|
+
<p><%= f.label :password_confirmation, "Confirm new password" %><br />
|
13
|
+
<%= f.password_field :password_confirmation %></p>
|
14
|
+
|
15
|
+
<p><%= f.submit "Change my password" %></p>
|
16
|
+
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
equal_to_current_password: "must be different to the current password!"
|
5
|
+
password_format: "must contain at least 1 uppercase letter, 1 lowercase letter, and a number."
|
6
|
+
devise:
|
7
|
+
password_expired:
|
8
|
+
updated: "Your new password is saved."
|
9
|
+
change_required: "Your password is expired. Please renew your password!"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "devise_password_expirable/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "devise_password_expirable"
|
7
|
+
s.version = DevisePasswordExpirable::VERSION.dup
|
8
|
+
s.authors = ["Jenni Kissinger"]
|
9
|
+
s.email = ["jkissinger@carekinesis.com"]
|
10
|
+
s.homepage = "https://github.com/jenjaina/devise_password_expirable"
|
11
|
+
s.licenses = ["MIT"]
|
12
|
+
s.summary = %q{Expire passwords plugin for devise}
|
13
|
+
s.description = "An extension to devise that will expire user passwords after a set amount of time and prompt them to update their password."
|
14
|
+
|
15
|
+
# s.rubyforge_project = "devise_password_expirable"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'rails', '3.0.20'
|
23
|
+
s.add_runtime_dependency 'devise', '1.1.3'
|
24
|
+
|
25
|
+
s.add_development_dependency 'bundler'
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'devise_password_expirable/version'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_support/core_ext/integer'
|
4
|
+
require 'active_support/ordered_hash'
|
5
|
+
require 'active_support/concern'
|
6
|
+
require 'devise'
|
7
|
+
|
8
|
+
module Devise
|
9
|
+
# Should the password expire (e.g 3.months)
|
10
|
+
mattr_accessor :expire_password_after
|
11
|
+
@@expire_password_after = 3.months
|
12
|
+
|
13
|
+
# Validate password for strongness
|
14
|
+
mattr_accessor :password_regex
|
15
|
+
@@password_regex = /^\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*$/
|
16
|
+
end
|
17
|
+
|
18
|
+
# an security extension for devise
|
19
|
+
module DevisePasswordExpirable
|
20
|
+
autoload :Schema, 'devise_password_expirable/schema'
|
21
|
+
|
22
|
+
module Controllers
|
23
|
+
autoload :Helpers, 'devise_password_expirable/controllers/helpers'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# modules
|
28
|
+
Devise.add_module :password_expirable, :controller => :password_expirable, :model => 'devise_password_expirable/models/password_expirable', :route => :password_expired
|
29
|
+
|
30
|
+
# requires
|
31
|
+
require 'devise_password_expirable/routes'
|
32
|
+
require 'devise_password_expirable/rails'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module DevisePasswordExpirable
|
2
|
+
module Controllers
|
3
|
+
module Helpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_filter :handle_password_change
|
8
|
+
end
|
9
|
+
|
10
|
+
# controller instance methods
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# lookup if an password change needed
|
15
|
+
def handle_password_change
|
16
|
+
if not devise_controller? and not ignore_password_expire? and not request.format.nil? and request.format.html?
|
17
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
18
|
+
if signed_in?(scope) and warden.session(scope)['password_expired']
|
19
|
+
session["#{scope}_return_to"] = request.path if request.get?
|
20
|
+
redirect_for_password_change scope
|
21
|
+
return
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# redirect for password update with alert message
|
28
|
+
def redirect_for_password_change(scope)
|
29
|
+
redirect_to change_password_required_path_for(scope), :alert => I18n.t('change_required', {:scope => 'devise.password_expired'})
|
30
|
+
end
|
31
|
+
|
32
|
+
# path for change password
|
33
|
+
def change_password_required_path_for(resource_or_scope = nil)
|
34
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
35
|
+
change_path = "#{scope}_password_expired_path"
|
36
|
+
send(change_path)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# allow to overwrite for some special handlings
|
42
|
+
def ignore_password_expire?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'devise_password_expirable/hooks/password_expirable'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Models
|
5
|
+
|
6
|
+
# PasswordExpirable takes care of change password after
|
7
|
+
module PasswordExpirable
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
before_save :update_password_changed
|
12
|
+
end
|
13
|
+
|
14
|
+
# is an password change required?
|
15
|
+
def need_change_password?
|
16
|
+
if self.class.expire_password_after.is_a? Fixnum or self.class.expire_password_after.is_a? Float
|
17
|
+
self.last_password_reset.nil? or self.last_password_reset < self.class.expire_password_after.ago
|
18
|
+
else
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# set a fake datetime so a password change is needed and save the record
|
24
|
+
def need_change_password!
|
25
|
+
if self.class.expire_password_after.is_a? Fixnum or self.class.expire_password_after.is_a? Float
|
26
|
+
need_change_password
|
27
|
+
self.save(:validate => false)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# set a fake datetime so a password change is needed
|
32
|
+
def need_change_password
|
33
|
+
if self.class.expire_password_after.is_a? Fixnum or self.class.expire_password_after.is_a? Float
|
34
|
+
self.last_password_reset = self.class.expire_password_after.ago
|
35
|
+
end
|
36
|
+
|
37
|
+
# is date not set it will set default to need set new password next login
|
38
|
+
need_change_password if self.last_password_reset.nil?
|
39
|
+
|
40
|
+
self.last_password_reset
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# is password changed then update password_cahanged_at
|
46
|
+
def update_password_changed
|
47
|
+
self.last_password_reset = Time.now if (self.new_record? or self.encrypted_password_changed?) and not self.last_password_reset_changed?
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
::Devise::Models.config(self, :expire_password_after)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
class Mapper
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
# route for handle expired passwords
|
7
|
+
def devise_password_expired(mapping, controllers)
|
8
|
+
resource :password_expired, :only => [:show, :update], :path => mapping.path_names[:password_expired], :controller => controllers[:password_expired]
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module DevisePasswordExpirable
|
2
|
+
# add schema helper for migrations
|
3
|
+
module Schema
|
4
|
+
# Add last_password_reset columns in the resource's database table.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# # For a new resource migration:
|
9
|
+
# create_table :the_resources do |t|
|
10
|
+
# t.password_expirable
|
11
|
+
# ...
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # or if the resource's table already exists, define a migration and put this in:
|
15
|
+
# change_table :the_resources do |t|
|
16
|
+
# t.datetime :last_password_reset
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
def password_expirable
|
20
|
+
apply_devise_schema :last_password_reset, DateTime
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DevisePasswordExpirable
|
2
|
+
module Generators
|
3
|
+
# Install Generator
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../../templates", __FILE__)
|
6
|
+
|
7
|
+
desc "Install the devise password expirable extension"
|
8
|
+
|
9
|
+
def add_configs
|
10
|
+
inject_into_file "config/initializers/devise.rb", "\n # ==> Password Expirable Extension\n # Configure expire passwords extension for devise\n\n" +
|
11
|
+
" # Should the password expire (e.g 3.months)\n" +
|
12
|
+
" # config.expire_password_after = false\n\n" +
|
13
|
+
" # Need 1 char of A-Z, a-z and 0-9\n" +
|
14
|
+
" # config.password_regex = /(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])/\n\n" +
|
15
|
+
"", :before => /end[ |\n|]+\Z/
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_locale
|
19
|
+
copy_file "../../../config/locales/en.yml", "config/locales/devise.password_expirable.en.yml"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise_password_expirable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jenni Kissinger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2014-10-21 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.20
|
22
|
+
type: :runtime
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: devise
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - "="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 1.1.3
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id002
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: bundler
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- &id004
|
40
|
+
- ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id003
|
45
|
+
description: An extension to devise that will expire user passwords after a set amount of time and prompt them to update their password.
|
46
|
+
email:
|
47
|
+
- jkissinger@carekinesis.com
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files: []
|
53
|
+
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
59
|
+
- app/controllers/devise/password_expired_controller.rb
|
60
|
+
- app/views/devise/password_expired/show.html.erb
|
61
|
+
- config/locales/en.yml
|
62
|
+
- devise_password_expirable.gemspec
|
63
|
+
- lib/devise_password_expirable.rb
|
64
|
+
- lib/devise_password_expirable/controllers/helpers.rb
|
65
|
+
- lib/devise_password_expirable/hooks/password_expirable.rb
|
66
|
+
- lib/devise_password_expirable/models/password_expirable.rb
|
67
|
+
- lib/devise_password_expirable/rails.rb
|
68
|
+
- lib/devise_password_expirable/routes.rb
|
69
|
+
- lib/devise_password_expirable/schema.rb
|
70
|
+
- lib/devise_password_expirable/version.rb
|
71
|
+
- lib/generators/devise_expire_passwords/install_generator.rb
|
72
|
+
homepage: https://github.com/jenjaina/devise_password_expirable
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- *id004
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- *id004
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.4.1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Expire passwords plugin for devise
|
95
|
+
test_files: []
|
96
|
+
|