devise_security_extension 0.2.1 → 0.3.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 CHANGED
@@ -23,10 +23,22 @@ after bundle execute
23
23
 
24
24
  * :password_expirable - activate that passwords will expire
25
25
  * :secure_validatable - better way to validate model. don't use with :validatable!!!
26
+ * :password_archivable - save password in old_passwords for history checks
26
27
 
27
28
  == Schema
28
29
 
29
- * t.password_expirable
30
+ === Password expirable
31
+
32
+ create_table :the_resources do |t|
33
+ t.password_expirable
34
+ end
35
+
36
+ === Password archive
37
+
38
+ create_table :old_passwords do
39
+ t.password_archivable
40
+ end
41
+ add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
30
42
 
31
43
  == Requirements
32
44
 
@@ -37,6 +49,7 @@ after bundle execute
37
49
 
38
50
  * expire passwords (update password with current password)
39
51
  * strong password validation
52
+ * save old passwords for check new passwords
40
53
 
41
54
  == Todo
42
55
 
@@ -48,6 +61,7 @@ after bundle execute
48
61
  == History
49
62
  * 0.1 expire passwords
50
63
  * 0.2 strong password validation
64
+ * 0.3 password archivable with validation
51
65
 
52
66
  == Maintainers
53
67
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{devise_security_extension}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.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"]
12
- s.date = %q{2011-02-03}
12
+ s.date = %q{2011-02-13}
13
13
  s.description = %q{a gem for extend devise for more password security}
14
14
  s.email = %q{develop@marco-scholl.de}
15
15
  s.extra_rdoc_files = [
@@ -32,6 +32,8 @@ Gem::Specification.new do |s|
32
32
  "lib/devise_security_extension.rb",
33
33
  "lib/devise_security_extension/controllers/helpers.rb",
34
34
  "lib/devise_security_extension/hooks/password_expirable.rb",
35
+ "lib/devise_security_extension/models/old_password.rb",
36
+ "lib/devise_security_extension/models/password_archivable.rb",
35
37
  "lib/devise_security_extension/models/password_expirable.rb",
36
38
  "lib/devise_security_extension/models/secure_validatable.rb",
37
39
  "lib/devise_security_extension/orm/active_record.rb",
@@ -1,6 +1,8 @@
1
1
  #require 'rails/all'
2
2
  require 'active_record/connection_adapters/abstract/schema_definitions'
3
3
  require 'active_support/core_ext/integer'
4
+ require 'active_support/ordered_hash'
5
+ require 'active_support/concern'
4
6
  require 'devise'
5
7
 
6
8
  module Devise # :nodoc:
@@ -13,6 +15,13 @@ module Devise # :nodoc:
13
15
  mattr_accessor :password_regex
14
16
  @@password_regex = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/
15
17
 
18
+ # write history of last x passwords
19
+ mattr_accessor :password_archiving_count
20
+ @@password_archiving_count = 5
21
+
22
+ # deny old password (true, false, integer)
23
+ mattr_accessor :deny_old_passwords
24
+ @@deny_old_passwords = true
16
25
  end
17
26
 
18
27
  # an security extension for devise
@@ -26,7 +35,9 @@ end
26
35
 
27
36
  Devise.add_module :password_expirable, :controller => :password_expirable, :model => 'devise_security_extension/models/password_expirable', :route => :password_expired
28
37
  Devise.add_module :secure_validatable, :model => 'devise_security_extension/models/secure_validatable'
38
+ Devise.add_module :password_archivable, :model => 'devise_security_extension/models/password_archivable'
29
39
 
30
40
  require 'devise_security_extension/routes'
31
41
  require 'devise_security_extension/rails'
32
42
  require 'devise_security_extension/orm/active_record'
43
+ require 'devise_security_extension/models/old_password'
@@ -0,0 +1,3 @@
1
+ class OldPassword < ActiveRecord::Base
2
+ belongs_to :password_archivable, :polymorphic => true
3
+ end
@@ -0,0 +1,67 @@
1
+ module Devise # :nodoc:
2
+ module Models # :nodoc:
3
+
4
+ # PasswordArchivable
5
+ module PasswordArchivable
6
+
7
+ def self.included(base) # :nodoc:
8
+ base.extend ClassMethods
9
+
10
+ base.class_eval do
11
+ include InstanceMethods
12
+ has_many :old_passwords, :as => :password_archivable, :class_name => "OldPassword"
13
+ before_save :archive_password
14
+ validate :validate_password_archive
15
+ end
16
+ end
17
+
18
+ module InstanceMethods # :nodoc:
19
+
20
+ def validate_password_archive
21
+ self.errors.add(:password, :taken_in_past) if password_archive_included?
22
+ end
23
+
24
+ # validate is the password used in the past
25
+ def password_archive_included?
26
+ unless self.class.deny_old_passwords.is_a? Fixnum
27
+ if self.class.deny_old_passwords.is_a? TrueClass and self.class.password_archiving_count > 0
28
+ self.class.deny_old_passwords = self.class.password_archiving_count
29
+ else
30
+ self.class.deny_old_passwords = 0
31
+ end
32
+ end
33
+
34
+ if self.class.deny_old_passwords > 0 and not self.password.nil?
35
+ self.old_passwords.order('created_at DESC').limit(self.class.deny_old_passwords).limit(self.class.deny_old_passwords).each do |old_password|
36
+ dummy = self.class.new
37
+ dummy.encrypted_password = old_password.encrypted_password
38
+ dummy.password_salt = old_password.password_salt
39
+ return true if dummy.valid_password?(self.password)
40
+ end
41
+ end
42
+
43
+ false
44
+ end
45
+
46
+ private
47
+
48
+ # archive the last password before save and delete all to old passwords from archive
49
+ def archive_password
50
+ if self.encrypted_password_changed?
51
+ if self.class.password_archiving_count.to_i > 0
52
+ self.old_passwords.create! :encrypted_password => self.encrypted_password_change.first, :password_salt => self.password_salt_change.first
53
+ self.old_passwords.order('created_at DESC').offset(self.class.password_archiving_count).destroy_all
54
+ else
55
+ self.old_passwords.destroy_all
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ module ClassMethods #:nodoc:
62
+ ::Devise::Models.config(self, :password_archiving_count, :deny_old_passwords)
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -6,7 +6,7 @@ module DeviseSecurityExtension
6
6
  # Examples
7
7
  #
8
8
  # # For a new resource migration:
9
- # create_table :the_resources do
9
+ # create_table :the_resources do |t|
10
10
  # t.password_expirable
11
11
  # ...
12
12
  # end
@@ -19,5 +19,22 @@ module DeviseSecurityExtension
19
19
  def password_expirable
20
20
  apply_devise_schema :password_changed_at, DateTime
21
21
  end
22
+
23
+ # Add password_archivable columns
24
+ #
25
+ # Examples
26
+ #
27
+ # create_table :old_passwords do
28
+ # t.password_archivable
29
+ # end
30
+ # add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
31
+ #
32
+ def password_archivable
33
+ apply_devise_schema :encrypted_password, String, :limit => 128, :null => false
34
+ apply_devise_schema :password_salt, String, :null => false
35
+ apply_devise_schema :password_archivable_id, Integer, :null => false
36
+ apply_devise_schema :password_archivable_type, String, :null => false
37
+ apply_devise_schema :created_at, DateTime
38
+ end
22
39
  end
23
40
  end
@@ -8,8 +8,12 @@ module DeviseSecurityExtension
8
8
 
9
9
  def add_configs
10
10
  inject_into_file "config/initializers/devise.rb", "\n\n # ==> Security Extension\n # Configure security extension for devise\n\n" +
11
- " # Should the password expire (e.g 3.months)\n # config.expire_password_after = false\n" +
12
- " # Need 1 char of A-Z, a-z and 0-9\n # config.password_regex = /(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])/\n" +
11
+ " # Should the password expire (e.g 3.months)\n" +
12
+ " # config.expire_password_after = false\n" +
13
+ " # Need 1 char of A-Z, a-z and 0-9\n" +
14
+ " # config.password_regex = /(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])/\n" +
15
+ " # How often save old passwords in archive\n" +
16
+ " # config.password_archiving_count = 5\n" +
13
17
  "\n", :before => /end[ |\n|]+\Z/
14
18
  end
15
19
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: devise_security_extension
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.1
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Marco Scholl
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-02-03 00:00:00 +01:00
13
+ date: 2011-02-13 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -104,6 +104,8 @@ files:
104
104
  - lib/devise_security_extension.rb
105
105
  - lib/devise_security_extension/controllers/helpers.rb
106
106
  - lib/devise_security_extension/hooks/password_expirable.rb
107
+ - lib/devise_security_extension/models/old_password.rb
108
+ - lib/devise_security_extension/models/password_archivable.rb
107
109
  - lib/devise_security_extension/models/password_expirable.rb
108
110
  - lib/devise_security_extension/models/secure_validatable.rb
109
111
  - lib/devise_security_extension/orm/active_record.rb
@@ -127,7 +129,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
129
  requirements:
128
130
  - - ">="
129
131
  - !ruby/object:Gem::Version
130
- hash: -219664376672679260
132
+ hash: -461004346872330403
131
133
  segments:
132
134
  - 0
133
135
  version: "0"