devise_password_expirable 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|