devise_security_extension 0.6.0 → 0.6.1

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/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