devise 1.0.11 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/CHANGELOG.rdoc +59 -13
  2. data/Gemfile +23 -0
  3. data/Gemfile.lock +118 -0
  4. data/README.rdoc +116 -77
  5. data/Rakefile +4 -2
  6. data/TODO +3 -2
  7. data/app/controllers/{confirmations_controller.rb → devise/confirmations_controller.rb} +1 -1
  8. data/app/controllers/{passwords_controller.rb → devise/passwords_controller.rb} +1 -1
  9. data/app/controllers/{registrations_controller.rb → devise/registrations_controller.rb} +12 -8
  10. data/app/controllers/devise/sessions_controller.rb +23 -0
  11. data/app/controllers/{unlocks_controller.rb → devise/unlocks_controller.rb} +1 -8
  12. data/app/helpers/devise_helper.rb +17 -0
  13. data/app/mailers/devise/mailer.rb +71 -0
  14. data/app/views/devise/confirmations/new.html.erb +12 -0
  15. data/app/views/devise/passwords/edit.html.erb +16 -0
  16. data/app/views/devise/passwords/new.html.erb +12 -0
  17. data/app/views/devise/registrations/edit.html.erb +25 -0
  18. data/app/views/devise/registrations/new.html.erb +18 -0
  19. data/app/views/devise/sessions/new.html.erb +17 -0
  20. data/app/views/devise/shared/_links.erb +19 -0
  21. data/app/views/devise/unlocks/new.html.erb +12 -0
  22. data/{lib/devise → config}/locales/en.yml +16 -12
  23. data/lib/devise/controllers/helpers.rb +57 -52
  24. data/lib/devise/controllers/internal_helpers.rb +19 -50
  25. data/lib/devise/controllers/scoped_views.rb +35 -0
  26. data/lib/devise/controllers/url_helpers.rb +1 -1
  27. data/lib/devise/encryptors/authlogic_sha512.rb +0 -2
  28. data/lib/devise/encryptors/base.rb +1 -1
  29. data/lib/devise/encryptors/bcrypt.rb +2 -4
  30. data/lib/devise/encryptors/clearance_sha1.rb +0 -2
  31. data/lib/devise/encryptors/sha1.rb +6 -8
  32. data/lib/devise/encryptors/sha512.rb +6 -8
  33. data/lib/devise/failure_app.rb +76 -41
  34. data/lib/devise/hooks/activatable.rb +6 -10
  35. data/lib/devise/hooks/forgetable.rb +11 -0
  36. data/lib/devise/hooks/rememberable.rb +40 -30
  37. data/lib/devise/hooks/timeoutable.rb +7 -3
  38. data/lib/devise/hooks/trackable.rb +5 -14
  39. data/lib/devise/mapping.rb +35 -62
  40. data/lib/devise/models/authenticatable.rb +126 -0
  41. data/lib/devise/models/confirmable.rb +19 -22
  42. data/lib/devise/models/database_authenticatable.rb +26 -60
  43. data/lib/devise/models/lockable.rb +43 -28
  44. data/lib/devise/models/recoverable.rb +11 -10
  45. data/lib/devise/models/rememberable.rb +56 -26
  46. data/lib/devise/models/timeoutable.rb +1 -3
  47. data/lib/devise/models/token_authenticatable.rb +14 -43
  48. data/lib/devise/models/trackable.rb +14 -0
  49. data/lib/devise/models/validatable.rb +16 -2
  50. data/lib/devise/models.rb +16 -53
  51. data/lib/devise/modules.rb +23 -0
  52. data/lib/devise/orm/active_record.rb +10 -15
  53. data/lib/devise/orm/mongoid.rb +29 -0
  54. data/lib/devise/path_checker.rb +18 -0
  55. data/lib/devise/rails/routes.rb +232 -117
  56. data/lib/devise/rails/warden_compat.rb +17 -41
  57. data/lib/devise/rails.rb +64 -9
  58. data/lib/devise/schema.rb +47 -23
  59. data/lib/devise/strategies/authenticatable.rb +123 -0
  60. data/lib/devise/strategies/base.rb +2 -3
  61. data/lib/devise/strategies/database_authenticatable.rb +7 -22
  62. data/lib/devise/strategies/rememberable.rb +21 -7
  63. data/lib/devise/strategies/token_authenticatable.rb +31 -19
  64. data/lib/devise/test_helpers.rb +6 -6
  65. data/lib/devise/version.rb +1 -1
  66. data/lib/devise.rb +174 -157
  67. data/lib/generators/active_record/devise_generator.rb +28 -0
  68. data/{generators/devise → lib/generators/active_record}/templates/migration.rb +9 -3
  69. data/lib/generators/devise/devise_generator.rb +17 -0
  70. data/lib/generators/devise/install_generator.rb +24 -0
  71. data/lib/generators/devise/orm_helpers.rb +23 -0
  72. data/{generators/devise_install → lib/generators/devise}/templates/README +9 -7
  73. data/lib/generators/devise/templates/devise.rb +142 -0
  74. data/lib/generators/devise/views_generator.rb +63 -0
  75. data/lib/generators/devise_install_generator.rb +4 -0
  76. data/lib/generators/devise_views_generator.rb +4 -0
  77. data/lib/generators/mongoid/devise_generator.rb +17 -0
  78. data/test/controllers/helpers_test.rb +48 -19
  79. data/test/controllers/internal_helpers_test.rb +12 -16
  80. data/test/controllers/url_helpers_test.rb +21 -10
  81. data/test/devise_test.rb +16 -25
  82. data/test/encryptors_test.rb +2 -3
  83. data/test/failure_app_test.rb +106 -27
  84. data/test/integration/authenticatable_test.rb +135 -131
  85. data/test/integration/confirmable_test.rb +22 -15
  86. data/test/integration/database_authenticatable_test.rb +38 -0
  87. data/test/integration/http_authenticatable_test.rb +9 -12
  88. data/test/integration/lockable_test.rb +22 -15
  89. data/test/integration/recoverable_test.rb +6 -6
  90. data/test/integration/registerable_test.rb +42 -33
  91. data/test/integration/rememberable_test.rb +84 -22
  92. data/test/integration/timeoutable_test.rb +16 -4
  93. data/test/integration/token_authenticatable_test.rb +45 -12
  94. data/test/integration/trackable_test.rb +1 -1
  95. data/test/mailers/confirmation_instructions_test.rb +11 -17
  96. data/test/mailers/reset_password_instructions_test.rb +7 -7
  97. data/test/mailers/unlock_instructions_test.rb +7 -7
  98. data/test/mapping_test.rb +22 -95
  99. data/test/models/confirmable_test.rb +12 -19
  100. data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +24 -56
  101. data/test/models/lockable_test.rb +32 -46
  102. data/test/models/recoverable_test.rb +7 -7
  103. data/test/models/rememberable_test.rb +118 -35
  104. data/test/models/timeoutable_test.rb +1 -1
  105. data/test/models/token_authenticatable_test.rb +5 -19
  106. data/test/models/trackable_test.rb +1 -1
  107. data/test/models/validatable_test.rb +20 -27
  108. data/test/models_test.rb +12 -5
  109. data/test/orm/active_record.rb +1 -23
  110. data/test/orm/mongoid.rb +10 -0
  111. data/test/rails_app/app/active_record/admin.rb +1 -5
  112. data/test/rails_app/app/active_record/shim.rb +2 -0
  113. data/test/rails_app/app/active_record/user.rb +3 -3
  114. data/test/rails_app/app/controllers/application_controller.rb +2 -5
  115. data/test/rails_app/app/controllers/home_controller.rb +3 -0
  116. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  117. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  118. data/test/rails_app/app/controllers/sessions_controller.rb +6 -0
  119. data/test/rails_app/app/controllers/users_controller.rb +7 -5
  120. data/test/rails_app/app/mongoid/admin.rb +6 -0
  121. data/test/rails_app/app/mongoid/shim.rb +16 -0
  122. data/test/rails_app/app/mongoid/user.rb +10 -0
  123. data/test/rails_app/config/application.rb +35 -0
  124. data/test/rails_app/config/boot.rb +10 -107
  125. data/test/rails_app/config/environment.rb +4 -41
  126. data/test/rails_app/config/environments/development.rb +15 -13
  127. data/test/rails_app/config/environments/production.rb +25 -20
  128. data/test/rails_app/config/environments/test.rb +33 -28
  129. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  130. data/test/rails_app/config/initializers/devise.rb +95 -38
  131. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  132. data/test/rails_app/config/routes.rb +47 -25
  133. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
  134. data/test/rails_app/db/schema.rb +86 -0
  135. data/test/routes_test.rb +62 -47
  136. data/test/support/{assertions_helper.rb → assertions.rb} +2 -15
  137. data/test/support/{tests_helper.rb → helpers.rb} +18 -3
  138. data/test/support/{integration_tests_helper.rb → integration.rb} +24 -7
  139. data/test/support/webrat/integrations/rails.rb +32 -0
  140. data/test/test_helper.rb +11 -11
  141. data/test/test_helpers_test.rb +30 -15
  142. metadata +107 -66
  143. data/app/controllers/sessions_controller.rb +0 -42
  144. data/app/models/devise_mailer.rb +0 -68
  145. data/app/views/confirmations/new.html.erb +0 -12
  146. data/app/views/passwords/edit.html.erb +0 -16
  147. data/app/views/passwords/new.html.erb +0 -12
  148. data/app/views/registrations/edit.html.erb +0 -25
  149. data/app/views/registrations/new.html.erb +0 -17
  150. data/app/views/sessions/new.html.erb +0 -17
  151. data/app/views/shared/_devise_links.erb +0 -19
  152. data/app/views/unlocks/new.html.erb +0 -12
  153. data/generators/devise/USAGE +0 -5
  154. data/generators/devise/devise_generator.rb +0 -15
  155. data/generators/devise/lib/route_devise.rb +0 -32
  156. data/generators/devise/templates/model.rb +0 -9
  157. data/generators/devise_install/USAGE +0 -3
  158. data/generators/devise_install/devise_install_generator.rb +0 -15
  159. data/generators/devise_install/templates/devise.rb +0 -105
  160. data/generators/devise_views/USAGE +0 -3
  161. data/generators/devise_views/devise_views_generator.rb +0 -21
  162. data/lib/devise/models/activatable.rb +0 -16
  163. data/lib/devise/models/http_authenticatable.rb +0 -23
  164. data/lib/devise/orm/data_mapper.rb +0 -83
  165. data/lib/devise/orm/mongo_mapper.rb +0 -52
  166. data/lib/devise/strategies/http_authenticatable.rb +0 -59
  167. data/rails/init.rb +0 -2
  168. data/test/integration/rack_middleware_test.rb +0 -47
  169. data/test/orm/mongo_mapper.rb +0 -20
  170. data/test/rails_app/app/mongo_mapper/admin.rb +0 -13
  171. data/test/rails_app/app/mongo_mapper/user.rb +0 -14
  172. data/test/rails_app/config/initializers/new_rails_defaults.rb +0 -24
  173. data/test/rails_app/config/initializers/session_store.rb +0 -15
  174. /data/app/views/{devise_mailer → devise/mailer}/confirmation_instructions.html.erb +0 -0
  175. /data/app/views/{devise_mailer → devise/mailer}/reset_password_instructions.html.erb +0 -0
  176. /data/app/views/{devise_mailer → devise/mailer}/unlock_instructions.html.erb +0 -0
@@ -4,28 +4,19 @@ module Devise
4
4
  # included in ApplicationController since they all depend on the url being
5
5
  # accessed.
6
6
  module InternalHelpers #:nodoc:
7
+ extend ActiveSupport::Concern
8
+ include Devise::Controllers::ScopedViews
7
9
 
8
- def self.included(base)
9
- base.class_eval do
10
- extend ScopedViews
11
- unloadable
10
+ included do
11
+ helper DeviseHelper
12
12
 
13
- helper_method :resource, :scope_name, :resource_name, :resource_class, :devise_mapping, :devise_controller?
14
- hide_action :resource, :scope_name, :resource_name, :resource_class, :devise_mapping, :devise_controller?
13
+ helpers = %w(resource scope_name resource_name
14
+ resource_class devise_mapping devise_controller?)
15
+ hide_action *helpers
16
+ helper_method *helpers
15
17
 
16
- skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
17
- prepend_before_filter :is_devise_resource?
18
- end
19
- end
20
-
21
- module ScopedViews
22
- def scoped_views
23
- defined?(@scoped_views) ? @scoped_views : Devise.scoped_views
24
- end
25
-
26
- def scoped_views=(value)
27
- @scoped_views = value
28
- end
18
+ prepend_before_filter :is_devise_resource?
19
+ skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
29
20
  end
30
21
 
31
22
  # Gets the actual resource stored in the instance variable
@@ -46,11 +37,7 @@ module Devise
46
37
 
47
38
  # Attempt to find the mapped route for devise based on request path
48
39
  def devise_mapping
49
- @devise_mapping ||= begin
50
- mapping = Devise::Mapping.find_by_path(request.path)
51
- mapping ||= Devise.mappings[Devise.default_scope] if Devise.use_default_scope
52
- mapping
53
- end
40
+ @devise_mapping ||= request.env["devise.mapping"]
54
41
  end
55
42
 
56
43
  # Overwrites devise_controller? to return true
@@ -62,7 +49,7 @@ module Devise
62
49
 
63
50
  # Checks whether it's a devise mapped resource or not.
64
51
  def is_devise_resource? #:nodoc:
65
- raise ActionController::UnknownAction unless devise_mapping && devise_mapping.allows?(controller_name)
52
+ raise ActionController::UnknownAction unless devise_mapping
66
53
  end
67
54
 
68
55
  # Sets the resource creating an instance variable
@@ -71,8 +58,9 @@ module Devise
71
58
  end
72
59
 
73
60
  # Build a devise resource.
74
- def build_resource
75
- self.resource ||= resource_class.new(params[resource_name] || {})
61
+ def build_resource(hash=nil)
62
+ hash ||= params[resource_name] || {}
63
+ self.resource = resource_class.new(hash)
76
64
  end
77
65
 
78
66
  # Helper for use in before_filters where no authentication is required.
@@ -97,33 +85,14 @@ module Devise
97
85
  #
98
86
  # Please refer to README or en.yml locale file to check what messages are
99
87
  # available.
100
- def set_flash_message(key, kind, now=false)
101
- flash_hash = now ? flash.now : flash
102
- flash_hash[key] = I18n.t(:"#{resource_name}.#{kind}",
88
+ def set_flash_message(key, kind)
89
+ flash[key] = I18n.t(:"#{resource_name}.#{kind}", :resource_name => resource_name,
103
90
  :scope => [:devise, controller_name.to_sym], :default => kind)
104
91
  end
105
92
 
106
- # Shortcut to set flash.now message. Same rules applied from set_flash_message
107
- def set_now_flash_message(key, kind)
108
- set_flash_message(key, kind, true)
93
+ def clean_up_passwords(object)
94
+ object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
109
95
  end
110
-
111
- # Render a view for the specified scope. Turned off by default.
112
- # Accepts just :controller as option.
113
- def render_with_scope(action, options={})
114
- controller_name = options.delete(:controller) || self.controller_name
115
-
116
- if self.class.scoped_views
117
- begin
118
- render :template => "#{controller_name}/#{devise_mapping.as}/#{action}"
119
- rescue ActionView::MissingTemplate
120
- render action, :controller => controller_name
121
- end
122
- else
123
- render action, :controller => controller_name
124
- end
125
- end
126
-
127
96
  end
128
97
  end
129
98
  end
@@ -0,0 +1,35 @@
1
+ module Devise
2
+ module Controllers
3
+ module ScopedViews
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def scoped_views?
8
+ defined?(@scoped_views) ? @scoped_views : Devise.scoped_views
9
+ end
10
+
11
+ def scoped_views=(value)
12
+ @scoped_views = value
13
+ end
14
+ end
15
+
16
+ protected
17
+
18
+ # Render a view for the specified scope. Turned off by default.
19
+ # Accepts just :controller as option.
20
+ def render_with_scope(action, options={})
21
+ controller_name = options.delete(:controller) || self.controller_name
22
+
23
+ if self.class.scoped_views?
24
+ begin
25
+ render :template => "#{devise_mapping.plural}/#{controller_name}/#{action}"
26
+ rescue ActionView::MissingTemplate
27
+ render :template => "#{controller_path}/#{action}"
28
+ end
29
+ else
30
+ render :template => "#{controller_path}/#{action}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -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)
@@ -7,7 +7,6 @@ module Devise
7
7
  # Warning: it uses Devise's stretches configuration to port Authlogic's one. Should be set to 20 in the initializer to silumate
8
8
  # the default behavior.
9
9
  class AuthlogicSha512 < Base
10
-
11
10
  # Gererates a default password digest based on salt, pepper and the
12
11
  # incoming password.
13
12
  def self.digest(password, stretches, salt, pepper)
@@ -15,7 +14,6 @@ module Devise
15
14
  stretches.times { digest = Digest::SHA512.hexdigest(digest) }
16
15
  digest
17
16
  end
18
-
19
17
  end
20
18
  end
21
19
  end
@@ -12,7 +12,7 @@ module Devise
12
12
  raise NotImplemented
13
13
  end
14
14
 
15
- def self.salt
15
+ def self.salt(stretches)
16
16
  Devise.friendly_token
17
17
  end
18
18
  end
@@ -5,17 +5,15 @@ module Devise
5
5
  # = BCrypt
6
6
  # Uses the BCrypt hash algorithm to encrypt passwords.
7
7
  class Bcrypt < Base
8
-
9
8
  # Gererates a default password digest based on stretches, salt, pepper and the
10
9
  # incoming password. We don't strech it ourselves since BCrypt does so internally.
11
10
  def self.digest(password, stretches, salt, pepper)
12
11
  ::BCrypt::Engine.hash_secret([password, pepper].join, salt, stretches)
13
12
  end
14
13
 
15
- def self.salt
16
- ::BCrypt::Engine.generate_salt
14
+ def self.salt(stretches)
15
+ ::BCrypt::Engine.generate_salt(stretches)
17
16
  end
18
-
19
17
  end
20
18
  end
21
19
  end
@@ -7,13 +7,11 @@ module Devise
7
7
  # Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
8
8
  # Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
9
9
  class ClearanceSha1 < Base
10
-
11
10
  # Gererates a default password digest based on salt, pepper and the
12
11
  # incoming password.
13
12
  def self.digest(password, stretches, salt, pepper)
14
13
  Digest::SHA1.hexdigest("--#{salt}--#{password}--")
15
14
  end
16
-
17
15
  end
18
16
  end
19
17
  end
@@ -5,7 +5,6 @@ module Devise
5
5
  # = Sha1
6
6
  # Uses the Sha1 hash algorithm to encrypt passwords.
7
7
  class Sha1 < Base
8
-
9
8
  # Gererates a default password digest based on stretches, salt, pepper and the
10
9
  # incoming password.
11
10
  def self.digest(password, stretches, salt, pepper)
@@ -14,14 +13,13 @@ module Devise
14
13
  digest
15
14
  end
16
15
 
17
- private
16
+ private
18
17
 
19
- # Generate a SHA1 digest joining args. Generated token is something like
20
- # --arg1--arg2--arg3--argN--
21
- def self.secure_digest(*tokens)
22
- ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
23
- end
24
-
18
+ # Generate a SHA1 digest joining args. Generated token is something like
19
+ # --arg1--arg2--arg3--argN--
20
+ def self.secure_digest(*tokens)
21
+ ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
22
+ end
25
23
  end
26
24
  end
27
25
  end
@@ -5,7 +5,6 @@ module Devise
5
5
  # = Sha512
6
6
  # Uses the Sha512 hash algorithm to encrypt passwords.
7
7
  class Sha512 < Base
8
-
9
8
  # Gererates a default password digest based on salt, pepper and the
10
9
  # incoming password.
11
10
  def self.digest(password, stretches, salt, pepper)
@@ -14,14 +13,13 @@ module Devise
14
13
  digest
15
14
  end
16
15
 
17
- private
16
+ private
18
17
 
19
- # Generate a Sha512 digest joining args. Generated token is something like
20
- # --arg1--arg2--arg3--argN--
21
- def self.secure_digest(*tokens)
22
- ::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
23
- end
24
-
18
+ # Generate a Sha512 digest joining args. Generated token is something like
19
+ # --arg1--arg2--arg3--argN--
20
+ def self.secure_digest(*tokens)
21
+ ::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
22
+ end
25
23
  end
26
24
  end
27
25
  end
@@ -1,72 +1,107 @@
1
+ require "action_controller/metal"
2
+
1
3
  module Devise
2
4
  # Failure application that will be called every time :warden is thrown from
3
5
  # any strategy or hook. Responsible for redirect the user to the sign in
4
6
  # page based on current scope and mapping. If no scope is given, redirect
5
7
  # to the default_url.
6
- class FailureApp
7
- attr_reader :env
8
- include Warden::Mixins::Common
8
+ class FailureApp < ActionController::Metal
9
+ include ActionController::RackDelegation
10
+ include ActionController::UrlFor
11
+ include ActionController::Redirecting
12
+ include Rails.application.routes.url_helpers
9
13
 
10
- cattr_accessor :default_url, :default_message, :instance_writer => false
11
- @@default_message = :unauthenticated
14
+ delegate :flash, :to => :request
12
15
 
13
16
  def self.call(env)
14
- new(env).respond!
17
+ action(:respond).call(env)
15
18
  end
16
19
 
17
- def initialize(env)
18
- @env = env
20
+ def self.default_url_options(*args)
21
+ ApplicationController.default_url_options(*args)
19
22
  end
20
23
 
21
- def respond!
22
- options = @env['warden.options']
23
- scope = options[:scope]
24
+ def respond
25
+ if http_auth?
26
+ http_auth
27
+ elsif warden_options[:recall]
28
+ recall
29
+ else
30
+ redirect
31
+ end
32
+ end
24
33
 
25
- redirect_path = redirect_path_for(scope)
26
- query_string = query_string_for(options)
27
- store_location!(scope)
34
+ def http_auth
35
+ self.status = 401
36
+ self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect})
37
+ self.content_type = request.format.to_s
38
+ self.response_body = http_auth_body
39
+ end
28
40
 
29
- headers = {}
30
- headers["Location"] = redirect_path
31
- headers["Location"] << "?" << query_string unless query_string.empty?
32
- headers["Content-Type"] = 'text/plain'
41
+ def recall
42
+ env["PATH_INFO"] = attempted_path
43
+ flash.now[:alert] = i18n_message(:invalid)
44
+ self.response = recall_controller.action(warden_options[:recall]).call(env)
45
+ end
33
46
 
34
- [302, headers, ["You are being redirected to #{redirect_path}"]]
47
+ def redirect
48
+ store_location!
49
+ flash[:alert] = i18n_message unless flash[:notice]
50
+ redirect_to redirect_url
35
51
  end
36
52
 
37
- # Build the proper query string based on the given message.
38
- def query_string_for(options)
39
- message = @env['warden'].try(:message) || options[:message] || default_message
53
+ protected
40
54
 
41
- params = case message
42
- when Symbol
43
- { message => true }
44
- when String
45
- { :message => message }
46
- else
47
- {}
55
+ def i18n_message(default = nil)
56
+ message = warden.message || warden_options[:message] || default || :unauthenticated
57
+
58
+ if message.is_a?(Symbol)
59
+ I18n.t(:"#{scope}.#{message}", :resource_name => scope,
60
+ :scope => "devise.failure", :default => [message, message.to_s])
61
+ else
62
+ message.to_s
48
63
  end
64
+ end
49
65
 
50
- Rack::Utils.build_query(params)
66
+ def redirect_url
67
+ send(:"new_#{scope}_session_path")
51
68
  end
52
69
 
53
- # Build the path based on current scope.
54
- def redirect_path_for(scope)
55
- if mapping = Devise.mappings[scope]
56
- "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}"
57
- else
58
- "/#{default_url}"
59
- end
70
+ def http_auth?
71
+ !Devise.navigational_formats.include?(request.format.to_sym) || (request.xhr? && Devise.http_authenticatable_on_xhr)
72
+ end
73
+
74
+ def http_auth_body
75
+ method = :"to_#{request.format.to_sym}"
76
+ {}.respond_to?(method) ? { :error => i18n_message }.send(method) : i18n_message
77
+ end
78
+
79
+ def recall_controller
80
+ "#{params[:controller].camelize}Controller".constantize
81
+ end
82
+
83
+ def warden
84
+ env['warden']
85
+ end
86
+
87
+ def warden_options
88
+ env['warden.options']
89
+ end
90
+
91
+ def scope
92
+ @scope ||= warden_options[:scope]
93
+ end
94
+
95
+ def attempted_path
96
+ warden_options[:attempted_path]
60
97
  end
61
98
 
62
99
  # Stores requested uri to redirect the user after signing in. We cannot use
63
100
  # scoped session provided by warden here, since the user is not authenticated
64
101
  # yet, but we still need to store the uri based on scope, so different scopes
65
102
  # would never use the same uri to redirect.
66
- def store_location!(scope)
67
- if request && request.get? && !request.xhr?
68
- session[:"#{scope}.return_to"] = request.request_uri
69
- end
103
+ def store_location!
104
+ session[:"#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
70
105
  end
71
106
  end
72
107
  end
@@ -1,15 +1,11 @@
1
- # Deny user access whenever his account is not active yet.
1
+ # Deny user access whenever his account is not active yet. All strategies that inherits from
2
+ # Devise::Strategies::Authenticatable and uses the validate already check if the user is active?
3
+ # before actively signing him in. However, we need this as hook to validate the user activity
4
+ # in each request and in case the user is using other strategies beside Devise ones.
2
5
  Warden::Manager.after_set_user do |record, warden, options|
3
6
  if record && record.respond_to?(:active?) && !record.active?
4
7
  scope = options[:scope]
5
8
  warden.logout(scope)
6
-
7
- # If winning strategy was set, this is being called after authenticate and
8
- # there is no need to force a redirect.
9
- if warden.winning_strategy
10
- warden.winning_strategy.fail!(record.inactive_message)
11
- else
12
- throw :warden, :scope => scope, :message => record.inactive_message
13
- end
9
+ throw :warden, :scope => scope, :message => record.inactive_message
14
10
  end
15
- end
11
+ end
@@ -0,0 +1,11 @@
1
+ # Before logout hook to forget the user in the given scope, if it responds
2
+ # to forget_me! Also clear remember token to ensure the user won't be
3
+ # remembered again. Notice that we forget the user unless the record is frozen.
4
+ # This avoids forgetting deleted users.
5
+ Warden::Manager.before_logout do |record, warden, options|
6
+ if record.respond_to?(:forget_me!)
7
+ record.forget_me! unless record.frozen?
8
+ options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
9
+ warden.cookies.delete("remember_#{options[:scope]}_token", options)
10
+ end
11
+ end
@@ -1,33 +1,43 @@
1
- # After authenticate hook to verify if the user in the given scope asked to be
2
- # remembered while he does not sign out. Generates a new remember token for
3
- # that specific user and adds a cookie with this user info to sign in this user
4
- # automatically without asking for credentials. Refer to rememberable strategy
5
- # for more info.
6
- Warden::Manager.prepend_after_authentication do |record, warden, options|
7
- scope = options[:scope]
8
- remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
9
-
10
- if Devise::TRUE_VALUES.include?(remember_me) &&
11
- warden.authenticated?(scope) && record.respond_to?(:remember_me!)
12
- record.remember_me!
13
-
14
- warden.response.set_cookie "remember_#{scope}_token", {
15
- :value => record.class.serialize_into_cookie(record),
16
- :expires => record.remember_expires_at,
17
- :path => "/"
18
- }
1
+ module Devise
2
+ module Hooks
3
+ # Overwrite success! in authentication strategies allowing users to be remembered.
4
+ # We choose to implement this as an strategy hook instead of a warden hook to allow a specific
5
+ # strategy (like token authenticatable or facebook authenticatable) to turn off remember_me?
6
+ # cookies.
7
+ module Rememberable #:nodoc:
8
+ def success!(resource)
9
+ super
10
+
11
+ if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
12
+ resource.remember_me!(extend_remember_period?)
13
+
14
+ configuration = {
15
+ :value => resource.class.serialize_into_cookie(resource),
16
+ :expires => resource.remember_expires_at,
17
+ :path => "/"
18
+ }
19
+
20
+ configuration[:domain] = resource.cookie_domain if resource.cookie_domain?
21
+ cookies.signed["remember_#{scope}_token"] = configuration
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def succeeded?
28
+ @result == :success
29
+ end
30
+
31
+ def extend_remember_period?
32
+ false
33
+ end
34
+
35
+ def remember_me?
36
+ valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
37
+ end
38
+ end
19
39
  end
20
40
  end
21
41
 
22
- # Before logout hook to forget the user in the given scope, only if rememberable
23
- # is activated for this scope. Also clear remember token to ensure the user
24
- # won't be remembered again.
25
- # Notice that we forget the user if the record is frozen. This usually means the
26
- # user was just deleted.
27
- Warden::Manager.before_logout do |record, warden, options|
28
- scope = options[:scope]
29
- if record.respond_to?(:forget_me!)
30
- record.forget_me! unless record.frozen?
31
- warden.response.delete_cookie "remember_#{scope}_token", :path => "/"
32
- end
33
- end
42
+ Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
43
+
@@ -1,16 +1,20 @@
1
- # Each time a record is set we check whether it's session has already timed out
1
+ # Each time a record is set we check whether its session has already timed out
2
2
  # or not, based on last request time. If so, the record is logged out and
3
3
  # redirected to the sign in page. Also, each time the request comes and the
4
4
  # record is set, we set the last request time inside it's scoped session to
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
@@ -1,18 +1,9 @@
1
1
  # After each sign in, update sign in time, sign in count and sign in IP.
2
+ # This is only triggered when the user is explicitly set (with set_user)
3
+ # and on authentication. Retrieving the user from session (:fetch) does
4
+ # not trigger it.
2
5
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
3
- scope = options[:scope]
4
- if Devise.mappings[scope].try(:trackable?) && warden.authenticated?(scope)
5
- old_current, new_current = record.current_sign_in_at, Time.now
6
- record.last_sign_in_at = old_current || new_current
7
- record.current_sign_in_at = new_current
8
-
9
- old_current, new_current = record.current_sign_in_ip, warden.request.remote_ip
10
- record.last_sign_in_ip = old_current || new_current
11
- record.current_sign_in_ip = new_current
12
-
13
- record.sign_in_count ||= 0
14
- record.sign_in_count += 1
15
-
16
- record.save(false)
6
+ if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope])
7
+ record.update_tracked_fields!(warden.request)
17
8
  end
18
9
  end