devise_security_extension 0.5.1 → 0.6.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/README.rdoc +30 -6
- data/VERSION +1 -1
- data/config/locales/de.yml +1 -0
- data/config/locales/en.yml +1 -0
- data/devise_security_extension.gemspec +4 -2
- data/lib/devise_security_extension.rb +8 -3
- data/lib/devise_security_extension/hooks/expirable.rb +10 -0
- data/lib/devise_security_extension/models/expirable.rb +124 -0
- data/lib/generators/devise_security_extension/install_generator.rb +5 -2
- metadata +17 -15
data/README.rdoc
CHANGED
@@ -9,12 +9,13 @@ An enterprise security extension for devise, trying to meet industrial standard
|
|
9
9
|
=== Model modules
|
10
10
|
|
11
11
|
* :password_expirable - passwords will expire after a configured time (and will need an update)
|
12
|
-
* :secure_validatable - better way to validate model (email, stronger password validation).
|
13
|
-
* :password_archivable - save used
|
14
|
-
* :session_limitable - ensures, that there is only one session usable per account at once
|
12
|
+
* :secure_validatable - better way to validate a model (email, stronger password validation). Don't use with :validatable!
|
13
|
+
* :password_archivable - save used passwords in an old_passwords table for history checks (don't be able to use a formerly used password)
|
14
|
+
* :session_limitable - ensures, that there is only one session usable per account at once
|
15
|
+
* :expirable - expires a user account after x days of inactivity (default 90 days)
|
15
16
|
|
16
17
|
== Installation
|
17
|
-
|
18
|
+
Add to Gemfile
|
18
19
|
gem 'devise_security_extension'
|
19
20
|
|
20
21
|
after bundle install
|
@@ -49,6 +50,10 @@ for :secure_validatable you need to add
|
|
49
50
|
|
50
51
|
# captcha integration for unlock form
|
51
52
|
# config.captcha_for_unlock = true
|
53
|
+
|
54
|
+
# ==> Configuration for :expirable
|
55
|
+
# Time period for account expiry from last_activity_at
|
56
|
+
config.expire_after = 90.days
|
52
57
|
end
|
53
58
|
|
54
59
|
== Captcha-Support
|
@@ -58,7 +63,7 @@ for :secure_validatable you need to add
|
|
58
63
|
1. add to Gemfile "gem 'easy_captcha'"
|
59
64
|
2. install easy_captcha "rails g easy_captcha:install"
|
60
65
|
3. enable captcha - see "Configuration"
|
61
|
-
4. add captcha source in
|
66
|
+
4. add captcha source in the devise views for each controller you have activated
|
62
67
|
|
63
68
|
<p><%= captcha_tag %></p>
|
64
69
|
<p><%= text_field_tag :captcha %></p>
|
@@ -87,6 +92,24 @@ That's it!
|
|
87
92
|
t.session_limitable
|
88
93
|
end
|
89
94
|
|
95
|
+
=== Expirable
|
96
|
+
Devise 2.0 style migrations on new resource:
|
97
|
+
|
98
|
+
create_table :the_resources do |t|
|
99
|
+
...
|
100
|
+
t.datetime :last_activity_at
|
101
|
+
t.datetime :expired_at
|
102
|
+
...
|
103
|
+
end
|
104
|
+
|
105
|
+
Add module to existing resource with
|
106
|
+
|
107
|
+
change_table :the_resources do |t|
|
108
|
+
t.datetime :last_activity_at
|
109
|
+
t.datetime :expired_at
|
110
|
+
end
|
111
|
+
|
112
|
+
|
90
113
|
== Requirements
|
91
114
|
|
92
115
|
* devise (https://github.com/plataformatec/devise)
|
@@ -95,7 +118,7 @@ That's it!
|
|
95
118
|
|
96
119
|
== Todo
|
97
120
|
|
98
|
-
*
|
121
|
+
* see the github issues (feature requests)
|
99
122
|
|
100
123
|
== History
|
101
124
|
* 0.1 expire passwords
|
@@ -103,6 +126,7 @@ That's it!
|
|
103
126
|
* 0.3 password archivable with validation
|
104
127
|
* 0.4 captcha support for sign_up, sign_in, recover and unlock
|
105
128
|
* 0.5 session_limitable module
|
129
|
+
* 0.6 expirable module
|
106
130
|
|
107
131
|
== Maintainers
|
108
132
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/config/locales/de.yml
CHANGED
@@ -10,3 +10,4 @@ de:
|
|
10
10
|
change_required: "Ihr Passwort ist abgelaufen. Bitte vergeben sie ein neues Passwort!"
|
11
11
|
failure:
|
12
12
|
session_limited: 'Ihre Anmeldedaten wurden in einem anderen Browser genutzt. Bitte melden Sie sich erneut an, um in diesem Browser fortzufahren.'
|
13
|
+
expired: 'Ihr Account ist aufgrund zu langer Inaktiviät abgelaufen. Bitte kontaktieren Sie den Administrator.'
|
data/config/locales/en.yml
CHANGED
@@ -10,3 +10,4 @@ en:
|
|
10
10
|
change_required: "Your password is expired. Please renew your password!"
|
11
11
|
failure:
|
12
12
|
session_limited: 'Your login credentials were used in another browser. Please sign in again to continue in this browser.'
|
13
|
+
expired: 'Your account has expired due to inactivity. Please contact the site administrator.'
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "devise_security_extension"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Marco Scholl", "Alexander Dreher"]
|
12
|
-
s.date = "2011-12-
|
12
|
+
s.date = "2011-12-28"
|
13
13
|
s.description = "An enterprise security extension for devise, trying to meet industrial standard security demands for web applications."
|
14
14
|
s.email = "team@phatworx.de"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -31,8 +31,10 @@ Gem::Specification.new do |s|
|
|
31
31
|
"devise_security_extension.gemspec",
|
32
32
|
"lib/devise_security_extension.rb",
|
33
33
|
"lib/devise_security_extension/controllers/helpers.rb",
|
34
|
+
"lib/devise_security_extension/hooks/expirable.rb",
|
34
35
|
"lib/devise_security_extension/hooks/password_expirable.rb",
|
35
36
|
"lib/devise_security_extension/hooks/session_limitable.rb",
|
37
|
+
"lib/devise_security_extension/models/expirable.rb",
|
36
38
|
"lib/devise_security_extension/models/old_password.rb",
|
37
39
|
"lib/devise_security_extension/models/password_archivable.rb",
|
38
40
|
"lib/devise_security_extension/models/password_expirable.rb",
|
@@ -43,7 +43,12 @@ module Devise # :nodoc:
|
|
43
43
|
# captcha integration for unlock form
|
44
44
|
mattr_accessor :captcha_for_unlock
|
45
45
|
@@captcha_for_unlock = false
|
46
|
-
|
46
|
+
|
47
|
+
# Time period for account expiry from last_activity_at
|
48
|
+
mattr_accessor :expire_after
|
49
|
+
@@expire_after = 90.days
|
50
|
+
mattr_accessor :delete_expired_after
|
51
|
+
@@delete_expired_after = 90.days
|
47
52
|
end
|
48
53
|
|
49
54
|
# an security extension for devise
|
@@ -51,7 +56,7 @@ module DeviseSecurityExtension
|
|
51
56
|
autoload :Schema, 'devise_security_extension/schema'
|
52
57
|
autoload :Patches, 'devise_security_extension/patches'
|
53
58
|
|
54
|
-
module Controllers
|
59
|
+
module Controllers
|
55
60
|
autoload :Helpers, 'devise_security_extension/controllers/helpers'
|
56
61
|
end
|
57
62
|
end
|
@@ -61,10 +66,10 @@ Devise.add_module :password_expirable, :controller => :password_expirable, :mode
|
|
61
66
|
Devise.add_module :secure_validatable, :model => 'devise_security_extension/models/secure_validatable'
|
62
67
|
Devise.add_module :password_archivable, :model => 'devise_security_extension/models/password_archivable'
|
63
68
|
Devise.add_module :session_limitable, :model => 'devise_security_extension/models/session_limitable'
|
69
|
+
Devise.add_module :expirable, :model => 'devise_security_extension/models/expirable'
|
64
70
|
|
65
71
|
# requires
|
66
72
|
require 'devise_security_extension/routes'
|
67
73
|
require 'devise_security_extension/rails'
|
68
74
|
require 'devise_security_extension/orm/active_record'
|
69
75
|
require 'devise_security_extension/models/old_password'
|
70
|
-
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Updates the last_activity_at fields from the record. Only when the user is active
|
2
|
+
# for authentication and authenticated.
|
3
|
+
# An expiry of the account is only checked on sign in OR on manually setting the
|
4
|
+
# expired_at to the past (see Devise::Models::Expirable for this)
|
5
|
+
Warden::Manager.after_set_user do |record, warden, options|
|
6
|
+
if record && record.respond_to?(:active_for_authentication?) && record.active_for_authentication? &&
|
7
|
+
warden.authenticated?(options[:scope]) && record.respond_to?(:update_last_activitiy!)
|
8
|
+
record.update_last_activitiy!
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'devise_security_extension/hooks/expirable'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Models
|
5
|
+
# Deactivate the account after a configurable amount of time. To be able to
|
6
|
+
# tell, it tracks activity about your account with the following columns:
|
7
|
+
#
|
8
|
+
# * last_activity_at - A timestamp updated when the user requests a page (only signed in)
|
9
|
+
#
|
10
|
+
# == Options
|
11
|
+
# +:expire_after+ - Time interval to expire accounts after
|
12
|
+
#
|
13
|
+
# == Additions
|
14
|
+
# Best used with two cron jobs. One for expiring accounts after inactivity,
|
15
|
+
# and another, that deletes accounts, which have expired for a given amount
|
16
|
+
# of time (for example 90 days).
|
17
|
+
#
|
18
|
+
module Expirable
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
# Updates +last_activity_at+, called from a Warden::Manager.after_set_user hook.
|
23
|
+
def update_last_activitiy!
|
24
|
+
self.last_activity_at = Time.now.utc
|
25
|
+
save(:validate => false)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Tells if the account has expired
|
29
|
+
#
|
30
|
+
# @return [bool]
|
31
|
+
def expired?
|
32
|
+
# expired_at set (manually, via cron, etc.)
|
33
|
+
return self.expired_at < Time.now.utc unless self.expired_at.nil?
|
34
|
+
# if it is not set, check the last activity against configured expire_after time range
|
35
|
+
return self.last_activity_at < self.class.expire_after.ago unless self.last_activity_at.nil?
|
36
|
+
# if last_activity_at is nil as well, the user has to be 'fresh' and is therefore not expired
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Expire an account. This is for cron jobs and manually expiring of accounts.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# User.expire!
|
44
|
+
# User.expire! 1.week.from_now
|
45
|
+
# @note +expired_at+ can be in the future as well
|
46
|
+
def expire!(at = Time.now.utc)
|
47
|
+
self.expired_at = at
|
48
|
+
save(:validate => false)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Overwrites active_for_authentication? from Devise::Models::Activatable
|
52
|
+
# for verifying whether a user is active to sign in or not. If the account
|
53
|
+
# is expired, it should never be allowed.
|
54
|
+
#
|
55
|
+
# @return [bool]
|
56
|
+
def active_for_authentication?
|
57
|
+
super && !self.expired?
|
58
|
+
end
|
59
|
+
|
60
|
+
# The message sym, if {#active_for_authentication?} returns +false+. E.g. needed
|
61
|
+
# for i18n.
|
62
|
+
def inactive_message
|
63
|
+
!self.expired? ? super : :expired
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
module ClassMethods
|
69
|
+
::Devise::Models.config(self, :expire_after, :delete_expired_after)
|
70
|
+
|
71
|
+
# Sample method for daily cron to mark expired entries.
|
72
|
+
#
|
73
|
+
# @example You can overide this in your +resource+ model
|
74
|
+
# def self.mark_expired
|
75
|
+
# puts 'overwritten mark_expired'
|
76
|
+
# end
|
77
|
+
def mark_expired
|
78
|
+
all.each do |u|
|
79
|
+
u.expire! if u.expired? && u.expired_at.nil?
|
80
|
+
end
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
84
|
+
# Scope method to collect all expired users since +time+ ago
|
85
|
+
def expired_for(time = delete_expired_after)
|
86
|
+
where('expired_at < ?', time.ago)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Sample method for daily cron to delete all expired entries after a
|
90
|
+
# given amount of +time+.
|
91
|
+
#
|
92
|
+
# In your overwritten method you can "blank out" the object instead of
|
93
|
+
# deleting it.
|
94
|
+
#
|
95
|
+
# *Word of warning*: You have to handle the dependent method
|
96
|
+
# on the +resource+ relations (+:destroy+ or +:nullify+) and catch this
|
97
|
+
# behavior (see http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Deleting+from+associations).
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# Resource.delete_all_expired_for 90.days
|
101
|
+
# @example You can overide this in your +resource+ model
|
102
|
+
# def self.delete_all_expired_for(time = 90.days)
|
103
|
+
# puts 'overwritten delete call'
|
104
|
+
# end
|
105
|
+
# @example Overwritten version to blank out the object.
|
106
|
+
# def self.delete_all_expired_for(time = 90.days)
|
107
|
+
# expired_for(time).each do |u|
|
108
|
+
# u.update_attributes first_name: nil, last_name: nil
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
def delete_all_expired_for(time)
|
112
|
+
expired_for(time).delete_all
|
113
|
+
end
|
114
|
+
|
115
|
+
# Version of {#delete_all_expired_for} without arguments (uses
|
116
|
+
# configured +delete_expired_after+ default value).
|
117
|
+
# @see #delete_all_expired_for
|
118
|
+
def delete_all_expired
|
119
|
+
delete_all_expired_for(delete_expired_after)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -26,8 +26,11 @@ module DeviseSecurityExtension
|
|
26
26
|
" # captcha integration for sign in form\n" +
|
27
27
|
" # config.captcha_for_sign_in = true\n\n" +
|
28
28
|
" # captcha integration for unlock form\n" +
|
29
|
-
" # config.captcha_for_unlock = true" +
|
30
|
-
"
|
29
|
+
" # config.captcha_for_unlock = true\n\n" +
|
30
|
+
" # ==> Configuration for :expirable\n" +
|
31
|
+
" # Time period for account expiry from last_activity_at\n" +
|
32
|
+
" config.expire_after = 90.days\n" +
|
33
|
+
"", :before => /end[ |\n|]+\Z/
|
31
34
|
end
|
32
35
|
|
33
36
|
def copy_locale
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise_security_extension
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2011-12-
|
13
|
+
date: 2011-12-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &21216320 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.1.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *21216320
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: devise
|
28
|
-
requirement: &
|
28
|
+
requirement: &21234920 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *21234920
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rails_email_validator
|
39
|
-
requirement: &
|
39
|
+
requirement: &21250840 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *21250840
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: easy_captcha
|
50
|
-
requirement: &
|
50
|
+
requirement: &21246220 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *21246220
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: bundler
|
61
|
-
requirement: &
|
61
|
+
requirement: &21243800 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ~>
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: 1.0.0
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *21243800
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: jeweler
|
72
|
-
requirement: &
|
72
|
+
requirement: &21268580 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ~>
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: 1.5.2
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *21268580
|
81
81
|
description: An enterprise security extension for devise, trying to meet industrial
|
82
82
|
standard security demands for web applications.
|
83
83
|
email: team@phatworx.de
|
@@ -101,8 +101,10 @@ files:
|
|
101
101
|
- devise_security_extension.gemspec
|
102
102
|
- lib/devise_security_extension.rb
|
103
103
|
- lib/devise_security_extension/controllers/helpers.rb
|
104
|
+
- lib/devise_security_extension/hooks/expirable.rb
|
104
105
|
- lib/devise_security_extension/hooks/password_expirable.rb
|
105
106
|
- lib/devise_security_extension/hooks/session_limitable.rb
|
107
|
+
- lib/devise_security_extension/models/expirable.rb
|
106
108
|
- lib/devise_security_extension/models/old_password.rb
|
107
109
|
- lib/devise_security_extension/models/password_archivable.rb
|
108
110
|
- lib/devise_security_extension/models/password_expirable.rb
|
@@ -132,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
134
|
version: '0'
|
133
135
|
segments:
|
134
136
|
- 0
|
135
|
-
hash:
|
137
|
+
hash: -3314141216685045721
|
136
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
139
|
none: false
|
138
140
|
requirements:
|