devise_security_extension 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|