devise 1.1.pre4 → 1.1.rc0

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.
Files changed (122) hide show
  1. data/CHANGELOG.rdoc +31 -2
  2. data/Gemfile +15 -6
  3. data/README.rdoc +12 -16
  4. data/Rakefile +2 -2
  5. data/TODO +2 -1
  6. data/app/controllers/devise/confirmations_controller.rb +1 -1
  7. data/app/controllers/devise/passwords_controller.rb +2 -3
  8. data/app/controllers/devise/registrations_controller.rb +5 -5
  9. data/app/controllers/devise/sessions_controller.rb +5 -27
  10. data/app/controllers/devise/unlocks_controller.rb +9 -1
  11. data/app/models/devise/mailer.rb +17 -11
  12. data/app/views/devise/confirmations/new.html.erb +1 -1
  13. data/app/views/devise/passwords/edit.html.erb +1 -1
  14. data/app/views/devise/passwords/new.html.erb +1 -1
  15. data/app/views/devise/registrations/edit.html.erb +2 -2
  16. data/app/views/devise/registrations/new.html.erb +2 -2
  17. data/app/views/devise/sessions/new.html.erb +2 -2
  18. data/app/views/devise/shared/_links.erb +5 -5
  19. data/app/views/devise/unlocks/new.html.erb +1 -1
  20. data/config/locales/en.yml +4 -9
  21. data/lib/devise.rb +83 -42
  22. data/lib/devise/controllers/helpers.rb +6 -18
  23. data/lib/devise/controllers/internal_helpers.rb +11 -12
  24. data/lib/devise/controllers/scoped_views.rb +2 -2
  25. data/lib/devise/controllers/url_helpers.rb +1 -1
  26. data/lib/devise/failure_app.rb +56 -16
  27. data/lib/devise/hooks/activatable.rb +18 -6
  28. data/lib/devise/hooks/rememberable.rb +36 -27
  29. data/lib/devise/hooks/timeoutable.rb +1 -1
  30. data/lib/devise/hooks/trackable.rb +4 -2
  31. data/lib/devise/mapping.rb +19 -14
  32. data/lib/devise/models.rb +12 -3
  33. data/lib/devise/models/authenticatable.rb +19 -95
  34. data/lib/devise/models/confirmable.rb +14 -20
  35. data/lib/devise/models/database_authenticatable.rb +99 -0
  36. data/lib/devise/models/lockable.rb +53 -39
  37. data/lib/devise/models/recoverable.rb +3 -3
  38. data/lib/devise/models/rememberable.rb +5 -10
  39. data/lib/devise/models/token_authenticatable.rb +18 -25
  40. data/lib/devise/models/validatable.rb +14 -9
  41. data/lib/devise/modules.rb +7 -8
  42. data/lib/devise/orm/active_record.rb +1 -1
  43. data/lib/devise/orm/data_mapper.rb +20 -7
  44. data/lib/devise/orm/mongoid.rb +40 -0
  45. data/lib/devise/rails.rb +26 -3
  46. data/lib/devise/rails/routes.rb +18 -16
  47. data/lib/devise/rails/warden_compat.rb +2 -2
  48. data/lib/devise/schema.rb +45 -18
  49. data/lib/devise/strategies/authenticatable.rb +92 -21
  50. data/lib/devise/strategies/base.rb +6 -3
  51. data/lib/devise/strategies/database_authenticatable.rb +20 -0
  52. data/lib/devise/strategies/rememberable.rb +10 -6
  53. data/lib/devise/strategies/token_authenticatable.rb +28 -19
  54. data/lib/devise/test_helpers.rb +5 -1
  55. data/lib/devise/version.rb +1 -1
  56. data/lib/generators/devise/devise_generator.rb +15 -5
  57. data/lib/generators/devise/templates/migration.rb +2 -2
  58. data/lib/generators/devise_install/templates/devise.rb +37 -16
  59. data/lib/generators/devise_views/devise_views_generator.rb +51 -4
  60. data/test/controllers/helpers_test.rb +16 -8
  61. data/test/controllers/internal_helpers_test.rb +6 -1
  62. data/test/controllers/url_helpers_test.rb +10 -10
  63. data/test/devise_test.rb +13 -17
  64. data/test/encryptors_test.rb +2 -0
  65. data/test/failure_app_test.rb +72 -23
  66. data/test/integration/confirmable_test.rb +4 -4
  67. data/test/integration/{authenticatable_test.rb → database_authenticatable_test.rb} +35 -17
  68. data/test/integration/http_authenticatable_test.rb +3 -3
  69. data/test/integration/lockable_test.rb +28 -8
  70. data/test/integration/recoverable_test.rb +3 -3
  71. data/test/integration/registerable_test.rb +6 -4
  72. data/test/integration/rememberable_test.rb +11 -4
  73. data/test/integration/timeoutable_test.rb +4 -4
  74. data/test/integration/token_authenticatable_test.rb +46 -10
  75. data/test/integration/trackable_test.rb +2 -2
  76. data/test/mailers/confirmation_instructions_test.rb +5 -5
  77. data/test/mailers/reset_password_instructions_test.rb +5 -5
  78. data/test/mailers/unlock_instructions_test.rb +5 -5
  79. data/test/mapping_test.rb +15 -14
  80. data/test/models/confirmable_test.rb +9 -32
  81. data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +2 -34
  82. data/test/models/lockable_test.rb +48 -66
  83. data/test/models/recoverable_test.rb +8 -8
  84. data/test/models/rememberable_test.rb +6 -28
  85. data/test/models/timeoutable_test.rb +1 -1
  86. data/test/models/token_authenticatable_test.rb +1 -8
  87. data/test/models/trackable_test.rb +1 -1
  88. data/test/models/validatable_test.rb +2 -2
  89. data/test/models_test.rb +16 -2
  90. data/test/orm/active_record.rb +1 -22
  91. data/test/orm/data_mapper.rb +1 -0
  92. data/test/orm/mongoid.rb +10 -0
  93. data/test/rails_app/app/active_record/admin.rb +1 -5
  94. data/test/rails_app/app/controllers/application_controller.rb +2 -0
  95. data/test/rails_app/app/controllers/sessions_controller.rb +1 -1
  96. data/test/rails_app/app/data_mapper/admin.rb +13 -0
  97. data/test/rails_app/app/data_mapper/user.rb +24 -0
  98. data/test/rails_app/app/mongoid/admin.rb +15 -0
  99. data/test/rails_app/app/mongoid/user.rb +21 -0
  100. data/test/rails_app/config/application.rb +10 -5
  101. data/test/rails_app/config/boot.rb +5 -1
  102. data/test/rails_app/config/initializers/devise.rb +1 -1
  103. data/test/rails_app/config/routes.rb +4 -1
  104. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
  105. data/test/rails_app/db/schema.rb +86 -0
  106. data/test/routes_test.rb +3 -3
  107. data/test/support/assertions.rb +2 -0
  108. data/test/support/helpers.rb +2 -0
  109. data/test/support/integration.rb +4 -7
  110. data/test/support/webrat/integrations/rails.rb +2 -1
  111. data/test/test_helper.rb +5 -2
  112. data/test/test_helpers_test.rb +4 -4
  113. metadata +36 -21
  114. data/lib/devise/models/http_authenticatable.rb +0 -19
  115. data/lib/devise/orm/mongo_mapper.rb +0 -49
  116. data/lib/devise/strategies/http_authenticatable.rb +0 -47
  117. data/test/models/http_authenticatable_test.rb +0 -19
  118. data/test/orm/mongo_mapper.rb +0 -12
  119. data/test/rails_app/app/mongo_mapper/admin.rb +0 -10
  120. data/test/rails_app/app/mongo_mapper/user.rb +0 -11
  121. data/test/rails_app/config/initializers/cookie_verification_secret.rb +0 -7
  122. data/test/rails_app/config/initializers/session_store.rb +0 -15
@@ -1,6 +1,6 @@
1
1
  <h2>Resend unlock instructions</h2>
2
2
 
3
- <% form_for resource_name, resource, :url => unlock_path(resource_name) do |f| %>
3
+ <%= form_for(resource_name, resource, :url => unlock_path(resource_name)) do |f| %>
4
4
  <%= f.error_messages %>
5
5
 
6
6
  <p><%= f.label :email %></p>
@@ -6,10 +6,7 @@ en:
6
6
  not_locked: "was not locked"
7
7
 
8
8
  devise:
9
- sessions:
10
- link: 'Sign in'
11
- signed_in: 'Signed in successfully.'
12
- signed_out: 'Signed out successfully.'
9
+ failure:
13
10
  unauthenticated: 'You need to sign in or sign up before continuing.'
14
11
  unconfirmed: 'You have to confirm your account before continuing.'
15
12
  locked: 'Your account is locked.'
@@ -17,25 +14,23 @@ en:
17
14
  invalid_token: 'Invalid authentication token.'
18
15
  timeout: 'Your session expired, please sign in again to continue.'
19
16
  inactive: 'Your account was not activated yet.'
17
+ sessions:
18
+ signed_in: 'Signed in successfully.'
19
+ signed_out: 'Signed out successfully.'
20
20
  passwords:
21
- link: 'Forgot password?'
22
21
  send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
23
22
  updated: 'Your password was changed successfully. You are now signed in.'
24
23
  confirmations:
25
- link: "Didn't receive confirmation instructions?"
26
24
  send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
27
25
  confirmed: 'Your account was successfully confirmed. You are now signed in.'
28
26
  registrations:
29
- link: 'Sign up'
30
27
  signed_up: 'You have signed up successfully.'
31
28
  updated: 'You updated your account successfully.'
32
29
  destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
33
30
  unlocks:
34
- link: "Didn't receive unlock instructions?"
35
31
  send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
36
32
  unlocked: 'Your account was successfully unlocked. You are now signed in.'
37
33
  mailer:
38
34
  confirmation_instructions: 'Confirmation instructions'
39
35
  reset_password_instructions: 'Reset password instructions'
40
36
  unlock_instructions: 'Unlock Instructions'
41
-
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/numeric/time'
2
+
1
3
  module Devise
2
4
  autoload :FailureApp, 'devise/failure_app'
3
5
  autoload :Schema, 'devise/schema'
@@ -20,13 +22,17 @@ module Devise
20
22
  autoload :Sha1, 'devise/encryptors/sha1'
21
23
  end
22
24
 
25
+ module Strategies
26
+ autoload :Base, 'devise/strategies/base'
27
+ autoload :Authenticatable, 'devise/strategies/authenticatable'
28
+ end
29
+
23
30
  # Constants which holds devise configuration for extensions. Those should
24
31
  # not be modified by the "end user".
25
- ALL = []
26
- CONTROLLERS = {}
27
- ROUTES = []
28
- STRATEGIES = []
29
- FLASH_MESSAGES = [:unauthenticated]
32
+ ALL = []
33
+ CONTROLLERS = ActiveSupport::OrderedHash.new
34
+ ROUTES = ActiveSupport::OrderedHash.new
35
+ STRATEGIES = ActiveSupport::OrderedHash.new
30
36
 
31
37
  # True values used to check params
32
38
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
@@ -41,9 +47,6 @@ module Devise
41
47
  :bcrypt => 60
42
48
  }
43
49
 
44
- # Email regex used to validate email formats. Adapted from authlogic.
45
- EMAIL_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
46
-
47
50
  # Used to encrypt password. Please generate one with rake secret.
48
51
  mattr_accessor :pepper
49
52
  @@pepper = nil
@@ -56,6 +59,26 @@ module Devise
56
59
  mattr_accessor :authentication_keys
57
60
  @@authentication_keys = [ :email ]
58
61
 
62
+ # If http authentication is enabled by default.
63
+ mattr_accessor :http_authenticatable
64
+ @@http_authenticatable = true
65
+
66
+ # If params authenticatable is enabled by default.
67
+ mattr_accessor :params_authenticatable
68
+ @@params_authenticatable = true
69
+
70
+ # The realm used in Http Basic Authentication.
71
+ mattr_accessor :http_authentication_realm
72
+ @@http_authentication_realm = "Application"
73
+
74
+ # Email regex used to validate email formats. Adapted from authlogic.
75
+ mattr_accessor :email_regexp
76
+ @@email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
77
+
78
+ # Range validation for password length
79
+ mattr_accessor :password_length
80
+ @@password_length = 6..20
81
+
59
82
  # Time interval where the remember me token is valid.
60
83
  mattr_accessor :remember_for
61
84
  @@remember_for = 2.weeks
@@ -77,7 +100,7 @@ module Devise
77
100
  @@mappings = ActiveSupport::OrderedHash.new
78
101
 
79
102
  # Tells if devise should apply the schema in ORMs where devise declaration
80
- # and schema belongs to the same class (as Datamapper and MongoMapper).
103
+ # and schema belongs to the same class (as Datamapper and Mongoid).
81
104
  mattr_accessor :apply_schema
82
105
  @@apply_schema = true
83
106
 
@@ -86,15 +109,20 @@ module Devise
86
109
  mattr_accessor :scoped_views
87
110
  @@scoped_views = false
88
111
 
89
- # Number of authentication tries before locking an account
90
- mattr_accessor :maximum_attempts
91
- @@maximum_attempts = 20
112
+ # Defines which strategy can be used to lock an account.
113
+ # Values: :failed_attempts, :none
114
+ mattr_accessor :lock_strategy
115
+ @@lock_strategy = :failed_attempts
92
116
 
93
117
  # Defines which strategy can be used to unlock an account.
94
118
  # Values: :email, :time, :both
95
119
  mattr_accessor :unlock_strategy
96
120
  @@unlock_strategy = :both
97
121
 
122
+ # Number of authentication tries before locking an account
123
+ mattr_accessor :maximum_attempts
124
+ @@maximum_attempts = 20
125
+
98
126
  # Time interval to unlock the account if :time is defined as unlock_strategy.
99
127
  mattr_accessor :unlock_in
100
128
  @@unlock_in = 1.hour
@@ -115,9 +143,10 @@ module Devise
115
143
  mattr_accessor :token_authentication_key
116
144
  @@token_authentication_key = :auth_token
117
145
 
118
- # The realm used in Http Basic Authentication
119
- mattr_accessor :http_authentication_realm
120
- @@http_authentication_realm = "Application"
146
+ # Private methods to interface with Warden.
147
+ mattr_accessor :warden_config
148
+ @@warden_config = nil
149
+ @@warden_config_block = nil
121
150
 
122
151
  # Default way to setup Devise. Run rails generate devise_install to create
123
152
  # a fresh initializer with all configuration values.
@@ -125,39 +154,57 @@ module Devise
125
154
  yield self
126
155
  end
127
156
 
157
+ # Register a model in Devise. You can call this manually if you don't want
158
+ # to use devise routes. Check devise_for in routes to know which options
159
+ # are available.
160
+ def self.register(resource, options)
161
+ mapping = Devise::Mapping.new(resource, options)
162
+ self.mappings[mapping.name] = mapping
163
+ self.default_scope ||= mapping.name
164
+
165
+ warden_config.default_scope ||= mapping.name
166
+ warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
167
+ mapping
168
+ end
169
+
128
170
  # Make Devise aware of an 3rd party Devise-module. For convenience.
129
171
  #
130
172
  # == Options:
131
173
  #
132
- # +strategy+ - Boolean value representing if this module got a custom *strategy*.
133
- # Default is +false+. Note: Devise will auto-detect this in such case if this is true.
134
- # +model+ - String representing the load path to a custom *model* for this module (to autoload.)
135
- # Default is +nil+ (i.e. +false+).
136
- # +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
137
- # Default is +nil+ (i.e. +false+).
138
- # +route+ - Symbol representing the named *router* helper for this module.
139
- # Default is +nil+ (i.e. +false+).
140
- # +flash+ - Symbol representing the *flash messages* used by this helper.
141
- # Default is +nil+ (i.e. +false+).
174
+ # +model+ - String representing the load path to a custom *model* for this module (to autoload.)
175
+ # +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
176
+ # +route+ - Symbol representing the named *route* helper for this module.
177
+ # +flash+ - Symbol representing the *flash messages* used by this helper.
178
+ # +strategy+ - Symbol representing if this module got a custom *strategy*.
179
+ #
180
+ # All values, except :model, accept also a boolean and will have the same name as the given module
181
+ # name.
142
182
  #
143
183
  # == Examples:
144
184
  #
145
185
  # Devise.add_module(:party_module)
146
186
  # Devise.add_module(:party_module, :strategy => true, :controller => :sessions)
147
- # Devise.add_module(:party_module, :autoload => 'party_module/model')
187
+ # Devise.add_module(:party_module, :model => 'party_module/model')
148
188
  #
149
189
  def self.add_module(module_name, options = {})
150
190
  ALL << module_name
151
- options.assert_valid_keys(:strategy, :model, :controller, :route, :flash)
191
+ options.assert_valid_keys(:strategy, :model, :controller, :route)
192
+
193
+ config = {
194
+ :strategy => STRATEGIES,
195
+ :route => ROUTES,
196
+ :controller => CONTROLLERS
197
+ }
152
198
 
153
- { :strategy => STRATEGIES, :flash => FLASH_MESSAGES, :route => ROUTES }.each do |key, value|
199
+ config.each do |key, value|
154
200
  next unless options[key]
155
201
  name = (options[key] == true ? module_name : options[key])
156
- value.unshift(name) unless value.include?(name)
157
- end
158
202
 
159
- if options[:controller]
160
- Devise::CONTROLLERS[module_name] = options[:controller].to_sym
203
+ if value.is_a?(Hash)
204
+ value[module_name] = name
205
+ else
206
+ value << name unless value.include?(name)
207
+ end
161
208
  end
162
209
 
163
210
  if options[:model]
@@ -165,7 +212,7 @@ module Devise
165
212
  Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path)
166
213
  end
167
214
 
168
- Devise::Mapping.register module_name
215
+ Devise::Mapping.add_module module_name
169
216
  end
170
217
 
171
218
  # Sets warden configuration using a block that will be invoked on warden
@@ -180,19 +227,13 @@ module Devise
180
227
  # end
181
228
  # end
182
229
  def self.warden(&block)
183
- @warden_config = block
230
+ @@warden_config_block = block
184
231
  end
185
232
 
186
233
  # A method used internally to setup warden manager from the Rails initialize
187
234
  # block.
188
- def self.configure_warden(config) #:nodoc:
189
- config.default_strategies *Devise::STRATEGIES
190
- config.failure_app = Devise::FailureApp
191
- config.silence_missing_strategies!
192
- config.default_scope = Devise.default_scope
193
-
194
- # If the user provided a warden hook, call it now.
195
- @warden_config.try :call, config
235
+ def self.configure_warden! #:nodoc:
236
+ @@warden_config_block.try :call, Devise.warden_config
196
237
  end
197
238
 
198
239
  # Generate a friendly string randomically to be used as token.
@@ -23,18 +23,6 @@ module Devise
23
23
  false
24
24
  end
25
25
 
26
- # Attempts to authenticate the given scope by running authentication hooks,
27
- # but does not redirect in case of failures.
28
- def authenticate(scope)
29
- warden.authenticate(:scope => scope)
30
- end
31
-
32
- # Attempts to authenticate the given scope by running authentication hooks,
33
- # redirecting in case of failures.
34
- def authenticate!(scope)
35
- warden.authenticate!(:scope => scope)
36
- end
37
-
38
26
  # Check if the given scope is signed in session, without running
39
27
  # authentication hooks.
40
28
  def signed_in?(scope)
@@ -79,7 +67,7 @@ module Devise
79
67
  #
80
68
  def stored_location_for(resource_or_scope)
81
69
  scope = Devise::Mapping.find_scope!(resource_or_scope)
82
- session.delete(:"#{scope}.return_to")
70
+ session.delete(:"#{scope}_return_to")
83
71
  end
84
72
 
85
73
  # The default url to be used after signing in. This is used by all Devise
@@ -129,10 +117,10 @@ module Devise
129
117
  #
130
118
  # If just a symbol is given, consider that the user was already signed in
131
119
  # through other means and just perform the redirection.
132
- def sign_in_and_redirect(resource_or_scope, resource=nil, skip=false)
120
+ def sign_in_and_redirect(resource_or_scope, resource=nil)
133
121
  scope = Devise::Mapping.find_scope!(resource_or_scope)
134
122
  resource ||= resource_or_scope
135
- sign_in(scope, resource) unless skip
123
+ sign_in(scope, resource) unless warden.user(scope) == resource
136
124
  redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
137
125
  end
138
126
 
@@ -150,9 +138,9 @@ module Devise
150
138
  # access that specific controller/action.
151
139
  # Example:
152
140
  #
153
- # Maps:
154
- # User => :authenticatable
155
- # Admin => :authenticatable
141
+ # Roles:
142
+ # User
143
+ # Admin
156
144
  #
157
145
  # Generated methods:
158
146
  # authenticate_user! # Signs user in or redirect
@@ -8,13 +8,14 @@ module Devise
8
8
  include Devise::Controllers::ScopedViews
9
9
 
10
10
  included do
11
- helpers = [:resource, :scope_name, :resource_name,
12
- :resource_class, :devise_mapping, :devise_controller?]
11
+ unloadable
13
12
 
13
+ helpers = %w(resource scope_name resource_name
14
+ resource_class devise_mapping devise_controller?)
14
15
  hide_action *helpers
15
16
  helper_method *helpers
16
17
 
17
- before_filter :is_devise_resource?
18
+ prepend_before_filter :is_devise_resource?
18
19
  skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
19
20
  end
20
21
 
@@ -62,8 +63,9 @@ module Devise
62
63
  end
63
64
 
64
65
  # Build a devise resource.
65
- def build_resource
66
- self.resource = resource_class.new(params[resource_name] || {})
66
+ def build_resource(hash=nil)
67
+ hash ||= params[resource_name] || {}
68
+ self.resource = resource_class.new(hash)
67
69
  end
68
70
 
69
71
  # Helper for use in before_filters where no authentication is required.
@@ -88,17 +90,14 @@ module Devise
88
90
  #
89
91
  # Please refer to README or en.yml locale file to check what messages are
90
92
  # available.
91
- def set_flash_message(key, kind, now=false)
92
- flash_hash = now ? flash.now : flash
93
- flash_hash[key] = I18n.t(:"#{resource_name}.#{kind}",
93
+ def set_flash_message(key, kind)
94
+ flash[key] = I18n.t(:"#{resource_name}.#{kind}", :resource_name => resource_name,
94
95
  :scope => [:devise, controller_name.to_sym], :default => kind)
95
96
  end
96
97
 
97
- # Shortcut to set flash.now message. Same rules applied from set_flash_message
98
- def set_now_flash_message(key, kind)
99
- set_flash_message(key, kind, true)
98
+ def clean_up_passwords(object)
99
+ object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
100
100
  end
101
-
102
101
  end
103
102
  end
104
103
  end
@@ -4,7 +4,7 @@ module Devise
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  module ClassMethods
7
- def scoped_views
7
+ def scoped_views?
8
8
  defined?(@scoped_views) ? @scoped_views : Devise.scoped_views
9
9
  end
10
10
 
@@ -20,7 +20,7 @@ module Devise
20
20
  def render_with_scope(action, options={})
21
21
  controller_name = options.delete(:controller) || self.controller_name
22
22
 
23
- if self.class.scoped_views
23
+ if self.class.scoped_views?
24
24
  begin
25
25
  render :template => "#{devise_mapping.as}/#{controller_name}/#{action}"
26
26
  rescue ActionView::MissingTemplate
@@ -19,7 +19,7 @@ module Devise
19
19
  # Those helpers are added to your ApplicationController.
20
20
  module UrlHelpers
21
21
 
22
- Devise::ROUTES.each do |module_name|
22
+ Devise::ROUTES.values.uniq.each do |module_name|
23
23
  [:path, :url].each do |path_or_url|
24
24
  actions = [ nil, :new_ ]
25
25
  actions << :edit_ if [:password, :registration].include?(module_name)
@@ -10,8 +10,7 @@ module Devise
10
10
  include ActionController::UrlFor
11
11
  include ActionController::Redirecting
12
12
 
13
- mattr_accessor :default_message
14
- self.default_message = :unauthenticated
13
+ delegate :flash, :to => :request
15
14
 
16
15
  def self.call(env)
17
16
  action(:respond).call(env)
@@ -22,27 +21,60 @@ module Devise
22
21
  end
23
22
 
24
23
  def respond
25
- scope = warden_options[:scope]
26
- store_location!(scope)
27
- redirect_to send(:"new_#{scope}_session_path", query_string_params)
24
+ if http_auth?
25
+ http_auth
26
+ elsif warden_options[:recall]
27
+ recall
28
+ else
29
+ redirect
30
+ end
31
+ end
32
+
33
+ def http_auth
34
+ self.status = 401
35
+ self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect})
36
+ self.content_type = request.format.to_s
37
+ self.response_body = http_auth_body
38
+ end
39
+
40
+ def recall
41
+ env["PATH_INFO"] = attempted_path
42
+ flash.now[:alert] = i18n_message(:invalid)
43
+ self.response = recall_controller.action(warden_options[:recall]).call(env)
44
+ end
45
+
46
+ def redirect
47
+ store_location!
48
+ flash[:alert] = i18n_message unless flash[:notice]
49
+ redirect_to send(:"new_#{scope}_session_path")
28
50
  end
29
51
 
30
52
  protected
31
53
 
32
- # Build the proper query string based on the given message.
33
- def query_string_params
34
- message = warden.try(:message) || warden_options[:message] || self.class.default_message
54
+ def i18n_message(default = nil)
55
+ message = warden.message || warden_options[:message] || default || :unauthenticated
35
56
 
36
- case message
37
- when Symbol
38
- { message => true }
39
- when String
40
- { :message => message }
57
+ if message.is_a?(Symbol)
58
+ I18n.t(:"#{scope}.#{message}", :resource_name => scope,
59
+ :scope => "devise.failure", :default => [message, message.to_s])
41
60
  else
42
- {}
61
+ message.to_s
43
62
  end
44
63
  end
45
64
 
65
+ def http_auth?
66
+ request.authorization
67
+ end
68
+
69
+ def http_auth_body
70
+ method = :"to_#{request.format.to_sym}"
71
+ {}.respond_to?(method) ? { :error => i18n_message }.send(method) : i18n_message
72
+ end
73
+
74
+ def recall_controller
75
+ "#{params[:controller].camelize}Controller".constantize
76
+ end
77
+
46
78
  def warden
47
79
  env['warden']
48
80
  end
@@ -51,12 +83,20 @@ module Devise
51
83
  env['warden.options']
52
84
  end
53
85
 
86
+ def scope
87
+ @scope ||= warden_options[:scope]
88
+ end
89
+
90
+ def attempted_path
91
+ warden_options[:attempted_path]
92
+ end
93
+
54
94
  # Stores requested uri to redirect the user after signing in. We cannot use
55
95
  # scoped session provided by warden here, since the user is not authenticated
56
96
  # yet, but we still need to store the uri based on scope, so different scopes
57
97
  # would never use the same uri to redirect.
58
- def store_location!(scope)
59
- session[:"#{scope}.return_to"] = request.request_uri if request && request.get?
98
+ def store_location!
99
+ session[:"#{scope}_return_to"] = attempted_path if request && request.get?
60
100
  end
61
101
  end
62
102
  end