devise_security_extension 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  gem "rails", ">= 3.1.1"
5
- gem "devise"
5
+ gem "devise", ">= 2.0.0"
6
6
 
7
7
  # Add dependencies to develop your gem here.
8
8
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -1,43 +1,49 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- actionmailer (3.1.3)
5
- actionpack (= 3.1.3)
6
- mail (~> 2.3.0)
7
- actionpack (3.1.3)
8
- activemodel (= 3.1.3)
9
- activesupport (= 3.1.3)
4
+ actionmailer (3.2.1)
5
+ actionpack (= 3.2.1)
6
+ mail (~> 2.4.0)
7
+ actionpack (3.2.1)
8
+ activemodel (= 3.2.1)
9
+ activesupport (= 3.2.1)
10
10
  builder (~> 3.0.0)
11
11
  erubis (~> 2.7.0)
12
- i18n (~> 0.6)
13
- rack (~> 1.3.5)
12
+ journey (~> 1.0.1)
13
+ rack (~> 1.4.0)
14
14
  rack-cache (~> 1.1)
15
- rack-mount (~> 0.8.2)
16
15
  rack-test (~> 0.6.1)
17
- sprockets (~> 2.0.3)
18
- activemodel (3.1.3)
19
- activesupport (= 3.1.3)
16
+ sprockets (~> 2.1.2)
17
+ activemodel (3.2.1)
18
+ activesupport (= 3.2.1)
20
19
  builder (~> 3.0.0)
21
- i18n (~> 0.6)
22
- activerecord (3.1.3)
23
- activemodel (= 3.1.3)
24
- activesupport (= 3.1.3)
25
- arel (~> 2.2.1)
20
+ activerecord (3.2.1)
21
+ activemodel (= 3.2.1)
22
+ activesupport (= 3.2.1)
23
+ arel (~> 3.0.0)
26
24
  tzinfo (~> 0.3.29)
27
- activeresource (3.1.3)
28
- activemodel (= 3.1.3)
29
- activesupport (= 3.1.3)
30
- activesupport (3.1.3)
25
+ activeresource (3.2.1)
26
+ activemodel (= 3.2.1)
27
+ activesupport (= 3.2.1)
28
+ activesupport (3.2.1)
29
+ i18n (~> 0.6)
31
30
  multi_json (~> 1.0)
32
- arel (2.2.1)
31
+ arel (3.0.0)
33
32
  bcrypt-ruby (3.0.1)
34
33
  builder (3.0.0)
35
- devise (1.5.1)
34
+ devise (2.0.0)
36
35
  bcrypt-ruby (~> 3.0)
37
36
  orm_adapter (~> 0.0.3)
37
+ railties (~> 3.1)
38
38
  warden (~> 1.1)
39
- easy_captcha (0.4.5)
39
+ diff-lcs (1.1.3)
40
+ easy_captcha (0.4.7)
41
+ bundler (~> 1.0.0)
40
42
  rails (>= 3.0.0)
43
+ rmagick (>= 2.13.1)
44
+ rspec-rails (~> 2.8.1)
45
+ simplecov (>= 0.3.8)
46
+ yard (>= 0.7.0)
41
47
  erubis (2.7.0)
42
48
  git (1.2.5)
43
49
  hike (1.2.1)
@@ -46,45 +52,62 @@ GEM
46
52
  bundler (~> 1.0.0)
47
53
  git (>= 1.2.5)
48
54
  rake
49
- json (1.6.1)
50
- mail (2.3.0)
55
+ journey (1.0.1)
56
+ json (1.6.5)
57
+ mail (2.4.1)
51
58
  i18n (>= 0.4.0)
52
59
  mime-types (~> 1.16)
53
60
  treetop (~> 1.4.8)
54
61
  mime-types (1.17.2)
55
- multi_json (1.0.3)
56
- orm_adapter (0.0.5)
62
+ multi_json (1.0.4)
63
+ orm_adapter (0.0.6)
57
64
  polyglot (0.3.3)
58
- rack (1.3.5)
65
+ rack (1.4.1)
59
66
  rack-cache (1.1)
60
67
  rack (>= 0.4)
61
- rack-mount (0.8.3)
62
- rack (>= 1.0.0)
63
68
  rack-ssl (1.3.2)
64
69
  rack
65
70
  rack-test (0.6.1)
66
71
  rack (>= 1.0)
67
- rails (3.1.3)
68
- actionmailer (= 3.1.3)
69
- actionpack (= 3.1.3)
70
- activerecord (= 3.1.3)
71
- activeresource (= 3.1.3)
72
- activesupport (= 3.1.3)
72
+ rails (3.2.1)
73
+ actionmailer (= 3.2.1)
74
+ actionpack (= 3.2.1)
75
+ activerecord (= 3.2.1)
76
+ activeresource (= 3.2.1)
77
+ activesupport (= 3.2.1)
73
78
  bundler (~> 1.0)
74
- railties (= 3.1.3)
79
+ railties (= 3.2.1)
75
80
  rails_email_validator (0.1.4)
76
81
  activemodel (>= 3.0.0)
77
- railties (3.1.3)
78
- actionpack (= 3.1.3)
79
- activesupport (= 3.1.3)
82
+ railties (3.2.1)
83
+ actionpack (= 3.2.1)
84
+ activesupport (= 3.2.1)
80
85
  rack-ssl (~> 1.3.2)
81
86
  rake (>= 0.8.7)
82
87
  rdoc (~> 3.4)
83
88
  thor (~> 0.14.6)
84
89
  rake (0.9.2.2)
85
- rdoc (3.11)
90
+ rdoc (3.12)
86
91
  json (~> 1.4)
87
- sprockets (2.0.3)
92
+ rmagick (2.13.1)
93
+ rspec (2.8.0)
94
+ rspec-core (~> 2.8.0)
95
+ rspec-expectations (~> 2.8.0)
96
+ rspec-mocks (~> 2.8.0)
97
+ rspec-core (2.8.0)
98
+ rspec-expectations (2.8.0)
99
+ diff-lcs (~> 1.1.2)
100
+ rspec-mocks (2.8.0)
101
+ rspec-rails (2.8.1)
102
+ actionpack (>= 3.0)
103
+ activesupport (>= 3.0)
104
+ railties (>= 3.0)
105
+ rspec (~> 2.8.0)
106
+ simplecov (0.5.4)
107
+ multi_json (~> 1.0.3)
108
+ simplecov-html (~> 0.5.3)
109
+ simplecov-html (0.5.3)
110
+ sprockets (2.1.2)
88
111
  hike (~> 1.2)
89
112
  rack (~> 1.0)
90
113
  tilt (~> 1.1, != 1.3.0)
@@ -96,13 +119,14 @@ GEM
96
119
  tzinfo (0.3.31)
97
120
  warden (1.1.0)
98
121
  rack (>= 1.0)
122
+ yard (0.7.5)
99
123
 
100
124
  PLATFORMS
101
125
  ruby
102
126
 
103
127
  DEPENDENCIES
104
128
  bundler (~> 1.0.0)
105
- devise
129
+ devise (>= 2.0.0)
106
130
  easy_captcha
107
131
  jeweler (~> 1.5.2)
108
132
  rails (>= 3.1.1)
data/README.rdoc CHANGED
@@ -76,39 +76,41 @@ That's it!
76
76
  === Password expirable
77
77
 
78
78
  create_table :the_resources do |t|
79
- t.password_expirable
79
+ # other devise fields
80
+
81
+ t.datetime :password_changed_at
80
82
  end
83
+ add_index :the_resources, :password_changed_at
81
84
 
82
85
  === Password archivable
83
86
 
84
87
  create_table :old_passwords do |t|
85
- t.password_archivable
88
+ t.string :encrypted_password, :null => false
89
+ t.string :password_salt
90
+ t.string :password_archivable_type, :null => false
91
+ t.integer :password_archivable_id, :null => false
92
+ t.datetime :created_at
86
93
  end
87
94
  add_index :old_passwords, [:password_archivable_type, :password_archivable_id], :name => :index_password_archivable
88
95
 
89
96
  === Session limitable
90
97
 
91
98
  create_table :the_resources do |t|
92
- t.session_limitable
99
+ # other devise fields
100
+
101
+ t.string :unique_session_id, :limit => 20
93
102
  end
94
103
 
95
104
  === Expirable
96
- Devise 2.0 style migrations on new resource:
97
105
 
98
106
  create_table :the_resources do |t|
99
- ...
100
- t.datetime :last_activity_at
101
- t.datetime :expired_at
102
- ...
103
- end
107
+ # other devise fields
104
108
 
105
- Add module to existing resource with
106
-
107
- change_table :the_resources do |t|
108
109
  t.datetime :last_activity_at
109
110
  t.datetime :expired_at
110
111
  end
111
-
112
+ add_index :the_resources, :last_activity_at
113
+ add_index :the_resources, :expired_at
112
114
 
113
115
  == Requirements
114
116
 
@@ -133,6 +135,7 @@ Add module to existing resource with
133
135
  * Team Phatworx (http://github.com/phatworx)
134
136
  * Marco Scholl (http://github.com/traxanos)
135
137
  * Alexander Dreher (http://github.com/alexdreher)
138
+ * Christoph Chilian (http://github.com/cc-web)
136
139
 
137
140
  == Contributing to devise_security_extension
138
141
 
@@ -146,4 +149,4 @@ Add module to existing resource with
146
149
 
147
150
  == Copyright
148
151
 
149
- Copyright (c) 2011 Marco Scholl. See LICENSE.txt for further details.
152
+ Copyright (c) 2011-2012 Marco Scholl. See LICENSE.txt for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.6.1
@@ -1,11 +1,11 @@
1
- class Devise::PasswordExpiredController < ApplicationController
1
+ class Devise::PasswordExpiredController < DeviseController
2
2
  skip_before_filter :handle_password_change
3
3
  prepend_before_filter :authenticate_scope!, :only => [:show, :update]
4
- include Devise::Controllers::InternalHelpers
4
+ include Devise::Controllers::Helpers
5
5
 
6
6
  def show
7
7
  if not resource.nil? and resource.need_change_password?
8
- render_with_scope :show
8
+ render 'devise/password_expired/show'
9
9
  else
10
10
  redirect_to :root
11
11
  end
@@ -19,7 +19,7 @@ class Devise::PasswordExpiredController < ApplicationController
19
19
  redirect_to stored_location_for(scope) || :root
20
20
  else
21
21
  clean_up_passwords(resource)
22
- render_with_scope :show
22
+ render 'devise/password_expired/show'
23
23
  end
24
24
  end
25
25
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "devise_security_extension"
8
- s.version = "0.6.0"
8
+ s.version = "0.6.1"
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-28"
12
+ s.date = "2012-06-06"
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 = [
@@ -42,7 +42,11 @@ Gem::Specification.new do |s|
42
42
  "lib/devise_security_extension/models/session_limitable.rb",
43
43
  "lib/devise_security_extension/orm/active_record.rb",
44
44
  "lib/devise_security_extension/patches.rb",
45
- "lib/devise_security_extension/patches/controller_captcha.rb",
45
+ "lib/devise_security_extension/patches/confirmations_controller_captcha.rb",
46
+ "lib/devise_security_extension/patches/passwords_controller_captcha.rb",
47
+ "lib/devise_security_extension/patches/registrations_controller_captcha.rb",
48
+ "lib/devise_security_extension/patches/sessions_controller_captcha.rb",
49
+ "lib/devise_security_extension/patches/unlocks_controller_captcha.rb",
46
50
  "lib/devise_security_extension/rails.rb",
47
51
  "lib/devise_security_extension/routes.rb",
48
52
  "lib/devise_security_extension/schema.rb",
@@ -53,7 +57,7 @@ Gem::Specification.new do |s|
53
57
  s.homepage = "http://github.com/phatworx/devise_security_extension"
54
58
  s.licenses = ["MIT"]
55
59
  s.require_paths = ["lib"]
56
- s.rubygems_version = "1.8.10"
60
+ s.rubygems_version = "1.8.21"
57
61
  s.summary = "Security extension for devise"
58
62
  s.test_files = [
59
63
  "test/helper.rb",
@@ -65,14 +69,14 @@ Gem::Specification.new do |s|
65
69
 
66
70
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
67
71
  s.add_runtime_dependency(%q<rails>, [">= 3.1.1"])
68
- s.add_runtime_dependency(%q<devise>, [">= 0"])
72
+ s.add_runtime_dependency(%q<devise>, [">= 2.0.0"])
69
73
  s.add_development_dependency(%q<rails_email_validator>, [">= 0"])
70
74
  s.add_development_dependency(%q<easy_captcha>, [">= 0"])
71
75
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
72
76
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
73
77
  else
74
78
  s.add_dependency(%q<rails>, [">= 3.1.1"])
75
- s.add_dependency(%q<devise>, [">= 0"])
79
+ s.add_dependency(%q<devise>, [">= 2.0.0"])
76
80
  s.add_dependency(%q<rails_email_validator>, [">= 0"])
77
81
  s.add_dependency(%q<easy_captcha>, [">= 0"])
78
82
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -80,7 +84,7 @@ Gem::Specification.new do |s|
80
84
  end
81
85
  else
82
86
  s.add_dependency(%q<rails>, [">= 3.1.1"])
83
- s.add_dependency(%q<devise>, [">= 0"])
87
+ s.add_dependency(%q<devise>, [">= 2.0.0"])
84
88
  s.add_dependency(%q<rails_email_validator>, [">= 0"])
85
89
  s.add_dependency(%q<easy_captcha>, [">= 0"])
86
90
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -5,7 +5,7 @@ require 'active_support/ordered_hash'
5
5
  require 'active_support/concern'
6
6
  require 'devise'
7
7
 
8
- module Devise # :nodoc:
8
+ module Devise
9
9
 
10
10
  # Should the password expire (e.g 3.months)
11
11
  mattr_accessor :expire_password_after
@@ -43,6 +43,10 @@ module Devise # :nodoc:
43
43
  # captcha integration for unlock form
44
44
  mattr_accessor :captcha_for_unlock
45
45
  @@captcha_for_unlock = false
46
+
47
+ # captcha integration for confirmation form
48
+ mattr_accessor :captcha_for_confirmation
49
+ @@captcha_for_confirmation = false
46
50
 
47
51
  # Time period for account expiry from last_activity_at
48
52
  mattr_accessor :expire_after
@@ -1,6 +1,6 @@
1
1
  module DeviseSecurityExtension
2
- module Controllers # :nodoc:
3
- module Helpers # :nodoc:
2
+ module Controllers
3
+ module Helpers
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
@@ -10,22 +10,18 @@ module DeviseSecurityExtension
10
10
  module ClassMethods
11
11
  # helper for captcha
12
12
  def init_recover_password_captcha
13
- p "init"
14
- p self.inspect
15
-
16
13
  include RecoverPasswordCaptcha
17
14
  end
18
15
  end
19
16
 
20
17
  module RecoverPasswordCaptcha
21
18
  def new
22
- p "Check here captcha"
23
19
  super
24
20
  end
25
21
  end
26
22
 
27
23
  # controller instance methods
28
- module InstanceMethods
24
+
29
25
  private
30
26
 
31
27
  # lookup if an password change needed
@@ -60,7 +56,7 @@ module DeviseSecurityExtension
60
56
  false
61
57
  end
62
58
 
63
- end
59
+
64
60
  end
65
61
  end
66
62
 
@@ -18,51 +18,48 @@ module Devise
18
18
  module Expirable
19
19
  extend ActiveSupport::Concern
20
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
21
+ # Updates +last_activity_at+, called from a Warden::Manager.after_set_user hook.
22
+ def update_last_activitiy!
23
+ self.last_activity_at = Time.now.utc
24
+ save(:validate => false)
25
+ end
39
26
 
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
27
+ # Tells if the account has expired
28
+ #
29
+ # @return [bool]
30
+ def expired?
31
+ # expired_at set (manually, via cron, etc.)
32
+ return self.expired_at < Time.now.utc unless self.expired_at.nil?
33
+ # if it is not set, check the last activity against configured expire_after time range
34
+ return self.last_activity_at < self.class.expire_after.ago unless self.last_activity_at.nil?
35
+ # if last_activity_at is nil as well, the user has to be 'fresh' and is therefore not expired
36
+ false
37
+ end
50
38
 
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
39
+ # Expire an account. This is for cron jobs and manually expiring of accounts.
40
+ #
41
+ # @example
42
+ # User.expire!
43
+ # User.expire! 1.week.from_now
44
+ # @note +expired_at+ can be in the future as well
45
+ def expire!(at = Time.now.utc)
46
+ self.expired_at = at
47
+ save(:validate => false)
48
+ end
59
49
 
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
50
+ # Overwrites active_for_authentication? from Devise::Models::Activatable
51
+ # for verifying whether a user is active to sign in or not. If the account
52
+ # is expired, it should never be allowed.
53
+ #
54
+ # @return [bool]
55
+ def active_for_authentication?
56
+ super && !self.expired?
57
+ end
65
58
 
59
+ # The message sym, if {#active_for_authentication?} returns +false+. E.g. needed
60
+ # for i18n.
61
+ def inactive_message
62
+ !self.expired? ? super : :expired
66
63
  end
67
64
 
68
65
  module ClassMethods
@@ -1,3 +1,5 @@
1
1
  class OldPassword < ActiveRecord::Base
2
2
  belongs_to :password_archivable, :polymorphic => true
3
- end
3
+
4
+ attr_accessible :encrypted_password
5
+ end
@@ -1,68 +1,61 @@
1
- module Devise # :nodoc:
2
- module Models # :nodoc:
1
+ module Devise
2
+ module Models
3
3
 
4
4
  # PasswordArchivable
5
5
  module PasswordArchivable
6
+ extend ActiveSupport::Concern
6
7
 
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, :dependent => :destroy
13
- before_update :archive_password
14
- validate :validate_password_archive
15
- end
8
+ included do
9
+ has_many :old_passwords, :as => :password_archivable, :dependent => :destroy
10
+ before_update :archive_password
11
+ validate :validate_password_archive
16
12
  end
17
13
 
18
- module InstanceMethods # :nodoc:
19
-
20
- def validate_password_archive
21
- self.errors.add(:password, :taken_in_past) if encrypted_password_changed? and password_archive_included?
22
- end
14
+ def validate_password_archive
15
+ self.errors.add(:password, :taken_in_past) if encrypted_password_changed? and password_archive_included?
16
+ end
23
17
 
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
18
+ # validate is the password used in the past
19
+ def password_archive_included?
20
+ unless self.class.deny_old_passwords.is_a? Fixnum
21
+ if self.class.deny_old_passwords.is_a? TrueClass and self.class.password_archiving_count > 0
22
+ self.class.deny_old_passwords = self.class.password_archiving_count
23
+ else
24
+ self.class.deny_old_passwords = 0
32
25
  end
26
+ end
33
27
 
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 if dummy.respond_to?(:password_salt)
39
- return true if dummy.valid_password?(self.password)
40
- end
28
+ if self.class.deny_old_passwords > 0 and not self.password.nil?
29
+ self.old_passwords.reverse_order(:id).limit(self.class.deny_old_passwords).each do |old_password|
30
+ dummy = self.class.new
31
+ dummy.encrypted_password = old_password.encrypted_password
32
+ dummy.password_salt = old_password.password_salt if dummy.respond_to?(:password_salt)
33
+ return true if dummy.valid_password?(self.password)
41
34
  end
42
-
43
- false
44
35
  end
45
36
 
46
- private
37
+ false
38
+ end
39
+
40
+ private
47
41
 
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
- if self.respond_to?(:password_salt_change) and not self.password_salt_change.nil?
53
- self.old_passwords.create! :encrypted_password => self.encrypted_password_change.first, :password_salt => self.password_salt_change.first
54
- else
55
- self.old_passwords.create! :encrypted_password => self.encrypted_password_change.first
56
- end
57
- self.old_passwords.order('created_at DESC').offset(self.class.password_archiving_count).destroy_all
42
+ # archive the last password before save and delete all to old passwords from archive
43
+ def archive_password
44
+ if self.encrypted_password_changed?
45
+ if self.class.password_archiving_count.to_i > 0
46
+ if self.respond_to?(:password_salt_change) and not self.password_salt_change.nil?
47
+ self.old_passwords.create! :encrypted_password => self.encrypted_password_change.first, :password_salt => self.password_salt_change.first
58
48
  else
59
- self.old_passwords.destroy_all
49
+ self.old_passwords.create! :encrypted_password => self.encrypted_password_change.first
60
50
  end
51
+ self.old_passwords.reverse_order(:id).offset(self.class.password_archiving_count).destroy_all
52
+ else
53
+ self.old_passwords.destroy_all
61
54
  end
62
55
  end
63
56
  end
64
57
 
65
- module ClassMethods #:nodoc:
58
+ module ClassMethods
66
59
  ::Devise::Models.config(self, :password_archiving_count, :deny_old_passwords)
67
60
  end
68
61
  end
@@ -1,63 +1,57 @@
1
1
  require 'devise_security_extension/hooks/password_expirable'
2
2
 
3
- module Devise # :nodoc:
4
- module Models # :nodoc:
3
+ module Devise
4
+ module Models
5
5
 
6
6
  # PasswordExpirable takes care of change password after
7
7
  module PasswordExpirable
8
+ extend ActiveSupport::Concern
8
9
 
9
- def self.included(base) # :nodoc:
10
- base.extend ClassMethods
10
+ included do
11
+ before_save :update_password_changed
12
+ end
11
13
 
12
- base.class_eval do
13
- before_save :update_password_changed
14
- include InstanceMethods
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.password_changed_at.nil? or self.password_changed_at < self.class.expire_password_after.ago
18
+ else
19
+ false
15
20
  end
16
21
  end
17
22
 
18
- module InstanceMethods # :nodoc:
19
-
20
- # is an password change required?
21
- def need_change_password?
22
- if self.class.expire_password_after.is_a? Fixnum
23
- self.password_changed_at.nil? or self.password_changed_at < self.class.expire_password_after.ago
24
- else
25
- false
26
- end
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)
27
28
  end
29
+ end
28
30
 
29
- # set a fake datetime so a password change is needed and save the record
30
- def need_change_password!
31
- if self.class.expire_password_after.is_a? Fixnum
32
- need_change_password
33
- self.save(:validate => false)
34
- end
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.password_changed_at = self.class.expire_password_after.ago
35
35
  end
36
36
 
37
- # set a fake datetime so a password change is needed
38
- def need_change_password
39
- if self.class.expire_password_after.is_a? Fixnum
40
- self.password_changed_at = self.class.expire_password_after.ago
41
- end
42
-
43
- # is date not set it will set default to need set new password next login
44
- need_change_password if self.password_changed_at.nil?
37
+ # is date not set it will set default to need set new password next login
38
+ need_change_password if self.password_changed_at.nil?
45
39
 
46
- self.password_changed_at
47
- end
40
+ self.password_changed_at
41
+ end
48
42
 
49
- private
43
+ private
50
44
 
51
45
  # is password changed then update password_cahanged_at
52
46
  def update_password_changed
53
47
  self.password_changed_at = Time.now if (self.new_record? or self.encrypted_password_changed?) and not self.password_changed_at_changed?
54
48
  end
55
- end
56
49
 
57
- module ClassMethods #:nodoc:
50
+ module ClassMethods
58
51
  ::Devise::Models.config(self, :expire_password_after)
59
52
  end
60
53
  end
54
+
61
55
  end
62
56
 
63
57
  end
@@ -11,6 +11,7 @@ module Devise
11
11
  # * +password_regex+: need strong password. Defaults to /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/
12
12
  #
13
13
  module SecureValidatable
14
+
14
15
  def self.included(base)
15
16
  base.extend ClassMethods
16
17
  assert_secure_validations_api!(base)
@@ -22,6 +23,7 @@ module Devise
22
23
 
23
24
  # validates email
24
25
  validates :email, :presence => true, :if => :email_required?
26
+ validates :email, :uniqueness => true, :allow_blank => true, :if => :email_changed? # check uniq for email ever
25
27
  validates :email, :email => email_validation if email_validation # use rails_email_validator or similar
26
28
 
27
29
  # validates password
@@ -32,7 +34,7 @@ module Devise
32
34
  end
33
35
  end
34
36
 
35
- def self.assert_secure_validations_api!(base) #:nodoc:
37
+ def self.assert_secure_validations_api!(base)
36
38
  raise "Could not use SecureValidatable on #{base}" unless base.respond_to?(:validates)
37
39
  end
38
40
 
@@ -1,7 +1,7 @@
1
1
  require 'devise_security_extension/hooks/session_limitable'
2
2
 
3
- module Devise # :nodoc:
4
- module Models # :nodoc:
3
+ module Devise
4
+ module Models
5
5
  # SessionLimited ensures, that there is only one session usable per account at once.
6
6
  # If someone logs in, and some other is logging in with the same credentials,
7
7
  # the session from the first one is invalidated and not usable anymore.
@@ -1,13 +1,18 @@
1
1
  module DeviseSecurityExtension
2
2
  module Patches
3
- autoload :ControllerCaptcha, 'devise_security_extension/patches/controller_captcha'
3
+ autoload :UnlocksControllerCaptcha, 'devise_security_extension/patches/unlocks_controller_captcha'
4
+ autoload :PasswordsControllerCaptcha, 'devise_security_extension/patches/passwords_controller_captcha'
5
+ autoload :SessionsControllerCaptcha, 'devise_security_extension/patches/sessions_controller_captcha'
6
+ autoload :RegistrationsControllerCaptcha, 'devise_security_extension/patches/registrations_controller_captcha'
7
+ autoload :ConfirmationsControllerCaptcha, 'devise_security_extension/patches/confirmations_controller_captcha'
4
8
 
5
9
  class << self
6
10
  def apply
7
- Devise::PasswordsController.send(:include, Patches::ControllerCaptcha) if Devise.captcha_for_recover
8
- Devise::UnlocksController.send(:include, Patches::ControllerCaptcha) if Devise.captcha_for_unlock
9
- Devise::RegistrationsController.send(:include, Patches::ControllerCaptcha) if Devise.captcha_for_sign_up
10
- Devise::SessionsController.send(:include, Patches::ControllerCaptcha) if Devise.captcha_for_sign_in
11
+ Devise::PasswordsController.send(:include, Patches::PasswordsControllerCaptcha) if Devise.captcha_for_recover
12
+ Devise::UnlocksController.send(:include, Patches::UnlocksControllerCaptcha) if Devise.captcha_for_unlock
13
+ Devise::RegistrationsController.send(:include, Patches::RegistrationsControllerCaptcha) if Devise.captcha_for_sign_up
14
+ Devise::SessionsController.send(:include, Patches::SessionsControllerCaptcha) if Devise.captcha_for_sign_in
15
+ Devise::ConfirmationsController.send(:include, Patches::ConfirmationsControllerCaptcha) if Devise.captcha_for_confirmation
11
16
  end
12
17
  end
13
18
  end
@@ -0,0 +1,21 @@
1
+ module DeviseSecurityExtension::Patches
2
+ module ConfirmationsControllerCaptcha
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ define_method :create do
6
+ if valid_captcha? params[:captcha]
7
+ self.resource = resource_class.send_confirmation_instructions(params[resource_name])
8
+
9
+ if successfully_sent?(resource)
10
+ respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
11
+ else
12
+ respond_with(resource)
13
+ end
14
+ else
15
+ flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
16
+ respond_with({}, :location => new_confirmation_path(resource_name))
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module DeviseSecurityExtension::Patches
2
+ module PasswordsControllerCaptcha
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ define_method :create do
6
+ if valid_captcha? params[:captcha]
7
+ self.resource = resource_class.send_reset_password_instructions(params[resource_name])
8
+ if successfully_sent?(resource)
9
+ respond_with({}, :location => new_session_path(resource_name))
10
+ else
11
+ respond_with(resource)
12
+ end
13
+ else
14
+ flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
15
+ respond_with({}, :location => new_password_path(resource_name))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module DeviseSecurityExtension::Patches
2
+ module RegistrationsControllerCaptcha
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ define_method :create do
6
+ build_resource
7
+
8
+ if valid_captcha? params[:captcha]
9
+
10
+ if resource.save
11
+ if resource.active_for_authentication?
12
+ set_flash_message :notice, :signed_up if is_navigational_format?
13
+ sign_in(resource_name, resource)
14
+ respond_with resource, :location => after_sign_up_path_for(resource)
15
+ else
16
+ set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
17
+ expire_session_data_after_sign_in!
18
+ respond_with resource, :location => after_inactive_sign_up_path_for(resource)
19
+ end
20
+ else
21
+ clean_up_passwords resource
22
+ respond_with resource
23
+ end
24
+
25
+ else
26
+ resource.errors.add :base, t('devise.invalid_captcha')
27
+ clean_up_passwords resource
28
+ respond_with resource
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ module DeviseSecurityExtension::Patches
2
+ module SessionsControllerCaptcha
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ define_method :create do
6
+ if valid_captcha? params[:captcha]
7
+ resource = warden.authenticate!(auth_options)
8
+ set_flash_message(:notice, :signed_in) if is_navigational_format?
9
+ sign_in(resource_name, resource)
10
+ respond_with resource, :location => after_sign_in_path_for(resource)
11
+ else
12
+ flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
13
+ respond_with({}, :location => new_session_path(resource_name))
14
+ end
15
+ end
16
+
17
+ # for bad protected use in controller
18
+ define_method :auth_options do
19
+ { :scope => resource_name, :recall => "#{controller_path}#new" }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module DeviseSecurityExtension::Patches
2
+ module UnlocksControllerCaptcha
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ define_method :create do
6
+ if valid_captcha? params[:captcha]
7
+ self.resource = resource_class.send_unlock_instructions(params[resource_name])
8
+ if successfully_sent?(resource)
9
+ respond_with({}, :location => new_session_path(resource_name))
10
+ else
11
+ respond_with(resource)
12
+ end
13
+ else
14
+ flash[:alert] = t('devise.invalid_captcha') if is_navigational_format?
15
+ respond_with({}, :location => new_unlock_path(resource_name))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module DeviseSecurityExtension
2
- class Engine < ::Rails::Engine # :nodoc:
2
+ class Engine < ::Rails::Engine
3
3
  ActiveSupport.on_load(:action_controller) do
4
4
  include DeviseSecurityExtension::Controllers::Helpers
5
5
  end
@@ -1,5 +1,5 @@
1
- module ActionDispatch::Routing # :nodoc:
2
- class Mapper # :nodoc:
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
3
 
4
4
  protected
5
5
 
@@ -1,5 +1,5 @@
1
1
  module DeviseSecurityExtension
2
- module Generators # :nodoc:
2
+ module Generators
3
3
  # Install Generator
4
4
  class InstallGenerator < Rails::Generators::Base
5
5
  source_root File.expand_path("../../templates", __FILE__)
@@ -27,9 +27,10 @@ module DeviseSecurityExtension
27
27
  " # config.captcha_for_sign_in = true\n\n" +
28
28
  " # captcha integration for unlock form\n" +
29
29
  " # config.captcha_for_unlock = true\n\n" +
30
- " # ==> Configuration for :expirable\n" +
30
+ " # captcha integration for confirmation form\n" +
31
+ " # config.captcha_for_confirmation = true\n\n" +
31
32
  " # Time period for account expiry from last_activity_at\n" +
32
- " config.expire_after = 90.days\n" +
33
+ " # config.expire_after = 90.days\n\n" +
33
34
  "", :before => /end[ |\n|]+\Z/
34
35
  end
35
36
 
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.6.0
4
+ version: 0.6.1
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-28 00:00:00.000000000 Z
13
+ date: 2012-06-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
17
- requirement: &21216320 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,21 +22,31 @@ dependencies:
22
22
  version: 3.1.1
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *21216320
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: 3.1.1
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: devise
28
- requirement: &21234920 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ! '>='
32
37
  - !ruby/object:Gem::Version
33
- version: '0'
38
+ version: 2.0.0
34
39
  type: :runtime
35
40
  prerelease: false
36
- version_requirements: *21234920
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 2.0.0
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rails_email_validator
39
- requirement: &21250840 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ! '>='
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: '0'
45
55
  type: :development
46
56
  prerelease: false
47
- version_requirements: *21250840
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: easy_captcha
50
- requirement: &21246220 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,10 +70,15 @@ dependencies:
55
70
  version: '0'
56
71
  type: :development
57
72
  prerelease: false
58
- version_requirements: *21246220
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
59
79
  - !ruby/object:Gem::Dependency
60
80
  name: bundler
61
- requirement: &21243800 !ruby/object:Gem::Requirement
81
+ requirement: !ruby/object:Gem::Requirement
62
82
  none: false
63
83
  requirements:
64
84
  - - ~>
@@ -66,10 +86,15 @@ dependencies:
66
86
  version: 1.0.0
67
87
  type: :development
68
88
  prerelease: false
69
- version_requirements: *21243800
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: 1.0.0
70
95
  - !ruby/object:Gem::Dependency
71
96
  name: jeweler
72
- requirement: &21268580 !ruby/object:Gem::Requirement
97
+ requirement: !ruby/object:Gem::Requirement
73
98
  none: false
74
99
  requirements:
75
100
  - - ~>
@@ -77,7 +102,12 @@ dependencies:
77
102
  version: 1.5.2
78
103
  type: :development
79
104
  prerelease: false
80
- version_requirements: *21268580
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.5.2
81
111
  description: An enterprise security extension for devise, trying to meet industrial
82
112
  standard security demands for web applications.
83
113
  email: team@phatworx.de
@@ -112,7 +142,11 @@ files:
112
142
  - lib/devise_security_extension/models/session_limitable.rb
113
143
  - lib/devise_security_extension/orm/active_record.rb
114
144
  - lib/devise_security_extension/patches.rb
115
- - lib/devise_security_extension/patches/controller_captcha.rb
145
+ - lib/devise_security_extension/patches/confirmations_controller_captcha.rb
146
+ - lib/devise_security_extension/patches/passwords_controller_captcha.rb
147
+ - lib/devise_security_extension/patches/registrations_controller_captcha.rb
148
+ - lib/devise_security_extension/patches/sessions_controller_captcha.rb
149
+ - lib/devise_security_extension/patches/unlocks_controller_captcha.rb
116
150
  - lib/devise_security_extension/rails.rb
117
151
  - lib/devise_security_extension/routes.rb
118
152
  - lib/devise_security_extension/schema.rb
@@ -134,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
168
  version: '0'
135
169
  segments:
136
170
  - 0
137
- hash: -3314141216685045721
171
+ hash: -3249260859492066288
138
172
  required_rubygems_version: !ruby/object:Gem::Requirement
139
173
  none: false
140
174
  requirements:
@@ -143,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
177
  version: '0'
144
178
  requirements: []
145
179
  rubyforge_project:
146
- rubygems_version: 1.8.10
180
+ rubygems_version: 1.8.21
147
181
  signing_key:
148
182
  specification_version: 3
149
183
  summary: Security extension for devise
@@ -1,21 +0,0 @@
1
- module DeviseSecurityExtension::Patches
2
- # patch passwords controller for captcha
3
- module ControllerCaptcha
4
- extend ActiveSupport::Concern
5
- included do
6
- # here the patch
7
-
8
- alias_method :create_without_captcha_check, :create
9
- define_method :create do
10
- if valid_captcha? params[:captcha]
11
- create_without_captcha_check
12
- else
13
- build_resource
14
- clean_up_passwords(resource)
15
- flash[:alert] = I18n.translate('devise.invalid_captcha')
16
- render_with_scope :new
17
- end
18
- end
19
- end
20
- end
21
- end