devise 2.1.0.rc → 2.1.0.rc2

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

Potentially problematic release.


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

Files changed (65) hide show
  1. data/CHANGELOG.rdoc +23 -1
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +4 -6
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +7 -3
  6. data/Rakefile +1 -1
  7. data/app/controllers/devise/sessions_controller.rb +2 -4
  8. data/app/controllers/devise/unlocks_controller.rb +15 -2
  9. data/app/controllers/devise_controller.rb +24 -11
  10. data/devise.gemspec +1 -1
  11. data/gemfiles/Gemfile.rails-3.1.x +1 -1
  12. data/gemfiles/Gemfile.rails-3.1.x.lock +38 -40
  13. data/lib/devise.rb +13 -55
  14. data/lib/devise/controllers/helpers.rb +0 -5
  15. data/lib/devise/failure_app.rb +3 -1
  16. data/lib/devise/hooks/lockable.rb +7 -0
  17. data/lib/devise/hooks/timeoutable.rb +1 -0
  18. data/lib/devise/models.rb +9 -3
  19. data/lib/devise/models/authenticatable.rb +13 -3
  20. data/lib/devise/models/confirmable.rb +2 -5
  21. data/lib/devise/models/database_authenticatable.rb +4 -6
  22. data/lib/devise/models/lockable.rb +6 -6
  23. data/lib/devise/models/rememberable.rb +3 -3
  24. data/lib/devise/models/token_authenticatable.rb +4 -1
  25. data/lib/devise/modules.rb +0 -1
  26. data/lib/devise/orm/active_record.rb +1 -42
  27. data/lib/devise/orm/mongoid.rb +1 -29
  28. data/lib/devise/rails.rb +1 -58
  29. data/lib/devise/rails/routes.rb +1 -1
  30. data/lib/devise/rails/warden_compat.rb +10 -4
  31. data/lib/devise/strategies/rememberable.rb +1 -1
  32. data/lib/devise/test_helpers.rb +48 -9
  33. data/lib/devise/version.rb +1 -1
  34. data/lib/generators/active_record/devise_generator.rb +8 -4
  35. data/lib/generators/devise/orm_helpers.rb +2 -1
  36. data/lib/generators/mongoid/devise_generator.rb +0 -3
  37. data/lib/generators/templates/devise.rb +1 -8
  38. data/test/controllers/custom_strategy_test.rb +62 -0
  39. data/test/controllers/sessions_controller_test.rb +21 -1
  40. data/test/failure_app_test.rb +13 -3
  41. data/test/generators/active_record_generator_test.rb +32 -0
  42. data/test/integration/authenticatable_test.rb +2 -2
  43. data/test/integration/recoverable_test.rb +13 -0
  44. data/test/integration/token_authenticatable_test.rb +13 -0
  45. data/test/models/lockable_test.rb +0 -9
  46. data/test/models/rememberable_test.rb +1 -2
  47. data/test/models_test.rb +5 -5
  48. data/test/rails_app/app/mongoid/admin.rb +0 -3
  49. data/test/rails_app/app/mongoid/user.rb +0 -3
  50. data/test/rails_app/config/initializers/devise.rb +0 -15
  51. data/test/rails_app/config/routes.rb +1 -0
  52. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -6
  53. data/test/rails_app/lib/shared_admin.rb +1 -1
  54. metadata +17 -24
  55. data/lib/devise/encryptors/authlogic_sha512.rb +0 -19
  56. data/lib/devise/encryptors/base.rb +0 -24
  57. data/lib/devise/encryptors/bcrypt.rb +0 -14
  58. data/lib/devise/encryptors/clearance_sha1.rb +0 -17
  59. data/lib/devise/encryptors/restful_authentication_sha1.rb +0 -22
  60. data/lib/devise/encryptors/sha1.rb +0 -25
  61. data/lib/devise/encryptors/sha512.rb +0 -25
  62. data/lib/devise/models/encryptable.rb +0 -80
  63. data/lib/devise/schema.rb +0 -109
  64. data/test/encryptors_test.rb +0 -30
  65. data/test/models/encryptable_test.rb +0 -73
@@ -1,4 +1,4 @@
1
- require 'devise/strategies/base'
1
+ require 'devise/strategies/authenticatable'
2
2
 
3
3
  module Devise
4
4
  module Strategies
@@ -70,22 +70,61 @@ module Devise
70
70
  def _catch_warden(&block)
71
71
  result = catch(:warden, &block)
72
72
 
73
- if result.is_a?(Hash) && !warden.custom_failure? && !@controller.send(:performed?)
74
- result[:action] ||= :unauthenticated
73
+ env = @controller.request.env
75
74
 
76
- env = @controller.request.env
77
- env["PATH_INFO"] = "/#{result[:action]}"
78
- env["warden.options"] = result
79
- Warden::Manager._run_callbacks(:before_failure, env, result)
75
+ result ||= {}
76
+
77
+ # Set the response. In production, the rack result is returned
78
+ # from Warden::Manager#call, which the following is modelled on.
79
+ case result
80
+ when Array
81
+ if result.first == 401 && intercept_401?(env) # does this happen during testing?
82
+ _process_unauthenticated(env)
83
+ else
84
+ result
85
+ end
86
+ when Hash
87
+ _process_unauthenticated(env, result)
88
+ else
89
+ result
90
+ end
91
+ end
92
+
93
+ def _process_unauthenticated(env, options = {})
94
+ options[:action] ||= :unauthenticated
95
+ proxy = env['warden']
96
+ result = options[:result] || proxy.result
97
+
98
+ ret = case result
99
+ when :redirect
100
+ body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
101
+ [proxy.status, proxy.headers, [body]]
102
+ when :custom
103
+ proxy.custom_response
104
+ else
105
+ env["PATH_INFO"] = "/#{options[:action]}"
106
+ env["warden.options"] = options
107
+ Warden::Manager._run_callbacks(:before_failure, env, options)
80
108
 
81
109
  status, headers, body = Devise.warden_config[:failure_app].call(env).to_a
82
110
  @controller.send :render, :status => status, :text => body,
83
111
  :content_type => headers["Content-Type"], :location => headers["Location"]
112
+ nil # causes process return @response
113
+ end
84
114
 
85
- nil
86
- else
87
- result
115
+ # ensure that the controller response is set up. In production, this is
116
+ # not necessary since warden returns the results to rack. However, at
117
+ # testing time, we want the response to be available to the testing
118
+ # framework to verify what would be returned to rack.
119
+ if ret.is_a?(Array)
120
+ # ensure the controller response is set to our response.
121
+ @controller.response ||= @response
122
+ @response.status = ret.first
123
+ @response.headers = ret.second
124
+ @response.body = ret.third
88
125
  end
126
+
127
+ ret
89
128
  end
90
129
  end
91
130
  end
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "2.1.0.rc".freeze
2
+ VERSION = "2.1.0.rc2".freeze
3
3
  end
@@ -22,10 +22,17 @@ module ActiveRecord
22
22
  end
23
23
 
24
24
  def inject_devise_content
25
- inject_into_class(model_path, class_name, model_contents + <<CONTENT) if model_exists?
25
+ content = model_contents + <<CONTENT
26
26
  # Setup accessible (or protected) attributes for your model
27
27
  attr_accessible :email, :password, :password_confirmation, :remember_me
28
28
  CONTENT
29
+
30
+ class_path = class_name.to_s.split("::")
31
+
32
+ indent_depth = class_path.size - 1
33
+ content = content.split("\n").map { |line| " " * indent_depth + line } .join("\n")
34
+
35
+ inject_into_class(model_path, class_path.last, content) if model_exists?
29
36
  end
30
37
 
31
38
  def migration_data
@@ -48,9 +55,6 @@ CONTENT
48
55
  t.string :current_sign_in_ip
49
56
  t.string :last_sign_in_ip
50
57
 
51
- ## Encryptable
52
- # t.string :password_salt
53
-
54
58
  ## Confirmable
55
59
  # t.string :confirmation_token
56
60
  # t.datetime :confirmed_at
@@ -4,7 +4,8 @@ module Devise
4
4
  def model_contents
5
5
  <<-CONTENT
6
6
  # Include default devise modules. Others available are:
7
- # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
7
+ # :token_authenticatable, :confirmable,
8
+ # :lockable, :timeoutable and :omniauthable
8
9
  devise :database_authenticatable, :registerable,
9
10
  :recoverable, :rememberable, :trackable, :validatable
10
11
 
@@ -37,9 +37,6 @@ module Mongoid
37
37
  field :current_sign_in_ip, :type => String
38
38
  field :last_sign_in_ip, :type => String
39
39
 
40
- ## Encryptable
41
- # field :password_salt, :type => String
42
-
43
40
  ## Confirmable
44
41
  # field :confirmation_token, :type => String
45
42
  # field :confirmed_at, :type => Time
@@ -9,9 +9,6 @@ Devise.setup do |config|
9
9
  # Configure the class responsible to send e-mails.
10
10
  # config.mailer = "Devise::Mailer"
11
11
 
12
- # Automatically apply schema changes in tableless databases
13
- config.apply_schema = false
14
-
15
12
  # ==> ORM configuration
16
13
  # Load and configure the ORM. Supports :active_record (default) and
17
14
  # :mongoid (bson_ext recommended) by default. Other ORMs may be
@@ -95,7 +92,7 @@ Devise.setup do |config|
95
92
  # the user cannot access the website without confirming his account.
96
93
  # config.allow_unconfirmed_access_for = 2.days
97
94
 
98
- # If true, requires any email changes to be confirmed (exctly the same way as
95
+ # If true, requires any email changes to be confirmed (exactly the same way as
99
96
  # initial account confirmation) to be applied. Requires additional unconfirmed_email
100
97
  # db field (see migrations). Until confirmed new email is stored in
101
98
  # unconfirmed email column, and copied to email column on successful confirmation.
@@ -111,10 +108,6 @@ Devise.setup do |config|
111
108
  # If true, extends the user's remember period when remembered via cookie.
112
109
  # config.extend_remember_period = false
113
110
 
114
- # If true, uses the password salt as remember token. This should be turned
115
- # to false if you are not using database authenticatable.
116
- config.use_salt_as_remember_token = true
117
-
118
111
  # Options to be passed to the created cookie. For instance, you can set
119
112
  # :secure => true in order to force SSL only cookies.
120
113
  # config.rememberable_options = {}
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+ require 'ostruct'
3
+ require 'warden/strategies/base'
4
+ require 'devise/test_helpers'
5
+
6
+ class CustomStrategyController < ActionController::Base
7
+ def new
8
+ warden.authenticate!(:custom_strategy)
9
+ end
10
+ end
11
+
12
+ # These tests are to prove that a warden strategy can successfully
13
+ # return a custom response, including a specific status code and
14
+ # custom http response headers. This does work in production,
15
+ # however, at the time of writing this, the Devise test helpers do
16
+ # not recognise the custom response and proceed to calling the
17
+ # Failure App. This makes it impossible to write tests for a
18
+ # strategy that return a custom response with Devise.
19
+ class CustomStrategy < Warden::Strategies::Base
20
+ def authenticate!
21
+ custom_headers = { "X-FOO" => "BAR" }
22
+ response = Rack::Response.new("BAD REQUEST", 400, custom_headers)
23
+ custom! response.finish
24
+ end
25
+ end
26
+
27
+ class CustomStrategyTest < ActionController::TestCase
28
+ tests CustomStrategyController
29
+
30
+ include Devise::TestHelpers
31
+
32
+ setup do
33
+ Warden::Strategies.add(:custom_strategy, CustomStrategy)
34
+ end
35
+
36
+ teardown do
37
+ Warden::Strategies._strategies.delete(:custom_strategy)
38
+ end
39
+
40
+ test "custom strategy can return its own status code" do
41
+ ret = get :new
42
+
43
+ # check the returned rack array
44
+ assert ret.is_a?(Array)
45
+ assert_equal 400, ret.first
46
+
47
+ # check the saved response as well. This is purely so that the response is available to the testing framework
48
+ # for verification. In production, the above array would be delivered directly to Rack.
49
+ assert_response 400
50
+ end
51
+
52
+ test "custom strategy can return custom headers" do
53
+ ret = get :new
54
+
55
+ # check the returned rack array
56
+ assert ret.is_a?(Array)
57
+ assert_equal ret.third['X-FOO'], 'BAR'
58
+
59
+ # check the saved response headers as well.
60
+ assert_equal response.headers['X-FOO'], 'BAR'
61
+ end
62
+ end
@@ -13,4 +13,24 @@ class SessionsControllerTest < ActionController::TestCase
13
13
  assert_equal 200, @response.status
14
14
  assert_template "devise/sessions/new"
15
15
  end
16
- end
16
+
17
+ if defined?(ActiveRecord)
18
+ if ActiveRecord::Base.respond_to?(:mass_assignment_sanitizer)
19
+ test "#new doesn't raise mass-assignment exception even if sign-in key is attr_protected" do
20
+ request.env["devise.mapping"] = Devise.mappings[:user]
21
+
22
+ ActiveRecord::Base.mass_assignment_sanitizer = :strict
23
+ User.class_eval { attr_protected :email }
24
+
25
+ begin
26
+ assert_nothing_raised ActiveModel::MassAssignmentSecurity::Error do
27
+ get :new, :user => { :email => "allez viens!" }
28
+ end
29
+ ensure
30
+ ActiveRecord::Base.mass_assignment_sanitizer = :logger
31
+ User.class_eval { attr_accessible :email }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -29,20 +29,20 @@ class FailureTest < ActiveSupport::TestCase
29
29
  end
30
30
 
31
31
  context 'When redirecting' do
32
- test 'return to the default redirect location' do
32
+ test 'returns to the default redirect location' do
33
33
  call_failure
34
34
  assert_equal 302, @response.first
35
35
  assert_equal 'You need to sign in or sign up before continuing.', @request.flash[:alert]
36
36
  assert_equal 'http://test.host/users/sign_in', @response.second['Location']
37
37
  end
38
38
 
39
- test 'return to the default redirect location for wildcard requests' do
39
+ test 'returns to the default redirect location for wildcard requests' do
40
40
  call_failure 'action_dispatch.request.formats' => nil, 'HTTP_ACCEPT' => '*/*'
41
41
  assert_equal 302, @response.first
42
42
  assert_equal 'http://test.host/users/sign_in', @response.second['Location']
43
43
  end
44
44
 
45
- test 'return to the root path if no session path is available' do
45
+ test 'returns to the root path if no session path is available' do
46
46
  swap Devise, :router_name => :fake_app do
47
47
  call_failure :app => RootFailureApp
48
48
  assert_equal 302, @response.first
@@ -51,6 +51,16 @@ class FailureTest < ActiveSupport::TestCase
51
51
  end
52
52
  end
53
53
 
54
+ if Rails.application.config.respond_to?(:relative_url_root)
55
+ test 'returns to the default redirect location considering the relative url root' do
56
+ swap Rails.application.config, :relative_url_root => "/sample" do
57
+ call_failure
58
+ assert_equal 302, @response.first
59
+ assert_equal 'http://test.host/sample/users/sign_in', @response.second['Location']
60
+ end
61
+ end
62
+ end
63
+
54
64
  test 'uses the proxy failure message as symbol' do
55
65
  call_failure('warden' => OpenStruct.new(:message => :invalid))
56
66
  assert_equal 'Invalid email or password.', @request.flash[:alert]
@@ -34,4 +34,36 @@ if DEVISE_ORM == :active_record
34
34
  assert_no_migration "db/migrate/devise_create_monsters.rb"
35
35
  end
36
36
  end
37
+
38
+ module RailsEngine
39
+ class Engine < Rails::Engine
40
+ isolate_namespace RailsEngine
41
+ end
42
+ end
43
+
44
+ def simulate_inside_engine(engine, namespace)
45
+ if Rails::Generators.respond_to?(:namespace=)
46
+ swap Rails::Generators, :namespace => namespace do
47
+ yield
48
+ end
49
+ else
50
+ swap Rails, :application => engine.instance do
51
+ yield
52
+ end
53
+ end
54
+ end
55
+
56
+ class ActiveRecordEngineGeneratorTest < Rails::Generators::TestCase
57
+ tests ActiveRecord::Generators::DeviseGenerator
58
+ destination File.expand_path("../../tmp", __FILE__)
59
+ setup :prepare_destination
60
+
61
+ test "all files are properly created" do
62
+ simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
63
+ run_generator ["monster"]
64
+
65
+ assert_file "app/models/rails_engine/monster.rb", /devise/,/attr_accessible (:[a-z_]+(, )?)+/
66
+ end
67
+ end
68
+ end
37
69
  end
@@ -461,14 +461,14 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
461
461
  test 'sign out with xml format returns ok response' do
462
462
  sign_in_as_user
463
463
  get destroy_user_session_path(:format => 'xml')
464
- assert_response :ok
464
+ assert_response :no_content
465
465
  assert_not warden.authenticated?(:user)
466
466
  end
467
467
 
468
468
  test 'sign out with json format returns empty json response' do
469
469
  sign_in_as_user
470
470
  get destroy_user_session_path(:format => 'json')
471
- assert_response :ok
471
+ assert_response :no_content
472
472
  assert_not warden.authenticated?(:user)
473
473
  end
474
474
  end
@@ -284,4 +284,17 @@ class PasswordTest < ActionController::IntegrationTest
284
284
  assert_current_url "/users/sign_in"
285
285
  end
286
286
  end
287
+
288
+ test "after recovering a password, should set failed attempts to 0" do
289
+ user = create_user
290
+ user.update_attribute(:failed_attempts, 10)
291
+
292
+ assert_equal 10, user.failed_attempts
293
+ request_forgot_password
294
+ reset_password :reset_password_token => user.reload.reset_password_token
295
+
296
+ assert warden.authenticated?(:user)
297
+ user.reload
298
+ assert_equal 0, user.failed_attempts
299
+ end
287
300
  end
@@ -100,6 +100,19 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
100
100
  end
101
101
  end
102
102
 
103
+ test 'should reset token and not authenticate when expire_auth_token_on_timeout is set to true, timeoutable is enabled and we have a timed out session' do
104
+ swap Devise, :token_authentication_key => :secret_token, :expire_auth_token_on_timeout => true, :timeout_in => (-1).minute do
105
+ user = sign_in_as_new_user_with_token
106
+ assert warden.authenticated?(:user)
107
+ token = user.authentication_token
108
+
109
+ get_users_path_as_existing_user(user)
110
+ assert_not warden.authenticated?(:user)
111
+ user.reload
112
+ assert_not_equal token, user.authentication_token
113
+ end
114
+ end
115
+
103
116
  test 'should not be subject to injection' do
104
117
  swap Devise, :token_authentication_key => :secret_token do
105
118
  user1 = create_user_with_authentication_token()
@@ -14,15 +14,6 @@ class LockableTest < ActiveSupport::TestCase
14
14
  end
15
15
  end
16
16
 
17
- test "should clear failed_attempts on successfull validation" do
18
- user = create_user
19
- user.confirm!
20
- user.valid_for_authentication?{ false }
21
- assert_equal 1, user.reload.failed_attempts
22
- user.valid_for_authentication?{ true }
23
- assert_equal 0, user.reload.failed_attempts
24
- end
25
-
26
17
  test "should increment failed_attempts on successfull validation if the user is already locked" do
27
18
  user = create_user
28
19
  user.confirm!
@@ -168,8 +168,7 @@ class RememberableTest < ActiveSupport::TestCase
168
168
 
169
169
  test 'should have the required_fiels array' do
170
170
  assert_same_content Devise::Models::Rememberable.required_fields(User), [
171
- :remember_created_at,
172
- :remember_token
171
+ :remember_created_at
173
172
  ]
174
173
  end
175
174
  end
data/test/models_test.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class Configurable < User
4
- devise :database_authenticatable, :encryptable, :confirmable, :rememberable, :timeoutable, :lockable,
4
+ devise :database_authenticatable, :confirmable, :rememberable, :timeoutable, :lockable,
5
5
  :stretches => 15, :pepper => 'abcdef', :allow_unconfirmed_access_for => 5.days,
6
6
  :remember_for => 7.days, :timeout_in => 15.minutes, :unlock_in => 10.days
7
7
  end
@@ -39,7 +39,7 @@ class ActiveRecordTest < ActiveSupport::TestCase
39
39
  end
40
40
 
41
41
  test 'can cherry pick modules' do
42
- assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable, :confirmable
42
+ assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :confirmable
43
43
  end
44
44
 
45
45
  test 'validations options are not applied too late' do
@@ -55,12 +55,12 @@ class ActiveRecordTest < ActiveSupport::TestCase
55
55
  end
56
56
 
57
57
  test 'chosen modules are inheritable' do
58
- assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable, :confirmable
58
+ assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :confirmable
59
59
  end
60
60
 
61
61
  test 'order of module inclusion' do
62
- correct_module_order = [:database_authenticatable, :encryptable, :recoverable, :registerable, :confirmable, :lockable, :timeoutable]
63
- incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :encryptable, :confirmable]
62
+ correct_module_order = [:database_authenticatable, :recoverable, :registerable, :confirmable, :lockable, :timeoutable]
63
+ incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :confirmable]
64
64
 
65
65
  assert_include_modules Admin, *incorrect_module_order
66
66