devise 0.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 (74) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +220 -0
  3. data/Rakefile +45 -0
  4. data/TODO +37 -0
  5. data/app/controllers/confirmations_controller.rb +32 -0
  6. data/app/controllers/passwords_controller.rb +38 -0
  7. data/app/controllers/sessions_controller.rb +35 -0
  8. data/app/models/notifier.rb +47 -0
  9. data/app/views/confirmations/new.html.erb +16 -0
  10. data/app/views/notifier/confirmation_instructions.html.erb +5 -0
  11. data/app/views/notifier/reset_password_instructions.html.erb +8 -0
  12. data/app/views/passwords/edit.html.erb +20 -0
  13. data/app/views/passwords/new.html.erb +16 -0
  14. data/app/views/sessions/new.html.erb +23 -0
  15. data/config/locales/en.yml +16 -0
  16. data/init.rb +2 -0
  17. data/lib/devise.rb +48 -0
  18. data/lib/devise/active_record.rb +86 -0
  19. data/lib/devise/controllers/filters.rb +109 -0
  20. data/lib/devise/controllers/helpers.rb +91 -0
  21. data/lib/devise/controllers/url_helpers.rb +47 -0
  22. data/lib/devise/hooks/rememberable.rb +24 -0
  23. data/lib/devise/mapping.rb +95 -0
  24. data/lib/devise/migrations.rb +50 -0
  25. data/lib/devise/models/authenticable.rb +98 -0
  26. data/lib/devise/models/confirmable.rb +125 -0
  27. data/lib/devise/models/recoverable.rb +88 -0
  28. data/lib/devise/models/rememberable.rb +71 -0
  29. data/lib/devise/models/validatable.rb +36 -0
  30. data/lib/devise/routes.rb +95 -0
  31. data/lib/devise/strategies/authenticable.rb +45 -0
  32. data/lib/devise/strategies/base.rb +24 -0
  33. data/lib/devise/strategies/rememberable.rb +33 -0
  34. data/lib/devise/version.rb +3 -0
  35. data/lib/devise/warden.rb +64 -0
  36. data/test/active_record_test.rb +96 -0
  37. data/test/controllers/filters_test.rb +97 -0
  38. data/test/controllers/helpers_test.rb +40 -0
  39. data/test/controllers/url_helpers_test.rb +47 -0
  40. data/test/integration/authenticable_test.rb +191 -0
  41. data/test/integration/confirmable_test.rb +60 -0
  42. data/test/integration/recoverable_test.rb +131 -0
  43. data/test/integration/rememberable_test.rb +56 -0
  44. data/test/mailers/confirmation_instructions_test.rb +59 -0
  45. data/test/mailers/reset_password_instructions_test.rb +62 -0
  46. data/test/mapping_test.rb +71 -0
  47. data/test/models/authenticable_test.rb +138 -0
  48. data/test/models/confirmable_test.rb +206 -0
  49. data/test/models/recoverable_test.rb +145 -0
  50. data/test/models/rememberable_test.rb +68 -0
  51. data/test/models/validatable_test.rb +99 -0
  52. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  53. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  54. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  55. data/test/rails_app/app/controllers/users_controller.rb +7 -0
  56. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  57. data/test/rails_app/app/models/account.rb +3 -0
  58. data/test/rails_app/app/models/admin.rb +3 -0
  59. data/test/rails_app/app/models/organizer.rb +3 -0
  60. data/test/rails_app/app/models/user.rb +3 -0
  61. data/test/rails_app/config/boot.rb +110 -0
  62. data/test/rails_app/config/environment.rb +41 -0
  63. data/test/rails_app/config/environments/development.rb +17 -0
  64. data/test/rails_app/config/environments/production.rb +28 -0
  65. data/test/rails_app/config/environments/test.rb +28 -0
  66. data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
  67. data/test/rails_app/config/initializers/session_store.rb +15 -0
  68. data/test/rails_app/config/routes.rb +18 -0
  69. data/test/routes_test.rb +75 -0
  70. data/test/support/assertions_helper.rb +22 -0
  71. data/test/support/integration_tests_helper.rb +66 -0
  72. data/test/support/model_tests_helper.rb +40 -0
  73. data/test/test_helper.rb +39 -0
  74. metadata +136 -0
@@ -0,0 +1,97 @@
1
+ require 'test/test_helper'
2
+ require 'ostruct'
3
+
4
+ class MockController < ApplicationController
5
+ attr_accessor :env
6
+
7
+ def request
8
+ self
9
+ end
10
+
11
+ def path
12
+ ''
13
+ end
14
+ end
15
+
16
+ class ControllerAuthenticableTest < ActionController::TestCase
17
+
18
+ def setup
19
+ @controller = MockController.new
20
+ @mock_warden = OpenStruct.new
21
+ @controller.env = { 'warden' => @mock_warden }
22
+ end
23
+
24
+ test 'setup warden' do
25
+ assert_not_nil @controller.warden
26
+ end
27
+
28
+ test 'provide access to warden instance' do
29
+ assert_equal @controller.warden, @controller.env['warden']
30
+ end
31
+
32
+ test 'run authenticate? with scope on warden' do
33
+ @mock_warden.expects(:authenticated?).with(:my_scope)
34
+ @controller.signed_in?(:my_scope)
35
+ end
36
+
37
+ test 'proxy signed_in? to authenticated' do
38
+ @mock_warden.expects(:authenticated?).with(:my_scope)
39
+ @controller.signed_in?(:my_scope)
40
+ end
41
+
42
+ test 'run user with scope on warden' do
43
+ @mock_warden.expects(:user).with(:admin).returns(true)
44
+ @controller.current_admin
45
+
46
+ @mock_warden.expects(:user).with(:user).returns(true)
47
+ @controller.current_user
48
+ end
49
+
50
+ test 'proxy logout to warden' do
51
+ @mock_warden.expects(:user).with(:user).returns(true)
52
+ @mock_warden.expects(:logout).with(:user).returns(true)
53
+ @controller.sign_out(:user)
54
+ end
55
+
56
+ test 'proxy user_authenticate! to authenticate with user scope' do
57
+ @mock_warden.expects(:authenticate!).with(:scope => :user)
58
+ @controller.authenticate_user!
59
+ end
60
+
61
+ test 'proxy admin_authenticate! to authenticate with admin scope' do
62
+ @mock_warden.expects(:authenticate!).with(:scope => :admin)
63
+ @controller.authenticate_admin!
64
+ end
65
+
66
+ test 'proxy user_authenticated? to authenticate with user scope' do
67
+ @mock_warden.expects(:authenticated?).with(:user)
68
+ @controller.user_signed_in?
69
+ end
70
+
71
+ test 'proxy admin_authenticated? to authenticate with admin scope' do
72
+ @mock_warden.expects(:authenticated?).with(:admin)
73
+ @controller.admin_signed_in?
74
+ end
75
+
76
+ test 'proxy user_session to session scope in warden' do
77
+ @mock_warden.expects(:session).with(:user).returns({})
78
+ @controller.user_session
79
+ end
80
+
81
+ test 'proxy admin_session to session scope in warden' do
82
+ @mock_warden.expects(:session).with(:admin).returns({})
83
+ @controller.admin_session
84
+ end
85
+
86
+ test 'require no authentication tests current mapping' do
87
+ @controller.expects(:resource_name).returns(:user)
88
+ @mock_warden.expects(:authenticated?).with(:user).returns(true)
89
+ @controller.expects(:redirect_to).with(root_path)
90
+ @controller.send :require_no_authentication
91
+ end
92
+
93
+ test 'sign in automatically proxy to set user on warden' do
94
+ @mock_warden.expects(:set_user).with(user = mock, :scope => :user).returns(true)
95
+ @controller.sign_in(:user, user)
96
+ end
97
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/test_helper'
2
+
3
+ class HelpersTest < ActionController::TestCase
4
+ tests ApplicationController
5
+
6
+ test 'get resource name from request path' do
7
+ @request.path = '/users/session'
8
+ assert_equal :user, @controller.resource_name
9
+ end
10
+
11
+ test 'get resource name from specific request path' do
12
+ @request.path = '/admin_area/session'
13
+ assert_equal :admin, @controller.resource_name
14
+ end
15
+
16
+ test 'get resource class from request path' do
17
+ @request.path = '/users/session'
18
+ assert_equal User, @controller.resource_class
19
+ end
20
+
21
+ test 'get resource instance variable from request path' do
22
+ @request.path = '/admin_area/session'
23
+ @controller.instance_variable_set(:@admin, admin = Admin.new)
24
+ assert_equal admin, @controller.resource
25
+ end
26
+
27
+ test 'set resource instance variable from request path' do
28
+ @request.path = '/admin_area/session'
29
+
30
+ admin = @controller.send(:resource_class).new
31
+ @controller.send(:resource=, admin)
32
+
33
+ assert_equal admin, @controller.send(:resource)
34
+ assert_equal admin, @controller.instance_variable_get(:@admin)
35
+ end
36
+
37
+ test 'resources methods are not controller actions' do
38
+ assert @controller.class.action_methods.empty?
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/test_helper'
2
+
3
+ class RoutesTest < ActionController::TestCase
4
+ tests ApplicationController
5
+
6
+ def test_path_and_url(name, prepend_path=nil)
7
+ @request.path = '/users/session'
8
+ prepend_path = "#{prepend_path}_" if prepend_path
9
+
10
+ # Resource param
11
+ assert_equal @controller.send(:"#{prepend_path}#{name}_path", :user),
12
+ send(:"#{prepend_path}user_#{name}_path")
13
+ assert_equal @controller.send(:"#{prepend_path}#{name}_url", :user),
14
+ send(:"#{prepend_path}user_#{name}_url")
15
+
16
+ # Default url params
17
+ assert_equal @controller.send(:"#{prepend_path}#{name}_path", :user, :param => 123),
18
+ send(:"#{prepend_path}user_#{name}_path", :param => 123)
19
+ assert_equal @controller.send(:"#{prepend_path}#{name}_url", :user, :param => 123),
20
+ send(:"#{prepend_path}user_#{name}_url", :param => 123)
21
+
22
+ @request.path = nil
23
+ # With an AR object
24
+ assert_equal @controller.send(:"#{prepend_path}#{name}_path", User.new),
25
+ send(:"#{prepend_path}user_#{name}_path")
26
+ assert_equal @controller.send(:"#{prepend_path}#{name}_url", User.new),
27
+ send(:"#{prepend_path}user_#{name}_url")
28
+ end
29
+
30
+
31
+ test 'should alias session to mapped user session' do
32
+ test_path_and_url :session
33
+ test_path_and_url :session, :new
34
+ test_path_and_url :session, :destroy
35
+ end
36
+
37
+ test 'should alias password to mapped user password' do
38
+ test_path_and_url :password
39
+ test_path_and_url :password, :new
40
+ test_path_and_url :password, :edit
41
+ end
42
+
43
+ test 'should alias confirmation to mapped user confirmation' do
44
+ test_path_and_url :confirmation
45
+ test_path_and_url :confirmation, :new
46
+ end
47
+ end
@@ -0,0 +1,191 @@
1
+ require 'test/test_helper'
2
+
3
+ class AuthenticationTest < ActionController::IntegrationTest
4
+
5
+ test 'home should be accessible without signed in' do
6
+ visit '/'
7
+ assert_response :success
8
+ assert_template 'home/index'
9
+ end
10
+
11
+ test 'sign in as user should not authenticate admin scope' do
12
+ sign_in_as_user
13
+
14
+ assert warden.authenticated?(:user)
15
+ assert_not warden.authenticated?(:admin)
16
+ end
17
+
18
+ test 'sign in as admin should not authenticate user scope' do
19
+ sign_in_as_admin
20
+
21
+ assert warden.authenticated?(:admin)
22
+ assert_not warden.authenticated?(:user)
23
+ end
24
+
25
+ test 'sign in as both user and admin at same time' do
26
+ sign_in_as_user
27
+ sign_in_as_admin
28
+
29
+ assert warden.authenticated?(:user)
30
+ assert warden.authenticated?(:admin)
31
+ end
32
+
33
+ test 'sign out as user should not touch admin authentication' do
34
+ sign_in_as_user
35
+ sign_in_as_admin
36
+
37
+ get destroy_user_session_path
38
+ assert_not warden.authenticated?(:user)
39
+ assert warden.authenticated?(:admin)
40
+ end
41
+
42
+ test 'sign out as admin should not touch user authentication' do
43
+ sign_in_as_user
44
+ sign_in_as_admin
45
+
46
+ get destroy_admin_session_path
47
+ assert_not warden.authenticated?(:admin)
48
+ assert warden.authenticated?(:user)
49
+ end
50
+
51
+ test 'not signed in as admin should not be able to access admins actions' do
52
+ get admins_path
53
+
54
+ assert_redirected_to new_admin_session_path(:unauthenticated => true)
55
+ assert_not warden.authenticated?(:admin)
56
+ end
57
+
58
+ test 'signed in as user should not be able to access admins actions' do
59
+ sign_in_as_user
60
+ assert warden.authenticated?(:user)
61
+ assert_not warden.authenticated?(:admin)
62
+
63
+ get admins_path
64
+ assert_redirected_to new_admin_session_path(:unauthenticated => true)
65
+ end
66
+
67
+ test 'signed in as admin should be able to access admin actions' do
68
+ sign_in_as_admin
69
+ assert warden.authenticated?(:admin)
70
+ assert_not warden.authenticated?(:user)
71
+
72
+ get admins_path
73
+
74
+ assert_response :success
75
+ assert_template 'admins/index'
76
+ assert_contain 'Welcome Admin'
77
+ end
78
+
79
+ test 'admin signing in with invalid email should return to sign in form with error message' do
80
+ sign_in_as_admin do
81
+ fill_in 'email', :with => 'wrongemail@test.com'
82
+ end
83
+
84
+ assert_response :success
85
+ assert_template 'sessions/new'
86
+ assert_contain 'Invalid email or password'
87
+ assert_not warden.authenticated?(:admin)
88
+ end
89
+
90
+ test 'admin signing in with invalid pasword should return to sign in form with error message' do
91
+ sign_in_as_admin do
92
+ fill_in 'password', :with => 'abcdef'
93
+ end
94
+
95
+ assert_response :success
96
+ assert_template 'sessions/new'
97
+ assert_contain 'Invalid email or password'
98
+ assert_not warden.authenticated?(:admin)
99
+ end
100
+
101
+ test 'error message is configurable by resource name' do
102
+ begin
103
+ I18n.backend.store_translations(:en, :devise => { :sessions =>
104
+ { :admin => { :unauthenticated => "Invalid credentials" } } })
105
+
106
+ sign_in_as_admin do
107
+ fill_in 'password', :with => 'abcdef'
108
+ end
109
+
110
+ assert_contain 'Invalid credentials'
111
+ ensure
112
+ I18n.reload!
113
+ end
114
+ end
115
+
116
+ test 'authenticated admin should not be able to sign as admin again' do
117
+ sign_in_as_admin
118
+ get new_admin_session_path
119
+
120
+ assert_response :redirect
121
+ assert_redirected_to root_path
122
+ assert warden.authenticated?(:admin)
123
+ end
124
+
125
+ test 'authenticated admin should be able to sign out' do
126
+ sign_in_as_admin
127
+ assert warden.authenticated?(:admin)
128
+
129
+ get destroy_admin_session_path
130
+ assert_response :redirect
131
+ assert_redirected_to root_path
132
+
133
+ get root_path
134
+ assert_contain 'Signed out successfully'
135
+ assert_not warden.authenticated?(:admin)
136
+ end
137
+
138
+ test 'unauthenticated admin does not set message on sign out' do
139
+ get destroy_admin_session_path
140
+ assert_response :redirect
141
+ assert_redirected_to root_path
142
+
143
+ get root_path
144
+ assert_not_contain 'Signed out successfully'
145
+ end
146
+
147
+ test 'redirect from warden shows error message' do
148
+ get admins_path
149
+
150
+ warden_path = new_admin_session_path(:unauthenticated => true)
151
+ assert_redirected_to warden_path
152
+
153
+ get warden_path
154
+ assert_contain 'Invalid email or password.'
155
+ end
156
+
157
+ test 'render 404 on roles without permission' do
158
+ get 'admin_area/password/new'
159
+ assert_response :not_found
160
+ assert_not_contain 'Send me reset password instructions'
161
+ end
162
+
163
+ test 'return to default url if no other was requested' do
164
+ sign_in_as_user
165
+
166
+ assert_template 'home/index'
167
+ assert_nil session[:return_to]
168
+ end
169
+
170
+ test 'return to given url after sign in' do
171
+ get users_path
172
+ assert_redirected_to new_user_session_path(:unauthenticated => true)
173
+ assert_equal users_path, session[:"user.return_to"]
174
+ follow_redirect!
175
+
176
+ sign_in_as_user :visit => false
177
+ assert_template 'users/index'
178
+ assert_nil session[:"user.return_to"]
179
+ end
180
+
181
+ test 'return to configured home path after sign in' do
182
+ sign_in_as_admin
183
+ assert_equal "/admin_area/home", @request.path
184
+ end
185
+
186
+ test 'allows session to be set by a given scope' do
187
+ sign_in_as_user
188
+ visit 'users/index'
189
+ assert_equal "Cart", @controller.user_session[:cart]
190
+ end
191
+ end
@@ -0,0 +1,60 @@
1
+ require 'test/test_helper'
2
+
3
+ class ConfirmationTest < ActionController::IntegrationTest
4
+
5
+ def visit_user_confirmation_with_token(confirmation_token)
6
+ visit user_confirmation_path(:confirmation_token => confirmation_token)
7
+ end
8
+
9
+ test 'user should be able to request a new confirmation' do
10
+ user = create_user(:confirm => false)
11
+ ActionMailer::Base.deliveries.clear
12
+
13
+ visit new_user_session_path
14
+ click_link 'Didn\'t receive confirmation instructions?'
15
+
16
+ fill_in 'email', :with => user.email
17
+ click_button 'Resend confirmation instructions'
18
+
19
+ assert_template 'sessions/new'
20
+ assert_contain 'You will receive an email with instructions about how to confirm your account in a few minutes'
21
+ assert_equal 1, ActionMailer::Base.deliveries.size
22
+ end
23
+
24
+ test 'user with invalid confirmation token should not be able to confirm an account' do
25
+ visit_user_confirmation_with_token('invalid_confirmation')
26
+
27
+ assert_response :success
28
+ assert_template 'confirmations/new'
29
+ assert_have_selector '#errorExplanation'
30
+ assert_contain 'Confirmation token is invalid'
31
+ end
32
+
33
+ test 'user with valid confirmation token should be able to confirm an account' do
34
+ user = create_user(:confirm => false)
35
+ assert_not user.confirmed?
36
+
37
+ visit_user_confirmation_with_token(user.confirmation_token)
38
+
39
+ assert_template 'home/index'
40
+ assert_contain 'Your account was successfully confirmed.'
41
+
42
+ assert user.reload.confirmed?
43
+ end
44
+
45
+ test 'user already confirmed user should not be able to confirm the account again' do
46
+ user = create_user
47
+ visit_user_confirmation_with_token(user.confirmation_token)
48
+
49
+ assert_template 'confirmations/new'
50
+ assert_have_selector '#errorExplanation'
51
+ assert_contain 'already confirmed'
52
+ end
53
+
54
+ test 'sign in user automatically after confirming it\'s email' do
55
+ user = create_user(:confirm => false)
56
+ visit_user_confirmation_with_token(user.confirmation_token)
57
+
58
+ assert warden.authenticated?(:user)
59
+ end
60
+ end
@@ -0,0 +1,131 @@
1
+ require 'test/test_helper'
2
+
3
+ class PasswordTest < ActionController::IntegrationTest
4
+
5
+ def visit_new_password_path
6
+ visit new_user_session_path
7
+ click_link 'Forgot password?'
8
+ end
9
+
10
+ def request_forgot_password(&block)
11
+ visit_new_password_path
12
+
13
+ assert_response :success
14
+ assert_template 'passwords/new'
15
+ assert_not warden.authenticated?(:user)
16
+
17
+ fill_in 'email', :with => 'user@test.com'
18
+ yield if block_given?
19
+ click_button 'Send me reset password instructions'
20
+ end
21
+
22
+ def reset_password(options={}, &block)
23
+ unless options[:visit] == false
24
+ visit edit_user_password_path(:reset_password_token => options[:reset_password_token])
25
+ end
26
+ assert_response :success
27
+ assert_template 'passwords/edit'
28
+
29
+ fill_in 'Password', :with => '987654321'
30
+ fill_in 'Password confirmation', :with => '987654321'
31
+ yield if block_given?
32
+ click_button 'Change my password'
33
+ end
34
+
35
+ test 'authenticated user should not be able to visit forgot password page' do
36
+ sign_in_as_user
37
+ assert warden.authenticated?(:user)
38
+
39
+ get new_user_password_path
40
+
41
+ assert_response :redirect
42
+ assert_redirected_to root_path
43
+ end
44
+
45
+ test 'not authenticated user should be able to request a forgot password' do
46
+ create_user
47
+ request_forgot_password
48
+
49
+ assert_template 'sessions/new'
50
+ assert_contain 'You will receive an email with instructions about how to reset your password in a few minutes.'
51
+ end
52
+
53
+ test 'not authenticated user with invalid email should receive an error message' do
54
+ request_forgot_password do
55
+ fill_in 'email', :with => 'invalid.test@test.com'
56
+ end
57
+
58
+ assert_response :success
59
+ assert_template 'passwords/new'
60
+ assert_have_selector 'input[type=text][value=\'invalid.test@test.com\']'
61
+ assert_contain 'Email not found'
62
+ end
63
+
64
+ test 'authenticated user should not be able to visit edit password page' do
65
+ sign_in_as_user
66
+
67
+ get edit_user_password_path
68
+
69
+ assert_response :redirect
70
+ assert_redirected_to root_path
71
+ assert warden.authenticated?(:user)
72
+ end
73
+
74
+ test 'not authenticated user with invalid reset password token should not be able to change his password' do
75
+ user = create_user
76
+ reset_password :reset_password_token => 'invalid_reset_password'
77
+
78
+ assert_response :success
79
+ assert_template 'passwords/edit'
80
+ assert_have_selector '#errorExplanation'
81
+ assert_contain 'Reset password token is invalid'
82
+ assert_not user.reload.valid_password?('987654321')
83
+ end
84
+
85
+ test 'not authenticated user with valid reset password token but invalid password should not be able to change his password' do
86
+ user = create_user
87
+ request_forgot_password
88
+ reset_password :reset_password_token => user.reload.reset_password_token do
89
+ fill_in 'Password confirmation', :with => 'other_password'
90
+ end
91
+
92
+ assert_response :success
93
+ assert_template 'passwords/edit'
94
+ assert_have_selector '#errorExplanation'
95
+ assert_contain 'Password doesn\'t match confirmation'
96
+ assert_not user.reload.valid_password?('987654321')
97
+ end
98
+
99
+ test 'not authenticated user with valid data should be able to change his password' do
100
+ user = create_user
101
+ request_forgot_password
102
+ reset_password :reset_password_token => user.reload.reset_password_token
103
+
104
+ assert_template 'home/index'
105
+ assert_contain 'Your password was changed successfully.'
106
+ assert user.reload.valid_password?('987654321')
107
+ end
108
+
109
+ test 'after entering invalid data user should still be able to change his password' do
110
+ user = create_user
111
+ request_forgot_password
112
+ reset_password :reset_password_token => user.reload.reset_password_token do
113
+ fill_in 'Password confirmation', :with => 'other_password'
114
+ end
115
+ assert_response :success
116
+ assert_have_selector '#errorExplanation'
117
+ assert_not user.reload.valid_password?('987654321')
118
+
119
+ reset_password :reset_password_token => user.reload.reset_password_token, :visit => false
120
+ assert_contain 'Your password was changed successfully.'
121
+ assert user.reload.valid_password?('987654321')
122
+ end
123
+
124
+ test 'sign in user automatically after changing it\'s password' do
125
+ user = create_user
126
+ request_forgot_password
127
+ reset_password :reset_password_token => user.reload.reset_password_token
128
+
129
+ assert warden.authenticated?(:user)
130
+ end
131
+ end