devise 1.1.rc1 → 1.1.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (93) hide show
  1. data/CHANGELOG.rdoc +63 -27
  2. data/Gemfile +15 -13
  3. data/README.rdoc +63 -51
  4. data/Rakefile +3 -2
  5. data/TODO +1 -0
  6. data/app/controllers/devise/registrations_controller.rb +1 -1
  7. data/app/mailers/devise/mailer.rb +43 -43
  8. data/app/views/devise/confirmations/new.html.erb +2 -2
  9. data/app/views/devise/passwords/edit.html.erb +4 -4
  10. data/app/views/devise/passwords/new.html.erb +2 -2
  11. data/app/views/devise/registrations/edit.html.erb +8 -8
  12. data/app/views/devise/registrations/new.html.erb +6 -6
  13. data/app/views/devise/sessions/new.html.erb +4 -4
  14. data/app/views/devise/unlocks/new.html.erb +2 -2
  15. data/config/locales/en.yml +7 -4
  16. data/lib/devise.rb +33 -6
  17. data/lib/devise/controllers/helpers.rb +38 -2
  18. data/lib/devise/encryptors/authlogic_sha512.rb +0 -2
  19. data/lib/devise/encryptors/bcrypt.rb +0 -2
  20. data/lib/devise/encryptors/clearance_sha1.rb +0 -2
  21. data/lib/devise/encryptors/sha1.rb +6 -8
  22. data/lib/devise/encryptors/sha512.rb +6 -8
  23. data/lib/devise/failure_app.rb +3 -2
  24. data/lib/devise/hooks/activatable.rb +4 -1
  25. data/lib/devise/hooks/forgetable.rb +4 -3
  26. data/lib/devise/hooks/rememberable.rb +6 -2
  27. data/lib/devise/hooks/timeoutable.rb +6 -2
  28. data/lib/devise/mapping.rb +7 -8
  29. data/lib/devise/models.rb +0 -34
  30. data/lib/devise/models/authenticatable.rb +29 -3
  31. data/lib/devise/models/confirmable.rb +3 -2
  32. data/lib/devise/models/database_authenticatable.rb +4 -2
  33. data/lib/devise/models/lockable.rb +1 -1
  34. data/lib/devise/models/recoverable.rb +1 -1
  35. data/lib/devise/models/rememberable.rb +9 -1
  36. data/lib/devise/orm/active_record.rb +4 -6
  37. data/lib/devise/orm/data_mapper.rb +5 -7
  38. data/lib/devise/orm/mongoid.rb +2 -13
  39. data/lib/devise/path_checker.rb +13 -0
  40. data/lib/devise/rails.rb +45 -18
  41. data/lib/devise/rails/routes.rb +24 -7
  42. data/lib/devise/schema.rb +23 -19
  43. data/lib/devise/strategies/authenticatable.rb +20 -4
  44. data/lib/devise/strategies/database_authenticatable.rb +1 -1
  45. data/lib/devise/strategies/token_authenticatable.rb +2 -2
  46. data/lib/devise/test_helpers.rb +2 -1
  47. data/lib/devise/version.rb +1 -1
  48. data/lib/generators/devise/devise/devise_generator.rb +86 -0
  49. data/lib/generators/devise/{templates → devise/templates}/migration.rb +2 -2
  50. data/lib/generators/devise/install/install_generator.rb +24 -0
  51. data/lib/generators/{devise_install → devise/install}/templates/README +1 -1
  52. data/lib/generators/{devise_install → devise/install}/templates/devise.rb +37 -18
  53. data/lib/generators/devise/views/views_generator.rb +63 -0
  54. data/lib/generators/devise_generator.rb +2 -0
  55. data/lib/generators/devise_install_generator.rb +4 -0
  56. data/lib/generators/devise_views_generator.rb +4 -0
  57. data/test/controllers/helpers_test.rb +15 -0
  58. data/test/devise_test.rb +1 -0
  59. data/test/failure_app_test.rb +25 -10
  60. data/test/integration/authenticatable_test.rb +279 -0
  61. data/test/integration/database_authenticatable_test.rb +2 -262
  62. data/test/integration/http_authenticatable_test.rb +7 -9
  63. data/test/integration/registerable_test.rb +14 -2
  64. data/test/integration/rememberable_test.rb +15 -3
  65. data/test/integration/timeoutable_test.rb +12 -0
  66. data/test/integration/token_authenticatable_test.rb +2 -3
  67. data/test/mailers/confirmation_instructions_test.rb +2 -2
  68. data/test/mailers/reset_password_instructions_test.rb +2 -2
  69. data/test/mailers/unlock_instructions_test.rb +3 -3
  70. data/test/models/confirmable_test.rb +16 -0
  71. data/test/models/database_authenticatable_test.rb +20 -20
  72. data/test/models/lockable_test.rb +1 -1
  73. data/test/models/rememberable_test.rb +4 -4
  74. data/test/orm/data_mapper.rb +9 -0
  75. data/test/rails_app/app/active_record/shim.rb +2 -0
  76. data/test/rails_app/app/controllers/application_controller.rb +1 -0
  77. data/test/rails_app/app/controllers/home_controller.rb +3 -0
  78. data/test/rails_app/app/controllers/users_controller.rb +2 -0
  79. data/test/rails_app/app/data_mapper/shim.rb +2 -0
  80. data/test/rails_app/app/data_mapper/user.rb +4 -5
  81. data/test/rails_app/app/mongoid/admin.rb +1 -10
  82. data/test/rails_app/app/mongoid/shim.rb +16 -0
  83. data/test/rails_app/app/mongoid/user.rb +1 -12
  84. data/test/rails_app/config/application.rb +2 -0
  85. data/test/rails_app/config/initializers/devise.rb +2 -2
  86. data/test/rails_app/config/routes.rb +6 -1
  87. data/test/routes_test.rb +2 -2
  88. data/test/test_helper.rb +0 -4
  89. data/test/test_helpers_test.rb +1 -0
  90. metadata +113 -12
  91. data/lib/generators/devise/devise_generator.rb +0 -67
  92. data/lib/generators/devise_install/devise_install_generator.rb +0 -25
  93. data/lib/generators/devise_views/devise_views_generator.rb +0 -62
@@ -5,12 +5,16 @@
5
5
  # verify timeout in the following request.
6
6
  Warden::Manager.after_set_user do |record, warden, options|
7
7
  scope = options[:scope]
8
+
8
9
  if record && record.respond_to?(:timedout?) && warden.authenticated?(scope)
9
10
  last_request_at = warden.session(scope)['last_request_at']
10
11
 
11
12
  if record.timedout?(last_request_at)
12
- warden.logout(scope)
13
- throw :warden, :scope => scope, :message => :timeout
13
+ path_checker = Devise::PathChecker.new(warden.env, scope)
14
+ unless path_checker.signing_out?
15
+ warden.logout(scope)
16
+ throw :warden, :scope => scope, :message => :timeout
17
+ end
14
18
  end
15
19
 
16
20
  warden.session(scope)['last_request_at'] = Time.now.utc
@@ -22,7 +22,7 @@ module Devise
22
22
  # # is the modules included in the class
23
23
  #
24
24
  class Mapping #:nodoc:
25
- attr_reader :singular, :plural, :path, :controllers, :path_names, :path_prefix
25
+ attr_reader :singular, :plural, :path, :controllers, :path_names, :path_prefix, :class_name
26
26
  alias :name :singular
27
27
 
28
28
  # Loop through all mappings looking for a map that matches with the requested
@@ -63,30 +63,29 @@ module Devise
63
63
 
64
64
  @plural = name.to_sym
65
65
  @path = (options.delete(:path) || name).to_sym
66
- @klass = (options.delete(:class_name) || name.to_s.classify).to_s
67
66
  @singular = (options.delete(:singular) || name.to_s.singularize).to_sym
68
67
 
68
+ @class_name = (options.delete(:class_name) || name.to_s.classify).to_s
69
+ @ref = ActiveSupport::Dependencies.ref(@class_name)
70
+
69
71
  @path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
70
72
 
71
73
  @controllers = Hash.new { |h,k| h[k] = "devise/#{k}" }
72
74
  @controllers.merge!(options.delete(:controllers) || {})
73
75
 
74
76
  @path_names = Hash.new { |h,k| h[k] = k.to_s }
77
+ @path_names.merge!(:registration => "")
75
78
  @path_names.merge!(options.delete(:path_names) || {})
76
79
  end
77
80
 
78
81
  # Return modules for the mapping.
79
82
  def modules
80
- @modules ||= to.devise_modules
83
+ @modules ||= to.respond_to?(:devise_modules) ? to.devise_modules : []
81
84
  end
82
85
 
83
86
  # Gives the class the mapping points to.
84
- # Reload mapped class each time when cache_classes is false.
85
87
  def to
86
- return @to if @to
87
- klass = @klass.constantize
88
- @to = klass if Rails.configuration.cache_classes
89
- klass
88
+ @ref.get
90
89
  end
91
90
 
92
91
  def strategies
@@ -1,17 +1,5 @@
1
1
  module Devise
2
2
  module Models
3
- class << self
4
- def hook(base)
5
- base.class_eval do
6
- class_attribute :devise_modules, :instance_writer => false
7
- self.devise_modules ||= []
8
- end
9
- end
10
-
11
- alias :included :hook
12
- alias :extended :hook
13
- end
14
-
15
3
  # Creates configuration values for Devise and for the given module.
16
4
  #
17
5
  # Devise::Models.config(Devise::Authenticable, :stretches, 10)
@@ -86,28 +74,6 @@ module Devise
86
74
  def devise_modules_hook!
87
75
  yield
88
76
  end
89
-
90
- # Find an initialize a record setting an error if it can't be found.
91
- def find_or_initialize_with_error_by(attribute, value, error=:invalid)
92
- if value.present?
93
- conditions = { attribute => value }
94
- record = find(:first, :conditions => conditions)
95
- end
96
-
97
- unless record
98
- record = new
99
-
100
- if value.present?
101
- record.send(:"#{attribute}=", value)
102
- else
103
- error = :blank
104
- end
105
-
106
- record.errors.add(attribute, error)
107
- end
108
-
109
- record
110
- end
111
77
  end
112
78
  end
113
79
 
@@ -39,10 +39,16 @@ module Devise
39
39
  module Authenticatable
40
40
  extend ActiveSupport::Concern
41
41
 
42
- # Check if the current object is valid for authentication. This method and find_for_authentication
43
- # are the methods used in a Warden::Strategy to check if a model should be signed in or not.
42
+ included do
43
+ class_attribute :devise_modules, :instance_writer => false
44
+ self.devise_modules ||= []
45
+ end
46
+
47
+ # Check if the current object is valid for authentication. This method and
48
+ # find_for_authentication are the methods used in a Warden::Strategy to check
49
+ # if a model should be signed in or not.
44
50
  #
45
- # However, you should not need to overwrite this method, you should overwrite active? and
51
+ # However, you should not overwrite this method, you should overwrite active? and
46
52
  # inactive_message instead.
47
53
  def valid_for_authentication?
48
54
  if active?
@@ -86,6 +92,26 @@ module Devise
86
92
  def find_for_authentication(conditions)
87
93
  find(:first, :conditions => conditions)
88
94
  end
95
+
96
+ # Find an initialize a record setting an error if it can't be found.
97
+ def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
98
+ if value.present?
99
+ conditions = { attribute => value }
100
+ record = find(:first, :conditions => conditions)
101
+ end
102
+
103
+ unless record
104
+ record = new
105
+ if value.present?
106
+ record.send(:"#{attribute}=", value)
107
+ else
108
+ error = :blank
109
+ end
110
+ record.errors.add(attribute, error)
111
+ end
112
+
113
+ record
114
+ end
89
115
  end
90
116
  end
91
117
  end
@@ -50,7 +50,8 @@ module Devise
50
50
 
51
51
  # Send confirmation instructions by email
52
52
  def send_confirmation_instructions
53
- ::Devise::Mailer.confirmation_instructions(self).deliver
53
+ generate_confirmation_token if self.confirmation_token.nil?
54
+ ::Devise.mailer.confirmation_instructions(self).deliver
54
55
  end
55
56
 
56
57
  # Resend confirmation token. This method does not need to generate a new token.
@@ -63,7 +64,7 @@ module Devise
63
64
  # is already confirmed, it should never be blocked. Otherwise we need to
64
65
  # calculate if the confirm time has not expired for this user.
65
66
  def active?
66
- super && (confirmed? || confirmation_period_valid?)
67
+ super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
67
68
  end
68
69
 
69
70
  # The message to be shown if the account is inactive.
@@ -58,8 +58,10 @@ module Devise
58
58
  def update_with_password(params={})
59
59
  current_password = params.delete(:current_password)
60
60
 
61
- params.delete(:password) if params[:password].blank?
62
- params.delete(:password_confirmation) if params[:password_confirmation].blank?
61
+ if params[:password].blank?
62
+ params.delete(:password)
63
+ params.delete(:password_confirmation) if params[:password_confirmation].blank?
64
+ end
63
65
 
64
66
  result = if valid_password?(current_password)
65
67
  update_attributes(params)
@@ -49,7 +49,7 @@ module Devise
49
49
 
50
50
  # Send unlock instructions by email
51
51
  def send_unlock_instructions
52
- ::Devise::Mailer.unlock_instructions(self).deliver
52
+ ::Devise.mailer.unlock_instructions(self).deliver
53
53
  end
54
54
 
55
55
  # Resend the unlock instructions if the user is locked.
@@ -28,7 +28,7 @@ module Devise
28
28
  # Resets reset password token and send reset password instructions by email
29
29
  def send_reset_password_instructions
30
30
  generate_reset_password_token!
31
- ::Devise::Mailer.reset_password_instructions(self).deliver
31
+ ::Devise.mailer.reset_password_instructions(self).deliver
32
32
  end
33
33
 
34
34
  protected
@@ -65,6 +65,14 @@ module Devise
65
65
  remember_created_at + self.class.remember_for
66
66
  end
67
67
 
68
+ def cookie_domain
69
+ self.class.cookie_domain
70
+ end
71
+
72
+ def cookie_domain?
73
+ self.class.cookie_domain != false
74
+ end
75
+
68
76
  module ClassMethods
69
77
  # Create the cookie key using the record id and remember_token
70
78
  def serialize_into_cookie(record)
@@ -78,7 +86,7 @@ module Devise
78
86
  record if record && !record.remember_expired?
79
87
  end
80
88
 
81
- Devise::Models.config(self, :remember_for)
89
+ Devise::Models.config(self, :remember_for, :cookie_domain)
82
90
  end
83
91
  end
84
92
  end
@@ -23,7 +23,7 @@ module Devise
23
23
  include Devise::Schema
24
24
 
25
25
  # Tell how to apply schema methods.
26
- def apply_schema(name, type, options={})
26
+ def apply_devise_schema(name, type, options={})
27
27
  column name, type.to_s.downcase.to_sym, options
28
28
  end
29
29
  end
@@ -31,8 +31,6 @@ module Devise
31
31
  end
32
32
  end
33
33
 
34
- if defined?(ActiveRecord)
35
- ActiveRecord::Base.extend Devise::Models
36
- ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord::Schema
37
- ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord::Schema
38
- end
34
+ ActiveRecord::Base.extend Devise::Models
35
+ ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord::Schema
36
+ ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord::Schema
@@ -21,7 +21,7 @@ module Devise
21
21
 
22
22
  # Tell how to apply schema methods. This automatically maps :limit to
23
23
  # :length and :null to :required.
24
- def apply_schema(name, type, options={})
24
+ def apply_devise_schema(name, type, options={})
25
25
  SCHEMA_OPTIONS.each do |old_key, new_key|
26
26
  next unless options.key?(old_key)
27
27
  options[new_key] = options.delete(old_key)
@@ -72,7 +72,7 @@ module Devise
72
72
  end
73
73
  end
74
74
  end
75
-
75
+
76
76
  def changed?
77
77
  dirty?
78
78
  end
@@ -84,7 +84,7 @@ module Devise
84
84
  super()
85
85
  end
86
86
  end
87
-
87
+
88
88
  def update_attributes(*args)
89
89
  update(*args)
90
90
  end
@@ -93,7 +93,5 @@ module Devise
93
93
  end
94
94
  end
95
95
 
96
- DataMapper::Model.class_eval do
97
- include Devise::Models
98
- include Devise::Orm::DataMapper::Hook
99
- end
96
+ DataMapper::Model.append_extensions(Devise::Models)
97
+ DataMapper::Model.append_extensions(Devise::Orm::DataMapper::Hook)
@@ -4,32 +4,21 @@ module Devise
4
4
  module Hook
5
5
  def devise_modules_hook!
6
6
  extend Schema
7
- include ::Mongoid::Timestamps
8
- include Compatibility
9
7
  yield
10
8
  return unless Devise.apply_schema
11
9
  devise_modules.each { |m| send(m) if respond_to?(m, true) }
12
10
  end
13
11
  end
14
-
12
+
15
13
  module Schema
16
14
  include Devise::Schema
17
15
 
18
16
  # Tell how to apply schema methods
19
- def apply_schema(name, type, options={})
17
+ def apply_devise_schema(name, type, options={})
20
18
  type = Time if type == DateTime
21
19
  field name, { :type => type }.merge(options)
22
20
  end
23
21
  end
24
-
25
- module Compatibility
26
- def save(validate = true)
27
- if validate.is_a?(Hash) && validate.has_key?(:validate)
28
- validate = validate[:validate]
29
- end
30
- super(validate)
31
- end
32
- end
33
22
  end
34
23
  end
35
24
  end
@@ -0,0 +1,13 @@
1
+ module Devise
2
+ class PathChecker
3
+ include Rails.application.routes.url_helpers
4
+
5
+ def initialize(env, scope)
6
+ @env, @scope = env, scope
7
+ end
8
+
9
+ def signing_out?
10
+ @env["PATH_INFO"] == send("destroy_#{@scope}_session_path")
11
+ end
12
+ end
13
+ end
@@ -1,35 +1,62 @@
1
1
  require 'devise/rails/routes'
2
2
  require 'devise/rails/warden_compat'
3
3
 
4
+ # Include UrlHelpers in ActionController and ActionView as soon as they are loaded.
5
+ ActiveSupport.on_load(:action_controller) { include Devise::Controllers::UrlHelpers }
6
+ ActiveSupport.on_load(:action_view) { include Devise::Controllers::UrlHelpers }
7
+
4
8
  module Devise
5
9
  class Engine < ::Rails::Engine
6
10
  config.devise = Devise
7
11
 
8
- initializer "devise.add_middleware" do |app|
9
- app.config.middleware.use Warden::Manager do |config|
10
- Devise.warden_config = config
11
- config.failure_app = Devise::FailureApp
12
- config.default_scope = Devise.default_scope
13
- end
12
+ config.app_middleware.use Warden::Manager do |config|
13
+ Devise.warden_config = config
14
14
  end
15
15
 
16
- initializer "devise.add_url_helpers" do |app|
17
- Devise::FailureApp.send :include, app.routes.url_helpers
18
- ActionController::Base.send :include, Devise::Controllers::UrlHelpers
19
- ActionView::Base.send :include, Devise::Controllers::UrlHelpers
20
- end
16
+ # Force routes to be loaded if we are doing any eager load.
17
+ config.before_eager_load { |app| app.reload_routes! }
21
18
 
22
19
  config.after_initialize do
23
- I18n.available_locales
24
- flash = [:unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked]
20
+ Devise.encryptor ||= begin
21
+ warn "[WARNING] config.encryptor is not set in your config/initializers/devise.rb. " \
22
+ "Devise will then set it to :bcrypt. If you were using the previous default " \
23
+ "encryptor, please add config.encryptor = :sha1 to your configuration file."
24
+ :bcrypt
25
+ end
26
+ end
27
+
28
+ unless Rails.env.production?
29
+ config.after_initialize do
30
+ actions = [:confirmation_instructions, :reset_password_instructions, :unlock_instructions]
31
+
32
+ translations = begin
33
+ I18n.t("devise.mailer", :raise => true).map { |k, v| k if v.is_a?(String) }.compact
34
+ rescue Exception => e # Do not care if something fails
35
+ []
36
+ end
37
+
38
+ keys = actions & translations
39
+
40
+ keys.each do |key|
41
+ ActiveSupport::Deprecation.warn "The I18n message 'devise.mailer.#{key}' is deprecated. " \
42
+ "Please use 'devise.mailer.#{key}.subject' instead."
43
+ end
44
+ end
45
+
46
+ config.after_initialize do
47
+ flash = [:unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked]
48
+
49
+ translations = begin
50
+ I18n.t("devise.sessions", :raise => true).keys
51
+ rescue Exception => e # Do not care if something fails
52
+ []
53
+ end
25
54
 
26
- I18n.backend.send(:translations).each do |locale, translations|
27
- keys = flash & (translations[:devise][:sessions].keys) rescue []
55
+ keys = flash & translations
28
56
 
29
57
  if keys.any?
30
- ActiveSupport::Deprecation.warn "The following I18n messages in 'devise.sessions' " <<
31
- "for locale '#{locale}' are deprecated: #{keys.to_sentence}. Please move them to " <<
32
- "'devise.failure' instead."
58
+ ActiveSupport::Deprecation.warn "The following I18n messages in 'devise.sessions' " \
59
+ "are deprecated: #{keys.to_sentence}. Please move them to 'devise.failure' instead."
33
60
  end
34
61
  end
35
62
  end
@@ -89,12 +89,13 @@ module ActionDispatch::Routing
89
89
  resources.map!(&:to_sym)
90
90
 
91
91
  resources.each do |resource|
92
- mapping = Devise.register(resource, options)
92
+ mapping = Devise.add_model(resource, options)
93
93
 
94
- unless mapping.to.respond_to?(:devise)
95
- raise "#{mapping.to.name} does not respond to 'devise' method. This usually means you haven't " <<
96
- "loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " <<
97
- "inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
94
+ begin
95
+ raise_no_devise_method_error!(mapping.class_name) unless mapping.to.respond_to?(:devise)
96
+ rescue NoMethodError => e
97
+ raise unless e.message.include?("undefined method `devise'")
98
+ raise_no_devise_method_error!(mapping.class_name)
98
99
  end
99
100
 
100
101
  routes = mapping.routes
@@ -106,6 +107,16 @@ module ActionDispatch::Routing
106
107
  end
107
108
  end
108
109
 
110
+ def authenticate(scope)
111
+ constraint = lambda do |request|
112
+ request.env["warden"].authenticate!(:scope => scope)
113
+ end
114
+
115
+ constraints(constraint) do
116
+ yield
117
+ end
118
+ end
119
+
109
120
  protected
110
121
 
111
122
  def devise_session(mapping, controllers)
@@ -136,9 +147,15 @@ module ActionDispatch::Routing
136
147
 
137
148
  def devise_registration(mapping, controllers)
138
149
  scope mapping.full_path[1..-1], :name_prefix => mapping.name do
139
- resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => "",
150
+ resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => mapping.path_names[:registration],
140
151
  :path_names => { :new => mapping.path_names[:sign_up] }, :controller => controllers[:registrations]
141
152
  end
142
153
  end
154
+
155
+ def raise_no_devise_method_error!(klass)
156
+ raise "#{klass} does not respond to 'devise' method. This usually means you haven't " <<
157
+ "loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " <<
158
+ "inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
159
+ end
143
160
  end
144
- end
161
+ end