devise 1.1.rc2 → 1.1.0

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 (77) hide show
  1. data/CHANGELOG.rdoc +22 -2
  2. data/Gemfile +7 -13
  3. data/Gemfile.lock +118 -0
  4. data/README.rdoc +15 -13
  5. data/app/controllers/devise/unlocks_controller.rb +0 -7
  6. data/app/mailers/devise/mailer.rb +7 -4
  7. data/app/views/devise/confirmations/new.html.erb +1 -1
  8. data/app/views/devise/passwords/new.html.erb +1 -1
  9. data/app/views/devise/unlocks/new.html.erb +1 -1
  10. data/lib/devise.rb +27 -9
  11. data/lib/devise/controllers/helpers.rb +19 -5
  12. data/lib/devise/controllers/internal_helpers.rb +2 -8
  13. data/lib/devise/encryptors/base.rb +1 -1
  14. data/lib/devise/encryptors/bcrypt.rb +2 -2
  15. data/lib/devise/failure_app.rb +6 -2
  16. data/lib/devise/hooks/rememberable.rb +9 -1
  17. data/lib/devise/mapping.rb +15 -50
  18. data/lib/devise/models/authenticatable.rb +8 -0
  19. data/lib/devise/models/confirmable.rb +10 -6
  20. data/lib/devise/models/database_authenticatable.rb +9 -1
  21. data/lib/devise/models/recoverable.rb +6 -1
  22. data/lib/devise/models/rememberable.rb +36 -7
  23. data/lib/devise/models/token_authenticatable.rb +5 -5
  24. data/lib/devise/models/validatable.rb +1 -1
  25. data/lib/devise/path_checker.rb +7 -2
  26. data/lib/devise/rails.rb +6 -1
  27. data/lib/devise/rails/routes.rb +137 -50
  28. data/lib/devise/rails/warden_compat.rb +16 -2
  29. data/lib/devise/strategies/authenticatable.rb +12 -0
  30. data/lib/devise/strategies/base.rb +0 -18
  31. data/lib/devise/strategies/rememberable.rb +9 -1
  32. data/lib/devise/test_helpers.rb +2 -0
  33. data/lib/devise/version.rb +1 -1
  34. data/lib/generators/active_record/devise_generator.rb +28 -0
  35. data/lib/generators/{devise/devise → active_record}/templates/migration.rb +4 -0
  36. data/lib/generators/devise/devise_generator.rb +17 -0
  37. data/lib/generators/devise/{install/install_generator.rb → install_generator.rb} +1 -1
  38. data/lib/generators/devise/orm_helpers.rb +23 -0
  39. data/lib/generators/devise/{install/templates → templates}/README +0 -0
  40. data/lib/generators/devise/{install/templates → templates}/devise.rb +20 -13
  41. data/lib/generators/devise/{views/views_generator.rb → views_generator.rb} +2 -2
  42. data/lib/generators/mongoid/devise_generator.rb +17 -0
  43. data/test/controllers/helpers_test.rb +9 -0
  44. data/test/controllers/internal_helpers_test.rb +7 -16
  45. data/test/controllers/url_helpers_test.rb +11 -0
  46. data/test/encryptors_test.rb +1 -1
  47. data/test/failure_app_test.rb +18 -5
  48. data/test/integration/authenticatable_test.rb +76 -11
  49. data/test/integration/confirmable_test.rb +16 -9
  50. data/test/integration/lockable_test.rb +11 -13
  51. data/test/integration/registerable_test.rb +4 -4
  52. data/test/integration/rememberable_test.rb +54 -1
  53. data/test/mapping_test.rb +10 -45
  54. data/test/models/confirmable_test.rb +1 -1
  55. data/test/models/rememberable_test.rb +108 -0
  56. data/test/models/validatable_test.rb +2 -4
  57. data/test/models_test.rb +4 -4
  58. data/test/rails_app/app/active_record/admin.rb +1 -1
  59. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  60. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  61. data/test/rails_app/app/controllers/users_controller.rb +5 -1
  62. data/test/rails_app/app/mongoid/admin.rb +1 -1
  63. data/test/rails_app/config/application.rb +2 -2
  64. data/test/rails_app/config/environments/test.rb +2 -0
  65. data/test/rails_app/config/initializers/devise.rb +95 -34
  66. data/test/rails_app/config/routes.rb +32 -14
  67. data/test/routes_test.rb +34 -2
  68. data/test/support/integration.rb +22 -6
  69. data/test/test_helpers_test.rb +16 -2
  70. metadata +24 -27
  71. data/lib/devise/orm/data_mapper.rb +0 -97
  72. data/lib/generators/devise/devise/devise_generator.rb +0 -86
  73. data/lib/generators/devise_generator.rb +0 -2
  74. data/test/orm/data_mapper.rb +0 -10
  75. data/test/rails_app/app/data_mapper/admin.rb +0 -12
  76. data/test/rails_app/app/data_mapper/shim.rb +0 -2
  77. data/test/rails_app/app/data_mapper/user.rb +0 -23
@@ -15,11 +15,25 @@ end
15
15
 
16
16
  class Warden::SessionSerializer
17
17
  def serialize(record)
18
- [record.class, record.id]
18
+ [record.class.name, record.id]
19
19
  end
20
20
 
21
21
  def deserialize(keys)
22
22
  klass, id = keys
23
- klass.find(:first, :conditions => { :id => id })
23
+
24
+ if klass.is_a?(Class)
25
+ raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
26
+ "you can fix it by changing one character in your cookie secret, forcing all previous " <<
27
+ "cookies to expire, or cleaning up your database sessions if you are using a db store."
28
+ end
29
+
30
+ klass.constantize.find(:first, :conditions => { :id => id })
31
+ rescue NameError => e
32
+ if e.message =~ /uninitialized constant/
33
+ Rails.logger.debug "Trying to deserialize invalid class #{klass}"
34
+ nil
35
+ else
36
+ raise
37
+ end
24
38
  end
25
39
  end
@@ -14,6 +14,18 @@ module Devise
14
14
 
15
15
  private
16
16
 
17
+ # Simply invokes valid_for_authentication? with the given block and deal with the result.
18
+ def validate(resource, &block)
19
+ result = resource && resource.valid_for_authentication?(&block)
20
+
21
+ case result
22
+ when Symbol, String
23
+ fail!(result)
24
+ else
25
+ result
26
+ end
27
+ end
28
+
17
29
  # Check if this is strategy is valid for http authentication by:
18
30
  #
19
31
  # * Validating if the model allows params authentication;
@@ -10,24 +10,6 @@ module Devise
10
10
  mapping
11
11
  end
12
12
  end
13
-
14
- protected
15
-
16
- def succeeded?
17
- @result == :success
18
- end
19
-
20
- # Simply invokes valid_for_authentication? with the given block and deal with the result.
21
- def validate(resource, &block)
22
- result = resource && resource.valid_for_authentication?(&block)
23
-
24
- case result
25
- when Symbol, String
26
- fail!(result)
27
- else
28
- result
29
- end
30
- end
31
13
  end
32
14
  end
33
15
  end
@@ -6,7 +6,7 @@ module Devise
6
6
  # to verify whether there is a cookie with the remember token, and to
7
7
  # recreate the user from this cookie if it exists. Must be called *before*
8
8
  # authenticatable.
9
- class Rememberable < Devise::Strategies::Base
9
+ class Rememberable < Authenticatable
10
10
  # A valid strategy for rememberable needs a remember token in the cookies.
11
11
  def valid?
12
12
  remember_cookie.present?
@@ -28,10 +28,18 @@ module Devise
28
28
 
29
29
  private
30
30
 
31
+ def remember_me?
32
+ true
33
+ end
34
+
31
35
  def remember_key
32
36
  "remember_#{scope}_token"
33
37
  end
34
38
 
39
+ def extend_remember_period?
40
+ mapping.to.extend_remember_period
41
+ end
42
+
35
43
  # Accessor for remember cookie
36
44
  def remember_cookie
37
45
  @remember_cookie ||= cookies.signed[remember_key]
@@ -42,6 +42,8 @@ module Devise
42
42
  status, headers, body = Devise::FailureApp.call(env).to_a
43
43
  @controller.send :render, :status => status, :text => body,
44
44
  :content_type => headers["Content-Type"], :location => headers["Location"]
45
+
46
+ nil
45
47
  else
46
48
  result
47
49
  end
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "1.1.rc2".freeze
2
+ VERSION = "1.1.0".freeze
3
3
  end
@@ -0,0 +1,28 @@
1
+ require 'rails/generators/active_record'
2
+ require 'generators/devise/orm_helpers'
3
+
4
+ module ActiveRecord
5
+ module Generators
6
+ class DeviseGenerator < ActiveRecord::Generators::Base
7
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
8
+
9
+ include Devise::Generators::OrmHelpers
10
+ source_root File.expand_path("../templates", __FILE__)
11
+
12
+ def generate_model
13
+ invoke "active_record:model", [name], :migration => false unless model_exists?
14
+ end
15
+
16
+ def copy_devise_migration
17
+ migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
18
+ end
19
+
20
+ def inject_devise_content
21
+ inject_into_class model_path, class_name, model_contents + <<-CONTENT
22
+ # Setup accessible (or protected) attributes for your model
23
+ attr_accessible :email, :password, :password_confirmation, :remember_me
24
+ CONTENT
25
+ end
26
+ end
27
+ end
28
+ end
@@ -10,6 +10,10 @@ class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
10
10
  # t.lockable :lock_strategy => :<%= Devise.lock_strategy %>, :unlock_strategy => :<%= Devise.unlock_strategy %>
11
11
  # t.token_authenticatable
12
12
 
13
+ <% for attribute in attributes -%>
14
+ t.<%= attribute.type %> :<%= attribute.name %>
15
+ <% end -%>
16
+
13
17
  t.timestamps
14
18
  end
15
19
 
@@ -0,0 +1,17 @@
1
+ module Devise
2
+ module Generators
3
+ class DeviseGenerator < Rails::Generators::NamedBase
4
+ namespace "devise"
5
+ source_root File.expand_path("../templates", __FILE__)
6
+
7
+ desc "Generates a model with the given NAME (if one does not exist) with devise " <<
8
+ "configuration plus a migration file and devise routes."
9
+
10
+ hook_for :orm
11
+
12
+ def add_devise_routes
13
+ route "devise_for :#{table_name}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -13,7 +13,7 @@ module Devise
13
13
  end
14
14
 
15
15
  def copy_locale
16
- copy_file "../../../../../config/locales/en.yml", "config/locales/devise.en.yml"
16
+ copy_file "../../../../config/locales/en.yml", "config/locales/devise.en.yml"
17
17
  end
18
18
 
19
19
  def show_readme
@@ -0,0 +1,23 @@
1
+ module Devise
2
+ module Generators
3
+ module OrmHelpers
4
+ def model_contents
5
+ <<-CONTENT
6
+ # Include default devise modules. Others available are:
7
+ # :token_authenticatable, :confirmable, :lockable and :timeoutable
8
+ devise :database_authenticatable, :registerable,
9
+ :recoverable, :rememberable, :trackable, :validatable
10
+
11
+ CONTENT
12
+ end
13
+
14
+ def model_exists?
15
+ File.exists?(File.join(destination_root, model_path))
16
+ end
17
+
18
+ def model_path
19
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
20
+ end
21
+ end
22
+ end
23
+ end
@@ -9,8 +9,9 @@ Devise.setup do |config|
9
9
  # config.mailer = "Devise::Mailer"
10
10
 
11
11
  # ==> ORM configuration
12
- # Load and configure the ORM. Supports :active_record (default), :mongoid
13
- # (bson_ext recommended) and :data_mapper (experimental).
12
+ # Load and configure the ORM. Supports :active_record (default) and
13
+ # :mongoid (bson_ext recommended) by default. Other ORMs may be
14
+ # available as additional gems.
14
15
  require 'devise/orm/<%= options[:orm] %>'
15
16
 
16
17
  # ==> Configuration for any authentication mechanism
@@ -27,6 +28,9 @@ Devise.setup do |config|
27
28
  # Tell if authentication through HTTP Basic Auth is enabled. True by default.
28
29
  # config.http_authenticatable = true
29
30
 
31
+ # Set this to true to use Basic Auth for AJAX requests. True by default.
32
+ # config.http_authenticatable_on_xhr = true
33
+
30
34
  # The realm used in Http Basic Authentication
31
35
  # config.http_authentication_realm = "Application"
32
36
 
@@ -57,6 +61,12 @@ Devise.setup do |config|
57
61
  # The time the user will be remembered without asking for credentials again.
58
62
  # config.remember_for = 2.weeks
59
63
 
64
+ # If true, a valid remember token can be re-used between multiple browsers.
65
+ # config.remember_across_browsers = true
66
+
67
+ # If true, extends the user's remember period when remembered via cookie.
68
+ # config.extend_remember_period = false
69
+
60
70
  # ==> Configuration for :validatable
61
71
  # Range for password length
62
72
  # config.password_length = 6..20
@@ -95,22 +105,19 @@ Devise.setup do |config|
95
105
 
96
106
  # ==> Scopes configuration
97
107
  # Turn scoped views on. Before rendering "sessions/new", it will first check for
98
- # "sessions/users/new". It's turned off by default because it's slower if you
108
+ # "users/sessions/new". It's turned off by default because it's slower if you
99
109
  # are using only default views.
100
110
  # config.scoped_views = true
101
111
 
102
- # By default, devise detects the role accessed based on the url. So whenever
103
- # accessing "/users/sign_in", it knows you are accessing an User. This makes
104
- # routes as "/sign_in" not possible, unless you tell Devise to use the default
105
- # scope, setting true below.
106
- # Note that devise does not generate default routes. You also have to
107
- # specify them in config/routes.rb
108
- # config.use_default_scope = true
109
-
110
- # Configure the default scope used by Devise. By default it's the first devise
111
- # role declared in your routes.
112
+ # Configure the default scope given to Warden. By default it's the first
113
+ # devise role declared in your routes.
112
114
  # config.default_scope = :user
113
115
 
116
+ # Configure sign_out behavior.
117
+ # By default sign_out is scoped (i.e. /users/sign_out affects only :user scope).
118
+ # In case of sign_out_all_scopes set to true any logout action will sign out all active scopes.
119
+ # config.sign_out_all_scopes = false
120
+
114
121
  # ==> Navigation configuration
115
122
  # Lists the formats that should be treated as navigational. Formats like
116
123
  # :html, should redirect to the sign in page when the user does not have
@@ -1,7 +1,7 @@
1
1
  module Devise
2
2
  module Generators
3
3
  class ViewsGenerator < Rails::Generators::Base
4
- source_root File.expand_path("../../../../../app/views", __FILE__)
4
+ source_root File.expand_path("../../../../app/views", __FILE__)
5
5
  desc "Copies all Devise views to your application."
6
6
 
7
7
  argument :scope, :required => false, :default => nil,
@@ -11,7 +11,7 @@ module Devise
11
11
  :desc => "Template engine for the views. Available options are 'erb' and 'haml'."
12
12
 
13
13
  def copy_views
14
- case options[:template_engine]
14
+ case options[:template_engine].to_s
15
15
  when "haml"
16
16
  verify_haml_existence
17
17
  verify_haml_version
@@ -0,0 +1,17 @@
1
+ require 'generators/devise/orm_helpers'
2
+
3
+ module Mongoid
4
+ module Generators
5
+ class DeviseGenerator < Rails::Generators::NamedBase
6
+ include Devise::Generators::OrmHelpers
7
+
8
+ def generate_model
9
+ invoke "mongoid:model", [name] unless model_exists?
10
+ end
11
+
12
+ def inject_devise_content
13
+ inject_into_file model_path, model_contents, :after => "include Mongoid::Document\n"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -126,6 +126,15 @@ class ControllerAuthenticableTest < ActionController::TestCase
126
126
  @controller.sign_out(User.new)
127
127
  end
128
128
 
129
+ test 'sign out everybody proxy to logout on warden' do
130
+ Devise.mappings.keys.each { |scope|
131
+ @mock_warden.expects(:user).with(scope).returns(true)
132
+ }
133
+
134
+ @mock_warden.expects(:logout).with(*Devise.mappings.keys).returns(true)
135
+ @controller.sign_out_all_scopes
136
+ end
137
+
129
138
  test 'stored location for returns the location for a given scope' do
130
139
  assert_nil @controller.stored_location_for(:user)
131
140
  @controller.session[:"user_return_to"] = "/foo.bar"
@@ -10,37 +10,28 @@ class HelpersTest < ActionController::TestCase
10
10
  def setup
11
11
  @mock_warden = OpenStruct.new
12
12
  @controller.request.env['warden'] = @mock_warden
13
+ @controller.request.env['devise.mapping'] = Devise.mappings[:user]
13
14
  end
14
15
 
15
- test 'get resource name from request path' do
16
- @request.path = '/users/session'
16
+ test 'get resource name from env' do
17
17
  assert_equal :user, @controller.resource_name
18
18
  end
19
19
 
20
- test 'get resource name from specific request path' do
21
- @request.path = '/admin_area/session'
22
- assert_equal :admin, @controller.resource_name
23
- end
24
-
25
- test 'get resource class from request path' do
26
- @request.path = '/users/session'
20
+ test 'get resource class from env' do
27
21
  assert_equal User, @controller.resource_class
28
22
  end
29
23
 
30
- test 'get resource instance variable from request path' do
31
- @request.path = '/admin_area/session'
32
- @controller.instance_variable_set(:@admin, admin = Admin.new)
24
+ test 'get resource instance variable from env' do
25
+ @controller.instance_variable_set(:@user, admin = Admin.new)
33
26
  assert_equal admin, @controller.resource
34
27
  end
35
28
 
36
- test 'set resource instance variable from request path' do
37
- @request.path = '/admin_area/session'
38
-
29
+ test 'set resource instance variable from env' do
39
30
  admin = @controller.send(:resource_class).new
40
31
  @controller.send(:resource=, admin)
41
32
 
42
33
  assert_equal admin, @controller.send(:resource)
43
- assert_equal admin, @controller.instance_variable_get(:@admin)
34
+ assert_equal admin, @controller.instance_variable_get(:@user)
44
35
  end
45
36
 
46
37
  test 'resources methods are not controller actions' do
@@ -44,4 +44,15 @@ class RoutesTest < ActionController::TestCase
44
44
  assert_path_and_url :confirmation
45
45
  assert_path_and_url :confirmation, :new
46
46
  end
47
+
48
+ test 'should alias unlock to mapped user unlock' do
49
+ assert_path_and_url :unlock
50
+ assert_path_and_url :unlock, :new
51
+ end
52
+
53
+ test 'should alias registration to mapped user registration' do
54
+ assert_path_and_url :registration
55
+ assert_path_and_url :registration, :new
56
+ assert_path_and_url :registration, :edit
57
+ end
47
58
  end
@@ -23,7 +23,7 @@ class Encryptors < ActiveSupport::TestCase
23
23
  test "should have length #{value} for #{key.inspect}" do
24
24
  swap Devise, :encryptor => key do
25
25
  encryptor = Devise::Encryptors.const_get(key.to_s.classify)
26
- assert_equal value, encryptor.digest('a', 4, encryptor.salt, nil).size
26
+ assert_equal value, encryptor.digest('a', 4, encryptor.salt(4), nil).size
27
27
  end
28
28
  end
29
29
  end
@@ -77,6 +77,23 @@ class FailureTest < ActiveSupport::TestCase
77
77
  assert_equal 'Basic realm="Application"', @response.second["WWW-Authenticate"]
78
78
  end
79
79
 
80
+ test 'dont return WWW-authenticate on ajax call if http_authenticatable_on_xhr false' do
81
+ swap Devise, :http_authenticatable_on_xhr => false do
82
+ call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
83
+ assert_equal 302, @response.first
84
+ assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
85
+ assert_nil @response.second['WWW-Authenticate']
86
+ end
87
+ end
88
+
89
+ test 'return WWW-authenticate on ajax call if http_authenticatable_on_xhr true' do
90
+ swap Devise, :http_authenticatable_on_xhr => true do
91
+ call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
92
+ assert_equal 401, @response.first
93
+ assert_equal 'Basic realm="Application"', @response.second["WWW-Authenticate"]
94
+ end
95
+ end
96
+
80
97
  test 'uses the proxy failure message as response body' do
81
98
  call_failure('formats' => :xml, 'warden' => OpenStruct.new(:message => :invalid))
82
99
  assert_match '<error>Invalid email or password.</error>', @response.third.body
@@ -88,11 +105,6 @@ class FailureTest < ActiveSupport::TestCase
88
105
  assert_equal 401, @response.first
89
106
  end
90
107
  end
91
-
92
- test 'works for xml http requests' do
93
- call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
94
- assert_equal 401, @response.first
95
- end
96
108
  end
97
109
 
98
110
  context 'With recall' do
@@ -100,6 +112,7 @@ class FailureTest < ActiveSupport::TestCase
100
112
  env = {
101
113
  "action_dispatch.request.parameters" => { :controller => "devise/sessions" },
102
114
  "warden.options" => { :recall => "new", :attempted_path => "/users/sign_in" },
115
+ "devise.mapping" => Devise.mappings[:user],
103
116
  "warden" => stub_everything
104
117
  }
105
118
  call_failure(env)