devise 1.1.3 → 1.2.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 (157) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.rdoc +94 -0
  4. data/Gemfile +24 -13
  5. data/Gemfile.lock +119 -75
  6. data/MIT-LICENSE +1 -1
  7. data/README.rdoc +144 -101
  8. data/Rakefile +3 -24
  9. data/app/controllers/devise/confirmations_controller.rb +1 -1
  10. data/app/controllers/devise/omniauth_callbacks_controller.rb +26 -0
  11. data/app/controllers/devise/passwords_controller.rb +1 -1
  12. data/app/controllers/devise/registrations_controller.rb +60 -7
  13. data/app/controllers/devise/sessions_controller.rb +6 -4
  14. data/app/controllers/devise/unlocks_controller.rb +1 -1
  15. data/app/helpers/devise_helper.rb +10 -2
  16. data/app/mailers/devise/mailer.rb +27 -10
  17. data/app/views/devise/confirmations/new.html.erb +1 -1
  18. data/app/views/devise/passwords/edit.html.erb +2 -2
  19. data/app/views/devise/passwords/new.html.erb +1 -1
  20. data/app/views/devise/registrations/edit.html.erb +1 -1
  21. data/app/views/devise/registrations/new.html.erb +1 -1
  22. data/app/views/devise/sessions/new.html.erb +1 -1
  23. data/app/views/devise/shared/_links.erb +6 -0
  24. data/app/views/devise/unlocks/new.html.erb +1 -1
  25. data/config/locales/en.yml +11 -2
  26. data/devise.gemspec +25 -0
  27. data/lib/devise/controllers/helpers.rb +119 -116
  28. data/lib/devise/controllers/internal_helpers.rb +29 -8
  29. data/lib/devise/controllers/rememberable.rb +52 -0
  30. data/lib/devise/controllers/scoped_views.rb +4 -6
  31. data/lib/devise/controllers/url_helpers.rb +3 -5
  32. data/lib/devise/encryptors/authlogic_sha512.rb +1 -1
  33. data/lib/devise/encryptors/base.rb +1 -1
  34. data/lib/devise/encryptors/restful_authentication_sha1.rb +4 -4
  35. data/lib/devise/failure_app.rb +46 -10
  36. data/lib/devise/hooks/activatable.rb +2 -2
  37. data/lib/devise/hooks/forgetable.rb +1 -3
  38. data/lib/devise/hooks/rememberable.rb +5 -42
  39. data/lib/devise/hooks/timeoutable.rb +1 -1
  40. data/lib/devise/mapping.rb +18 -7
  41. data/lib/devise/models/authenticatable.rb +73 -31
  42. data/lib/devise/models/confirmable.rb +16 -20
  43. data/lib/devise/models/database_authenticatable.rb +27 -37
  44. data/lib/devise/models/encryptable.rb +72 -0
  45. data/lib/devise/models/lockable.rb +27 -21
  46. data/lib/devise/models/omniauthable.rb +23 -0
  47. data/lib/devise/models/recoverable.rb +13 -3
  48. data/lib/devise/models/registerable.rb +13 -0
  49. data/lib/devise/models/rememberable.rb +39 -34
  50. data/lib/devise/models/timeoutable.rb +20 -3
  51. data/lib/devise/models/token_authenticatable.rb +22 -10
  52. data/lib/devise/models/validatable.rb +16 -4
  53. data/lib/devise/models.rb +4 -16
  54. data/lib/devise/modules.rb +15 -8
  55. data/lib/devise/omniauth/config.rb +18 -0
  56. data/lib/devise/omniauth/url_helpers.rb +33 -0
  57. data/lib/devise/omniauth.rb +32 -0
  58. data/lib/devise/orm/active_record.rb +2 -0
  59. data/lib/devise/orm/mongoid.rb +4 -2
  60. data/lib/devise/rails/routes.rb +67 -20
  61. data/lib/devise/rails/warden_compat.rb +101 -15
  62. data/lib/devise/rails.rb +33 -44
  63. data/lib/devise/schema.rb +16 -16
  64. data/lib/devise/strategies/authenticatable.rb +48 -7
  65. data/lib/devise/strategies/database_authenticatable.rb +1 -1
  66. data/lib/devise/strategies/rememberable.rb +6 -5
  67. data/lib/devise/strategies/token_authenticatable.rb +6 -2
  68. data/lib/devise/test_helpers.rb +13 -3
  69. data/lib/devise/version.rb +1 -1
  70. data/lib/devise.rb +162 -50
  71. data/lib/generators/active_record/devise_generator.rb +2 -2
  72. data/lib/generators/active_record/templates/migration.rb +2 -0
  73. data/lib/generators/devise/devise_generator.rb +3 -1
  74. data/lib/generators/devise/orm_helpers.rb +1 -1
  75. data/lib/generators/devise/views_generator.rb +8 -45
  76. data/lib/generators/mongoid/devise_generator.rb +2 -2
  77. data/lib/generators/templates/devise.rb +82 -39
  78. data/test/controllers/helpers_test.rb +78 -72
  79. data/test/controllers/internal_helpers_test.rb +29 -8
  80. data/test/controllers/url_helpers_test.rb +2 -1
  81. data/test/devise_test.rb +10 -0
  82. data/test/failure_app_test.rb +86 -22
  83. data/test/generators/active_record_generator_test.rb +24 -0
  84. data/test/generators/devise_generator_test.rb +33 -0
  85. data/test/generators/install_generator_test.rb +13 -0
  86. data/test/generators/mongoid_generator_test.rb +22 -0
  87. data/test/generators/views_generator_test.rb +35 -0
  88. data/test/indifferent_hash.rb +33 -0
  89. data/test/integration/authenticatable_test.rb +165 -62
  90. data/test/integration/database_authenticatable_test.rb +22 -0
  91. data/test/integration/http_authenticatable_test.rb +12 -2
  92. data/test/integration/omniauthable_test.rb +138 -0
  93. data/test/integration/recoverable_test.rb +39 -20
  94. data/test/integration/registerable_test.rb +60 -4
  95. data/test/integration/rememberable_test.rb +72 -29
  96. data/test/integration/timeoutable_test.rb +10 -1
  97. data/test/integration/token_authenticatable_test.rb +55 -6
  98. data/test/mailers/confirmation_instructions_test.rb +4 -0
  99. data/test/mailers/reset_password_instructions_test.rb +4 -0
  100. data/test/mailers/unlock_instructions_test.rb +4 -0
  101. data/test/mapping_test.rb +37 -3
  102. data/test/models/confirmable_test.rb +32 -15
  103. data/test/models/database_authenticatable_test.rb +14 -71
  104. data/test/models/encryptable_test.rb +65 -0
  105. data/test/models/lockable_test.rb +48 -11
  106. data/test/models/recoverable_test.rb +28 -2
  107. data/test/models/rememberable_test.rb +186 -125
  108. data/test/models/token_authenticatable_test.rb +19 -1
  109. data/test/models_test.rb +12 -5
  110. data/test/omniauth/url_helpers_test.rb +54 -0
  111. data/test/orm/mongoid.rb +3 -2
  112. data/test/rails_app/Rakefile +10 -0
  113. data/test/rails_app/app/active_record/admin.rb +4 -1
  114. data/test/rails_app/app/active_record/user.rb +5 -4
  115. data/test/rails_app/app/controllers/{sessions_controller.rb → admins/sessions_controller.rb} +1 -1
  116. data/test/rails_app/app/controllers/application_controller.rb +0 -1
  117. data/test/rails_app/app/controllers/home_controller.rb +9 -0
  118. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +14 -0
  119. data/test/rails_app/app/mongoid/admin.rb +4 -1
  120. data/test/rails_app/app/mongoid/shim.rb +16 -3
  121. data/test/rails_app/app/mongoid/user.rb +5 -5
  122. data/test/rails_app/app/views/admins/index.html.erb +1 -0
  123. data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
  124. data/test/rails_app/app/views/home/index.html.erb +1 -0
  125. data/test/rails_app/app/views/home/private.html.erb +1 -0
  126. data/test/rails_app/app/views/layouts/application.html.erb +24 -0
  127. data/test/rails_app/app/views/users/index.html.erb +1 -0
  128. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +1 -0
  129. data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
  130. data/test/rails_app/config/application.rb +5 -0
  131. data/test/rails_app/config/boot.rb +2 -2
  132. data/test/rails_app/config/database.yml +18 -0
  133. data/test/rails_app/config/initializers/devise.rb +71 -31
  134. data/test/rails_app/config/routes.rb +14 -6
  135. data/test/rails_app/config.ru +4 -0
  136. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +21 -17
  137. data/test/rails_app/db/schema.rb +17 -51
  138. data/test/rails_app/lib/shared_admin.rb +9 -0
  139. data/test/rails_app/lib/shared_user.rb +23 -0
  140. data/test/rails_app/public/404.html +26 -0
  141. data/test/rails_app/public/422.html +26 -0
  142. data/test/rails_app/public/500.html +26 -0
  143. data/test/rails_app/public/favicon.ico +0 -0
  144. data/test/rails_app/script/rails +10 -0
  145. data/test/routes_test.rb +42 -9
  146. data/test/schema_test.rb +33 -0
  147. data/test/support/integration.rb +4 -4
  148. data/test/support/locale/en.yml +4 -0
  149. data/test/support/webrat/integrations/rails.rb +11 -19
  150. data/test/test_helper.rb +8 -2
  151. data/test/test_helpers_test.rb +64 -2
  152. metadata +106 -30
  153. data/TODO +0 -3
  154. data/lib/devise/encryptors/bcrypt.rb +0 -19
  155. data/lib/generators/devise_install_generator.rb +0 -4
  156. data/lib/generators/devise_views_generator.rb +0 -4
  157. data/test/support/test_silencer.rb +0 -5
@@ -1,6 +1,6 @@
1
1
  class Devise::Mailer < ::ActionMailer::Base
2
2
  include Devise::Controllers::ScopedViews
3
- attr_reader :devise_mapping, :resource
3
+ attr_reader :scope_name, :resource
4
4
 
5
5
  def confirmation_instructions(record)
6
6
  setup_mail(record, :confirmation_instructions)
@@ -18,19 +18,36 @@ class Devise::Mailer < ::ActionMailer::Base
18
18
 
19
19
  # Configure default email options
20
20
  def setup_mail(record, action)
21
- @scope_name = Devise::Mapping.find_scope!(record)
22
- @devise_mapping = Devise.mappings[@scope_name]
23
- @resource = instance_variable_set("@#{@devise_mapping.name}", record)
21
+ initialize_from_record(record)
22
+ mail headers_for(action)
23
+ end
24
+
25
+ def initialize_from_record(record)
26
+ @scope_name = Devise::Mapping.find_scope!(record)
27
+ @resource = instance_variable_set("@#{devise_mapping.name}", record)
28
+ end
29
+
30
+ def devise_mapping
31
+ @devise_mapping ||= Devise.mappings[scope_name]
32
+ end
24
33
 
34
+ def headers_for(action)
25
35
  headers = {
26
- :subject => translate(@devise_mapping, action),
27
- :from => mailer_sender(@devise_mapping),
28
- :to => record.email,
36
+ :subject => translate(devise_mapping, action),
37
+ :from => mailer_sender(devise_mapping),
38
+ :to => resource.email,
29
39
  :template_path => template_paths
30
40
  }
31
41
 
32
- headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
33
- mail(headers)
42
+ if resource.respond_to?(:headers_for)
43
+ headers.merge!(resource.headers_for(action))
44
+ end
45
+
46
+ unless headers.key?(:reply_to)
47
+ headers[:reply_to] = headers[:from]
48
+ end
49
+
50
+ headers
34
51
  end
35
52
 
36
53
  def mailer_sender(mapping)
@@ -43,7 +60,7 @@ class Devise::Mailer < ::ActionMailer::Base
43
60
 
44
61
  def template_paths
45
62
  template_path = [self.class.mailer_name]
46
- template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
63
+ template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
47
64
  template_path
48
65
  end
49
66
 
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Resend confirmation instructions" %></p>
10
10
  <% end %>
@@ -4,10 +4,10 @@
4
4
  <%= devise_error_messages! %>
5
5
  <%= f.hidden_field :reset_password_token %>
6
6
 
7
- <p><%= f.label :password %><br />
7
+ <p><%= f.label :password, "New password" %><br />
8
8
  <%= f.password_field :password %></p>
9
9
 
10
- <p><%= f.label :password_confirmation %><br />
10
+ <p><%= f.label :password_confirmation, "Confirm new password" %><br />
11
11
  <%= f.password_field :password_confirmation %></p>
12
12
 
13
13
  <p><%= f.submit "Change my password" %></p>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Send me reset password instructions" %></p>
10
10
  <% end %>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
10
10
  <%= f.password_field :password %></p>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.label :password %><br />
10
10
  <%= f.password_field :password %></p>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
4
4
  <p><%= f.label :email %><br />
5
- <%= f.text_field :email %></p>
5
+ <%= f.email_field :email %></p>
6
6
 
7
7
  <p><%= f.label :password %><br />
8
8
  <%= f.password_field :password %></p>
@@ -17,3 +17,9 @@
17
17
  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18
18
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
19
19
  <% end -%>
20
+
21
+ <%- if devise_mapping.omniauthable? %>
22
+ <%- resource_class.omniauth_providers.each do |provider| %>
23
+ <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
24
+ <% end -%>
25
+ <% end -%>
@@ -4,7 +4,7 @@
4
4
  <%= devise_error_messages! %>
5
5
 
6
6
  <p><%= f.label :email %><br />
7
- <%= f.text_field :email %></p>
7
+ <%= f.email_field :email %></p>
8
8
 
9
9
  <p><%= f.submit "Resend unlock instructions" %></p>
10
10
  <% end %>
@@ -1,9 +1,14 @@
1
+ # Additional translations at http://github.com/plataformatec/devise/wiki/I18n
2
+
1
3
  en:
2
4
  errors:
3
5
  messages:
4
6
  not_found: "not found"
5
- already_confirmed: "was already confirmed"
7
+ already_confirmed: "was already confirmed, please try signing in"
6
8
  not_locked: "was not locked"
9
+ not_saved:
10
+ one: "1 error prohibited this %{resource} from being saved:"
11
+ other: "%{count} errors prohibited this %{resource} from being saved:"
7
12
 
8
13
  devise:
9
14
  failure:
@@ -24,12 +29,16 @@ en:
24
29
  send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
25
30
  confirmed: 'Your account was successfully confirmed. You are now signed in.'
26
31
  registrations:
27
- signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
32
+ signed_up: 'Welcome! You have signed up successfully.'
33
+ inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
28
34
  updated: 'You updated your account successfully.'
29
35
  destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
30
36
  unlocks:
31
37
  send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
32
38
  unlocked: 'Your account was successfully unlocked. You are now signed in.'
39
+ omniauth_callbacks:
40
+ success: 'Successfully authorized from %{kind} account.'
41
+ failure: 'Could not authorize you from %{kind} because "%{reason}".'
33
42
  mailer:
34
43
  confirmation_instructions:
35
44
  subject: 'Confirmation instructions'
data/devise.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "devise/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "devise"
7
+ s.version = Devise::VERSION.dup
8
+ s.platform = Gem::Platform::RUBY
9
+ s.summary = "Flexible authentication solution for Rails with Warden"
10
+ s.email = "contact@plataformatec.com.br"
11
+ s.homepage = "http://github.com/plataformatec/devise"
12
+ s.description = "Flexible authentication solution for Rails with Warden"
13
+ s.authors = ['José Valim', 'Carlos Antônio']
14
+
15
+ s.rubyforge_project = "devise"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency("warden", "~> 1.0.3")
23
+ s.add_dependency("orm_adapter", "~> 0.0.3")
24
+ s.add_dependency("bcrypt-ruby", "~> 2.1.2")
25
+ end
@@ -5,8 +5,57 @@ module Devise
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- helper_method :warden, :signed_in?, :devise_controller?, :anybody_signed_in?,
9
- *Devise.mappings.keys.map { |m| [:"current_#{m}", :"#{m}_signed_in?", :"#{m}_session"] }.flatten
8
+ helper_method :warden, :signed_in?, :devise_controller?, :anybody_signed_in?
9
+ end
10
+
11
+ # Define authentication filters and accessor helpers based on mappings.
12
+ # These filters should be used inside the controllers as before_filters,
13
+ # so you can control the scope of the user who should be signed in to
14
+ # access that specific controller/action.
15
+ # Example:
16
+ #
17
+ # Roles:
18
+ # User
19
+ # Admin
20
+ #
21
+ # Generated methods:
22
+ # authenticate_user! # Signs user in or redirect
23
+ # authenticate_admin! # Signs admin in or redirect
24
+ # user_signed_in? # Checks whether there is a user signed in or not
25
+ # admin_signed_in? # Checks whether there is an admin signed in or not
26
+ # current_user # Current signed in user
27
+ # current_admin # Current signed in admin
28
+ # user_session # Session data available only to the user scope
29
+ # admin_session # Session data available only to the admin scope
30
+ #
31
+ # Use:
32
+ # before_filter :authenticate_user! # Tell devise to use :user map
33
+ # before_filter :authenticate_admin! # Tell devise to use :admin map
34
+ #
35
+ def self.define_helpers(mapping) #:nodoc:
36
+ mapping = mapping.name
37
+
38
+ class_eval <<-METHODS, __FILE__, __LINE__ + 1
39
+ def authenticate_#{mapping}!(force = false)
40
+ warden.authenticate!(:scope => :#{mapping}) if !devise_controller? || force
41
+ end
42
+
43
+ def #{mapping}_signed_in?
44
+ !!current_#{mapping}
45
+ end
46
+
47
+ def current_#{mapping}
48
+ @current_#{mapping} ||= warden.authenticate(:scope => :#{mapping})
49
+ end
50
+
51
+ def #{mapping}_session
52
+ current_#{mapping} && warden.session(:#{mapping})
53
+ end
54
+ METHODS
55
+
56
+ ActiveSupport.on_load(:action_controller) do
57
+ helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
58
+ end
10
59
  end
11
60
 
12
61
  # The main accessor for the warden proxy instance
@@ -16,40 +65,59 @@ module Devise
16
65
 
17
66
  # Return true if it's a devise_controller. false to all controllers unless
18
67
  # the controllers defined inside devise. Useful if you want to apply a before
19
- # filter to all controller, except the ones in devise:
68
+ # filter to all controllers, except the ones in devise:
20
69
  #
21
70
  # before_filter :my_filter, :unless => { |c| c.devise_controller? }
22
71
  def devise_controller?
23
72
  false
24
73
  end
25
74
 
26
- # Check if the given scope is signed in session, without running
27
- # authentication hooks.
28
- def signed_in?(scope)
29
- warden.authenticate?(:scope => scope)
75
+ # Return true if the given scope is signed in session. If no scope given, return
76
+ # true if any scope is signed in. Does not run authentication hooks.
77
+ def signed_in?(scope=nil)
78
+ [ scope || Devise.mappings.keys ].flatten.any? do |scope|
79
+ warden.authenticate?(:scope => scope)
80
+ end
30
81
  end
31
82
 
32
- # Check if the any scope is signed in session, without running
33
- # authentication hooks.
34
83
  def anybody_signed_in?
35
- Devise.mappings.keys.any? { |scope| signed_in?(scope) }
84
+ ActiveSupport::Deprecation.warn "Devise#anybody_signed_in? is deprecated. "
85
+ "Please use Devise#signed_in?(nil) instead."
86
+ signed_in?
36
87
  end
37
88
 
38
- # Sign in an user that already was authenticated. This helper is useful for logging
89
+ # Sign in a user that already was authenticated. This helper is useful for logging
39
90
  # users in after sign up.
40
91
  #
41
- # Examples:
92
+ # All options given to sign_in is passed forward to the set_user method in warden.
93
+ # The only exception is the :bypass option, which bypass warden callbacks and stores
94
+ # the user straight in session. This option is useful in cases the user is already
95
+ # signed in, but we want to refresh the credentials in session.
42
96
  #
43
- # sign_in :user, @user # sign_in(scope, resource)
44
- # sign_in @user # sign_in(resource)
97
+ # Examples:
45
98
  #
46
- def sign_in(resource_or_scope, resource=nil)
47
- scope = Devise::Mapping.find_scope!(resource_or_scope)
48
- resource ||= resource_or_scope
49
- warden.set_user(resource, :scope => scope)
99
+ # sign_in :user, @user # sign_in(scope, resource)
100
+ # sign_in @user # sign_in(resource)
101
+ # sign_in @user, :event => :authentication # sign_in(resource, options)
102
+ # sign_in @user, :bypass => true # sign_in(resource, options)
103
+ #
104
+ def sign_in(resource_or_scope, *args)
105
+ options = args.extract_options!
106
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
107
+ resource = args.last || resource_or_scope
108
+
109
+ expire_session_data_after_sign_in!
110
+
111
+ if options[:bypass]
112
+ warden.session_serializer.store(resource, scope)
113
+ elsif warden.user(scope) == resource && !options.delete(:force)
114
+ # Do nothing. User already signed in and we are not forcing it.
115
+ else
116
+ warden.set_user(resource, options.merge!(:scope => scope))
117
+ end
50
118
  end
51
119
 
52
- # Sign out a given user or scope. This helper is useful for signing out an user
120
+ # Sign out a given user or scope. This helper is useful for signing out a user
53
121
  # after deleting accounts.
54
122
  #
55
123
  # Examples:
@@ -57,7 +125,8 @@ module Devise
57
125
  # sign_out :user # sign_out(scope)
58
126
  # sign_out @user # sign_out(resource)
59
127
  #
60
- def sign_out(resource_or_scope)
128
+ def sign_out(resource_or_scope=nil)
129
+ return sign_out_all_scopes unless resource_or_scope
61
130
  scope = Devise::Mapping.find_scope!(resource_or_scope)
62
131
  warden.user(scope) # Without loading user here, before_logout hook is not called
63
132
  warden.raw_session.inspect # Without this inspect here. The session does not clear.
@@ -65,13 +134,11 @@ module Devise
65
134
  end
66
135
 
67
136
  # Sign out all active users or scopes. This helper is useful for signing out all roles
68
- # in one click.
137
+ # in one click. This signs out ALL scopes in warden.
69
138
  def sign_out_all_scopes
70
- # Not "warden.logout" since we need to sign_out only devise-defined scopes.
71
- scopes = Devise.mappings.keys
72
- scopes.each { |scope| warden.user(scope) }
139
+ Devise.mappings.keys.each { |s| warden.user(s) }
73
140
  warden.raw_session.inspect
74
- warden.logout(*scopes)
141
+ warden.logout
75
142
  end
76
143
 
77
144
  # Returns and delete the url stored in the session for the given scope. Useful
@@ -83,7 +150,7 @@ module Devise
83
150
  #
84
151
  def stored_location_for(resource_or_scope)
85
152
  scope = Devise::Mapping.find_scope!(resource_or_scope)
86
- session.delete(:"#{scope}_return_to")
153
+ session.delete("#{scope}_return_to")
87
154
  end
88
155
 
89
156
  # The default url to be used after signing in. This is used by all Devise
@@ -114,41 +181,11 @@ module Devise
114
181
  #
115
182
  def after_sign_in_path_for(resource_or_scope)
116
183
  scope = Devise::Mapping.find_scope!(resource_or_scope)
117
- home_path = :"#{scope}_root_path"
184
+ home_path = "#{scope}_root_path"
118
185
  respond_to?(home_path, true) ? send(home_path) : root_path
119
186
  end
120
187
 
121
- # The default url to be used after updating a resource. This is used by all Devise
122
- # controllers and you can overwrite it in your ApplicationController to
123
- # provide a custom hook for a custom resource.
124
- #
125
- # By default, it first tries to find a resource_root_path, otherwise it
126
- # uses the root path. For a user scope, you can define the default url in
127
- # the following way:
128
- #
129
- # map.user_root '/users', :controller => 'users' # creates user_root_path
130
- #
131
- # map.resources :users do |users|
132
- # users.root # creates user_root_path
133
- # end
134
- #
135
- #
136
- # If none of these are defined, root_path is used. However, if this default
137
- # is not enough, you can customize it, for example:
138
- #
139
- # def after_update_path_for(resource)
140
- # if resource.is_a?(User) && resource.can_publish?
141
- # publisher_url
142
- # else
143
- # super
144
- # end
145
- # end
146
- #
147
- def after_update_path_for(resource_or_scope)
148
- after_sign_in_path_for(resource_or_scope)
149
- end
150
-
151
- # Method used by sessions controller to sign out an user. You can overwrite
188
+ # Method used by sessions controller to sign out a user. You can overwrite
152
189
  # it in your ApplicationController to provide a custom hook for a custom
153
190
  # scope. Notice that differently from +after_sign_in_path_for+ this method
154
191
  # receives a symbol with the scope, and not the resource.
@@ -158,74 +195,40 @@ module Devise
158
195
  root_path
159
196
  end
160
197
 
161
- # Sign in an user and tries to redirect first to the stored location and
162
- # then to the url specified by after_sign_in_path_for.
163
- #
164
- # If just a symbol is given, consider that the user was already signed in
165
- # through other means and just perform the redirection.
166
- def sign_in_and_redirect(resource_or_scope, resource=nil)
167
- scope = Devise::Mapping.find_scope!(resource_or_scope)
168
- resource ||= resource_or_scope
169
- sign_in(scope, resource) unless warden.user(scope) == resource
170
- redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
198
+ # Sign in a user and tries to redirect first to the stored location and
199
+ # then to the url specified by after_sign_in_path_for. It accepts the same
200
+ # parameters as the sign_in method.
201
+ def sign_in_and_redirect(resource_or_scope, *args)
202
+ options = args.extract_options!
203
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
204
+ resource = args.last || resource_or_scope
205
+ sign_in(scope, resource, options)
206
+ redirect_to redirect_location(scope, resource)
171
207
  end
172
208
 
173
- # Sign out an user and tries to redirect to the url specified by
209
+ def redirect_location(scope, resource) #:nodoc:
210
+ stored_location_for(scope) || after_sign_in_path_for(resource)
211
+ end
212
+
213
+ # Sign out a user and tries to redirect to the url specified by
174
214
  # after_sign_out_path_for.
175
215
  def sign_out_and_redirect(resource_or_scope)
176
216
  scope = Devise::Mapping.find_scope!(resource_or_scope)
177
- if Devise.sign_out_all_scopes
178
- sign_out_all_scopes
179
- else
180
- sign_out(scope)
181
- end
217
+ Devise.sign_out_all_scopes ? sign_out : sign_out(scope)
182
218
  redirect_to after_sign_out_path_for(scope)
183
219
  end
184
220
 
185
- # Define authentication filters and accessor helpers based on mappings.
186
- # These filters should be used inside the controllers as before_filters,
187
- # so you can control the scope of the user who should be signed in to
188
- # access that specific controller/action.
189
- # Example:
190
- #
191
- # Roles:
192
- # User
193
- # Admin
194
- #
195
- # Generated methods:
196
- # authenticate_user! # Signs user in or redirect
197
- # authenticate_admin! # Signs admin in or redirect
198
- # user_signed_in? # Checks whether there is an user signed in or not
199
- # admin_signed_in? # Checks whether there is an admin signed in or not
200
- # current_user # Current signed in user
201
- # current_admin # Currend signed in admin
202
- # user_session # Session data available only to the user scope
203
- # admin_session # Session data available only to the admin scope
204
- #
205
- # Use:
206
- # before_filter :authenticate_user! # Tell devise to use :user map
207
- # before_filter :authenticate_admin! # Tell devise to use :admin map
208
- #
209
- Devise.mappings.each_key do |mapping|
210
- class_eval <<-METHODS, __FILE__, __LINE__ + 1
211
- def authenticate_#{mapping}!
212
- warden.authenticate!(:scope => :#{mapping})
213
- end
214
-
215
- def #{mapping}_signed_in?
216
- warden.authenticate?(:scope => :#{mapping})
217
- end
218
-
219
- def current_#{mapping}
220
- @current_#{mapping} ||= warden.authenticate(:scope => :#{mapping})
221
- end
222
-
223
- def #{mapping}_session
224
- current_#{mapping} && warden.session(:#{mapping})
225
- end
226
- METHODS
221
+ # A hook called to expire session data after sign up/in. All keys
222
+ # stored under "devise." namespace are removed after sign in.
223
+ def expire_session_data_after_sign_in!
224
+ session.keys.grep(/^devise\./).each { |k| session.delete(k) }
227
225
  end
228
226
 
227
+ # Overwrite Rails' handle unverified request to sign out all scopes.
228
+ def handle_unverified_request
229
+ sign_out_all_scopes
230
+ super # call the default behaviour which resets the session
231
+ end
229
232
  end
230
233
  end
231
234
  end
@@ -10,13 +10,13 @@ module Devise
10
10
  included do
11
11
  helper DeviseHelper
12
12
 
13
- helpers = %w(resource scope_name resource_name
13
+ helpers = %w(resource scope_name resource_name signed_in_resource
14
14
  resource_class devise_mapping devise_controller?)
15
15
  hide_action *helpers
16
16
  helper_method *helpers
17
17
 
18
18
  prepend_before_filter :is_devise_resource?
19
- skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
19
+ respond_to *Mime::SET.map(&:to_sym) if mimes_for_respond_to.empty?
20
20
  end
21
21
 
22
22
  # Gets the actual resource stored in the instance variable
@@ -35,6 +35,11 @@ module Devise
35
35
  devise_mapping.to
36
36
  end
37
37
 
38
+ # Returns a signed in resource from session (if one exists)
39
+ def signed_in_resource
40
+ warden.authenticate(:scope => resource_name)
41
+ end
42
+
38
43
  # Attempt to find the mapped route for devise based on request path
39
44
  def devise_mapping
40
45
  @devise_mapping ||= request.env["devise.mapping"]
@@ -49,7 +54,17 @@ module Devise
49
54
 
50
55
  # Checks whether it's a devise mapped resource or not.
51
56
  def is_devise_resource? #:nodoc:
52
- raise ActionController::UnknownAction unless devise_mapping
57
+ unknown_action!("Could not find devise mapping for path #{request.fullpath.inspect}") unless devise_mapping
58
+ end
59
+
60
+ # Check whether it's navigational format, such as :html or :iphone, or not.
61
+ def is_navigational_format?
62
+ Devise.navigational_formats.include?(request.format.to_sym)
63
+ end
64
+
65
+ def unknown_action!(msg)
66
+ logger.debug "[Devise] #{msg}" if logger
67
+ raise ActionController::UnknownAction, msg
53
68
  end
54
69
 
55
70
  # Sets the resource creating an instance variable
@@ -68,7 +83,10 @@ module Devise
68
83
  # Example:
69
84
  # before_filter :require_no_authentication, :only => :new
70
85
  def require_no_authentication
71
- redirect_to after_sign_in_path_for(resource_name) if warden.authenticated?(resource_name)
86
+ if warden.authenticated?(resource_name)
87
+ resource = warden.user(resource_name)
88
+ redirect_to after_sign_in_path_for(resource)
89
+ end
72
90
  end
73
91
 
74
92
  # Sets the flash message with :key, using I18n. By default you are able
@@ -85,12 +103,15 @@ module Devise
85
103
  #
86
104
  # Please refer to README or en.yml locale file to check what messages are
87
105
  # available.
88
- def set_flash_message(key, kind)
89
- flash[key] = I18n.t(:"#{resource_name}.#{kind}", :resource_name => resource_name,
90
- :scope => [:devise, controller_name.to_sym], :default => kind)
106
+ def set_flash_message(key, kind, options={}) #:nodoc:
107
+ options[:scope] = "devise.#{controller_name}"
108
+ options[:default] = Array(options[:default]).unshift(kind.to_sym)
109
+ options[:resource_name] = resource_name
110
+ message = I18n.t("#{resource_name}.#{kind}", options)
111
+ flash[key] = message if message.present?
91
112
  end
92
113
 
93
- def clean_up_passwords(object)
114
+ def clean_up_passwords(object) #:nodoc:
94
115
  object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
95
116
  end
96
117
  end
@@ -0,0 +1,52 @@
1
+ module Devise
2
+ module Controllers
3
+ # A module that may be optionally included in a controller in order
4
+ # to provide remember me behavior.
5
+ module Rememberable
6
+ # Return default cookie values retrieved from session options.
7
+ def self.cookie_values
8
+ Rails.configuration.session_options.slice(:path, :domain, :secure)
9
+ end
10
+
11
+ # A small warden proxy so we can remember and forget uses from hooks.
12
+ class Proxy #:nodoc:
13
+ include Devise::Controllers::Rememberable
14
+
15
+ delegate :cookies, :env, :to => :@warden
16
+
17
+ def initialize(warden)
18
+ @warden = warden
19
+ end
20
+ end
21
+
22
+ # Remembers the given resource by setting up a cookie
23
+ def remember_me(resource)
24
+ scope = Devise::Mapping.find_scope!(resource)
25
+ resource.remember_me!(resource.extend_remember_period)
26
+ cookies.signed["remember_#{scope}_token"] = remember_cookie_values(resource)
27
+ end
28
+
29
+ # Forgets the given resource by deleting a cookie
30
+ def forget_me(resource)
31
+ scope = Devise::Mapping.find_scope!(resource)
32
+ resource.forget_me! unless resource.frozen?
33
+ cookies.delete("remember_#{scope}_token", forget_cookie_values(resource))
34
+ end
35
+
36
+ protected
37
+
38
+ def forget_cookie_values(resource)
39
+ Devise::Controllers::Rememberable.cookie_values.merge!(resource.cookie_options)
40
+ end
41
+
42
+ def remember_cookie_values(resource)
43
+ options = { :httponly => true }
44
+ options.merge!(forget_cookie_values(resource))
45
+ options.merge!(
46
+ :value => resource.class.serialize_into_cookie(resource),
47
+ :expires => resource.remember_expires_at
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end