devise 0.9.2 → 1.0.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.
- data/CHANGELOG.rdoc +11 -0
- data/README.rdoc +3 -2
- data/TODO +0 -1
- data/app/controllers/confirmations_controller.rb +18 -7
- data/app/controllers/passwords_controller.rb +18 -7
- data/app/controllers/registrations_controller.rb +55 -0
- data/app/controllers/sessions_controller.rb +17 -5
- data/app/controllers/unlocks_controller.rb +18 -7
- data/app/models/devise_mailer.rb +3 -2
- data/app/views/registrations/edit.html.erb +25 -0
- data/app/views/registrations/new.html.erb +17 -0
- data/app/views/sessions/new.html.erb +10 -12
- data/app/views/shared/_devise_links.erb +5 -1
- data/generators/devise_install/templates/devise.rb +3 -1
- data/lib/devise.rb +15 -8
- data/lib/devise/controllers/helpers.rb +1 -1
- data/lib/devise/controllers/internal_helpers.rb +15 -6
- data/lib/devise/controllers/url_helpers.rb +7 -7
- data/lib/devise/locales/en.yml +6 -0
- data/lib/devise/mapping.rb +9 -15
- data/lib/devise/models.rb +9 -16
- data/lib/devise/models/authenticatable.rb +38 -8
- data/lib/devise/models/lockable.rb +42 -24
- data/lib/devise/models/registerable.rb +8 -0
- data/lib/devise/models/timeoutable.rb +1 -1
- data/lib/devise/orm/active_record.rb +3 -2
- data/lib/devise/orm/data_mapper.rb +3 -3
- data/lib/devise/orm/mongo_mapper.rb +3 -3
- data/lib/devise/rails/routes.rb +9 -6
- data/lib/devise/strategies/authenticatable.rb +11 -1
- data/lib/devise/strategies/base.rb +5 -13
- data/lib/devise/strategies/http_authenticatable.rb +49 -0
- data/lib/devise/strategies/rememberable.rb +1 -1
- data/lib/devise/strategies/token_authenticatable.rb +9 -10
- data/lib/devise/version.rb +1 -1
- data/test/devise_test.rb +1 -1
- data/test/integration/authenticatable_test.rb +59 -43
- data/test/integration/http_authenticatable_test.rb +44 -0
- data/test/integration/registerable_test.rb +130 -0
- data/test/integration/token_authenticatable_test.rb +4 -4
- data/test/mailers/confirmation_instructions_test.rb +9 -0
- data/test/mapping_test.rb +14 -10
- data/test/models/authenticatable_test.rb +31 -9
- data/test/models/lockable_test.rb +8 -8
- data/test/models_test.rb +1 -1
- data/test/rails_app/app/active_record/admin.rb +1 -1
- data/test/rails_app/app/active_record/user.rb +4 -2
- data/test/rails_app/config/routes.rb +3 -2
- data/test/routes_test.rb +35 -0
- data/test/support/integration_tests_helper.rb +5 -1
- data/test/support/tests_helper.rb +35 -1
- metadata +9 -4
- data/lib/devise/controllers/common.rb +0 -24
- data/test/support/model_tests_helper.rb +0 -36
@@ -20,7 +20,7 @@ module Devise
|
|
20
20
|
#
|
21
21
|
module ActiveRecord
|
22
22
|
# Required ORM hook. Just yield the given block in ActiveRecord.
|
23
|
-
def self.included_modules_hook(klass
|
23
|
+
def self.included_modules_hook(klass)
|
24
24
|
yield
|
25
25
|
end
|
26
26
|
|
@@ -36,5 +36,6 @@ end
|
|
36
36
|
|
37
37
|
if defined?(ActiveRecord)
|
38
38
|
ActiveRecord::Base.extend Devise::Models
|
39
|
+
ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord
|
39
40
|
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord
|
40
|
-
end
|
41
|
+
end
|
@@ -11,13 +11,13 @@ module Devise
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.included_modules_hook(klass
|
14
|
+
def self.included_modules_hook(klass)
|
15
15
|
klass.send :extend, self
|
16
16
|
klass.send :include, InstanceMethods
|
17
17
|
|
18
18
|
yield
|
19
19
|
|
20
|
-
|
20
|
+
klass.devise_modules.each do |mod|
|
21
21
|
klass.send(mod) if klass.respond_to?(mod)
|
22
22
|
end
|
23
23
|
end
|
@@ -80,4 +80,4 @@ module Devise
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
-
DataMapper::Model.send(:include, Devise::Models)
|
83
|
+
DataMapper::Model.send(:include, Devise::Models)
|
@@ -11,12 +11,12 @@ module Devise
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.included_modules_hook(klass
|
14
|
+
def self.included_modules_hook(klass)
|
15
15
|
klass.send :extend, self
|
16
16
|
klass.send :include, InstanceMethods
|
17
17
|
yield
|
18
18
|
|
19
|
-
|
19
|
+
klass.devise_modules.each do |mod|
|
20
20
|
klass.send(mod) if klass.respond_to?(mod)
|
21
21
|
end
|
22
22
|
end
|
@@ -47,4 +47,4 @@ module Devise
|
|
47
47
|
end
|
48
48
|
|
49
49
|
MongoMapper::Document::ClassMethods.send(:include, Devise::Models)
|
50
|
-
MongoMapper::EmbeddedDocument::ClassMethods.send(:include, Devise::Models)
|
50
|
+
MongoMapper::EmbeddedDocument::ClassMethods.send(:include, Devise::Models)
|
data/lib/devise/rails/routes.rb
CHANGED
@@ -88,8 +88,8 @@ module ActionController::Routing
|
|
88
88
|
route_options = mapping.route_options.merge(:path_prefix => mapping.raw_path, :name_prefix => "#{mapping.name}_")
|
89
89
|
|
90
90
|
with_options(route_options) do |routes|
|
91
|
-
mapping.for.each do |
|
92
|
-
send(
|
91
|
+
mapping.for.each do |mod|
|
92
|
+
send(mod, routes, mapping) if self.respond_to?(mod, true)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -105,10 +105,6 @@ module ActionController::Routing
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
-
def recoverable(routes, mapping)
|
109
|
-
routes.resource :password, :only => [:new, :create, :edit, :update], :as => mapping.path_names[:password]
|
110
|
-
end
|
111
|
-
|
112
108
|
def confirmable(routes, mapping)
|
113
109
|
routes.resource :confirmation, :only => [:new, :create, :show], :as => mapping.path_names[:confirmation]
|
114
110
|
end
|
@@ -117,6 +113,13 @@ module ActionController::Routing
|
|
117
113
|
routes.resource :unlock, :only => [:new, :create, :show], :as => mapping.path_names[:unlock]
|
118
114
|
end
|
119
115
|
|
116
|
+
def recoverable(routes, mapping)
|
117
|
+
routes.resource :password, :only => [:new, :create, :edit, :update], :as => mapping.path_names[:password]
|
118
|
+
end
|
119
|
+
|
120
|
+
def registerable(routes, mapping)
|
121
|
+
routes.resource :registration, :only => [:new, :create, :edit, :update, :destroy], :as => mapping.raw_path[1..-1], :path_prefix => nil, :path_names => { :new => mapping.path_names[:sign_up] }
|
122
|
+
end
|
120
123
|
end
|
121
124
|
end
|
122
125
|
end
|
@@ -6,7 +6,7 @@ module Devise
|
|
6
6
|
# Redirects to sign_in page if it's not authenticated
|
7
7
|
class Authenticatable < Base
|
8
8
|
def valid?
|
9
|
-
|
9
|
+
valid_controller? && valid_params? && mapping.to.respond_to?(:authenticate)
|
10
10
|
end
|
11
11
|
|
12
12
|
# Authenticate a user based on email and password params, returning to warden
|
@@ -19,6 +19,16 @@ module Devise
|
|
19
19
|
fail!(:invalid)
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def valid_controller?
|
26
|
+
params[:controller] == 'sessions'
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid_params?
|
30
|
+
params[scope] && params[scope][:password].present?
|
31
|
+
end
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
@@ -2,22 +2,14 @@ module Devise
|
|
2
2
|
module Strategies
|
3
3
|
# Base strategy for Devise. Responsible for verifying correct scope and mapping.
|
4
4
|
class Base < ::Warden::Strategies::Base
|
5
|
-
# Validate strategy. By default will raise an error if no scope or an
|
6
|
-
# invalid mapping is found.
|
7
|
-
def valid?
|
8
|
-
raise "Could not find mapping for #{scope}" unless mapping
|
9
|
-
mapping.for.include?(klass_type)
|
10
|
-
end
|
11
|
-
|
12
5
|
# Checks if a valid scope was given for devise and find mapping based on
|
13
6
|
# this scope.
|
14
7
|
def mapping
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@klass_type ||= self.class.name.split("::").last.underscore.to_sym
|
8
|
+
@mapping ||= begin
|
9
|
+
mapping = Devise.mappings[scope]
|
10
|
+
raise "Could not find mapping for #{scope}" unless mapping
|
11
|
+
mapping
|
12
|
+
end
|
21
13
|
end
|
22
14
|
end
|
23
15
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'devise/strategies/base'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Strategies
|
5
|
+
# Sign in an user using HTTP authentication.
|
6
|
+
class HttpAuthenticatable < Base
|
7
|
+
def valid?
|
8
|
+
http_authentication? && mapping.to.respond_to?(:authenticate_with_http)
|
9
|
+
end
|
10
|
+
|
11
|
+
def authenticate!
|
12
|
+
username, password = username_and_password
|
13
|
+
|
14
|
+
if resource = mapping.to.authenticate_with_http(username, password)
|
15
|
+
success!(resource)
|
16
|
+
else
|
17
|
+
custom!([401, custom_headers, ["HTTP Basic: Access denied.\n"]])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def username_and_password
|
24
|
+
decode_credentials(request).split(/:/, 2)
|
25
|
+
end
|
26
|
+
|
27
|
+
def http_authentication
|
28
|
+
request.env['HTTP_AUTHORIZATION'] ||
|
29
|
+
request.env['X-HTTP_AUTHORIZATION'] ||
|
30
|
+
request.env['X_HTTP_AUTHORIZATION'] ||
|
31
|
+
request.env['REDIRECT_X_HTTP_AUTHORIZATION']
|
32
|
+
end
|
33
|
+
alias :http_authentication? :http_authentication
|
34
|
+
|
35
|
+
def decode_credentials(request)
|
36
|
+
ActiveSupport::Base64.decode64(http_authentication.split(' ', 2).last || '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def custom_headers
|
40
|
+
{
|
41
|
+
"Content-Type" => "text/plain",
|
42
|
+
"WWW-Authenticate" => %(Basic realm="#{Devise.http_authentication_realm.gsub(/"/, "")}")
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Warden::Strategies.add(:http_authenticatable, Devise::Strategies::HttpAuthenticatable)
|
@@ -10,7 +10,7 @@ module Devise
|
|
10
10
|
|
11
11
|
# A valid strategy for rememberable needs a remember token in the cookies.
|
12
12
|
def valid?
|
13
|
-
|
13
|
+
remember_me_cookie.present? && mapping.to.respond_to?(:serialize_from_cookie)
|
14
14
|
end
|
15
15
|
|
16
16
|
# To authenticate a user we deserialize the cookie and attempt finding
|
@@ -6,7 +6,7 @@ module Devise
|
|
6
6
|
# Redirects to sign_in page if it's not authenticated.
|
7
7
|
class TokenAuthenticatable < Base
|
8
8
|
def valid?
|
9
|
-
|
9
|
+
mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present?
|
10
10
|
end
|
11
11
|
|
12
12
|
# Authenticate a user based on authenticatable token params, returning to warden
|
@@ -20,17 +20,16 @@ module Devise
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
private
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
25
|
+
# Detect authentication token in params: scoped or not.
|
26
|
+
def authentication_token(scope)
|
27
|
+
if params[scope]
|
28
|
+
params[scope][mapping.to.token_authentication_key]
|
29
|
+
else
|
30
|
+
params[mapping.to.token_authentication_key]
|
32
31
|
end
|
33
|
-
|
32
|
+
end
|
34
33
|
end
|
35
34
|
end
|
36
35
|
end
|
data/lib/devise/version.rb
CHANGED
data/test/devise_test.rb
CHANGED
@@ -25,7 +25,7 @@ class DeviseTest < ActiveSupport::TestCase
|
|
25
25
|
Devise.configure_warden(config)
|
26
26
|
|
27
27
|
assert_equal Devise::FailureApp, config.failure_app
|
28
|
-
assert_equal [:rememberable, :token_authenticatable, :authenticatable], config.default_strategies
|
28
|
+
assert_equal [:rememberable, :http_authenticatable, :token_authenticatable, :authenticatable], config.default_strategies
|
29
29
|
assert_equal :user, config.default_scope
|
30
30
|
assert config.silence_missing_strategies?
|
31
31
|
end
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'test/test_helper'
|
2
2
|
|
3
|
-
class
|
4
|
-
|
5
|
-
test 'home should be accessible without signed in' do
|
3
|
+
class AuthenticationSanityTest < ActionController::IntegrationTest
|
4
|
+
test 'home should be accessible without sign in' do
|
6
5
|
visit '/'
|
7
6
|
assert_response :success
|
8
7
|
assert_template 'home/index'
|
@@ -76,14 +75,47 @@ class AuthenticationTest < ActionController::IntegrationTest
|
|
76
75
|
assert_contain 'Welcome Admin'
|
77
76
|
end
|
78
77
|
|
79
|
-
test '
|
78
|
+
test 'authenticated admin should not be able to sign as admin again' do
|
79
|
+
sign_in_as_admin
|
80
|
+
get new_admin_session_path
|
81
|
+
|
82
|
+
assert_response :redirect
|
83
|
+
assert_redirected_to admin_root_path
|
84
|
+
assert warden.authenticated?(:admin)
|
85
|
+
end
|
86
|
+
|
87
|
+
test 'authenticated admin should be able to sign out' do
|
88
|
+
sign_in_as_admin
|
89
|
+
assert warden.authenticated?(:admin)
|
90
|
+
|
91
|
+
get destroy_admin_session_path
|
92
|
+
assert_response :redirect
|
93
|
+
assert_redirected_to root_path
|
94
|
+
|
95
|
+
get root_path
|
96
|
+
assert_contain 'Signed out successfully'
|
97
|
+
assert_not warden.authenticated?(:admin)
|
98
|
+
end
|
99
|
+
|
100
|
+
test 'unauthenticated admin does not set message on sign out' do
|
101
|
+
get destroy_admin_session_path
|
102
|
+
assert_response :redirect
|
103
|
+
assert_redirected_to root_path
|
104
|
+
|
105
|
+
get root_path
|
106
|
+
assert_not_contain 'Signed out successfully'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class AuthenticationTest < ActionController::IntegrationTest
|
111
|
+
test 'sign in should not authenticate if not using proper authentication keys' do
|
80
112
|
swap Devise, :authentication_keys => [:username] do
|
81
113
|
sign_in_as_user
|
82
114
|
assert_not warden.authenticated?(:user)
|
83
115
|
end
|
84
116
|
end
|
85
117
|
|
86
|
-
test '
|
118
|
+
test 'sign in with invalid email should return to sign in form with error message' do
|
87
119
|
sign_in_as_admin do
|
88
120
|
fill_in 'email', :with => 'wrongemail@test.com'
|
89
121
|
end
|
@@ -92,7 +124,7 @@ class AuthenticationTest < ActionController::IntegrationTest
|
|
92
124
|
assert_not warden.authenticated?(:admin)
|
93
125
|
end
|
94
126
|
|
95
|
-
test '
|
127
|
+
test 'sign in with invalid pasword should return to sign in form with error message' do
|
96
128
|
sign_in_as_admin do
|
97
129
|
fill_in 'password', :with => 'abcdef'
|
98
130
|
end
|
@@ -113,37 +145,6 @@ class AuthenticationTest < ActionController::IntegrationTest
|
|
113
145
|
end
|
114
146
|
end
|
115
147
|
|
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 admin_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
148
|
test 'redirect from warden shows sign in or sign up message' do
|
148
149
|
get admins_path
|
149
150
|
|
@@ -194,20 +195,21 @@ class AuthenticationTest < ActionController::IntegrationTest
|
|
194
195
|
assert_equal "/admin_area/home", @request.path
|
195
196
|
end
|
196
197
|
|
197
|
-
test '
|
198
|
+
test 'destroyed account is signed out' do
|
198
199
|
sign_in_as_user
|
199
200
|
visit 'users/index'
|
200
|
-
assert_equal "Cart", @controller.user_session[:cart]
|
201
|
-
end
|
202
201
|
|
203
|
-
test 'destroyed account is logged out' do
|
204
|
-
sign_in_as_user
|
205
|
-
visit 'users/index'
|
206
202
|
User.destroy_all
|
207
203
|
visit 'users/index'
|
208
204
|
assert_redirected_to '/users/sign_in?unauthenticated=true'
|
209
205
|
end
|
210
206
|
|
207
|
+
test 'allows session to be set by a given scope' do
|
208
|
+
sign_in_as_user
|
209
|
+
visit 'users/index'
|
210
|
+
assert_equal "Cart", @controller.user_session[:cart]
|
211
|
+
end
|
212
|
+
|
211
213
|
test 'renders the scoped view if turned on and view is available' do
|
212
214
|
swap Devise, :scoped_views => true do
|
213
215
|
assert_raise Webrat::NotFoundError do
|
@@ -217,6 +219,20 @@ class AuthenticationTest < ActionController::IntegrationTest
|
|
217
219
|
end
|
218
220
|
end
|
219
221
|
|
222
|
+
test 'renders the scoped view if turned on in an specific controller' do
|
223
|
+
begin
|
224
|
+
SessionsController.scoped_views = true
|
225
|
+
assert_raise Webrat::NotFoundError do
|
226
|
+
sign_in_as_user
|
227
|
+
end
|
228
|
+
|
229
|
+
assert_match /Special user view/, response.body
|
230
|
+
assert !PasswordsController.scoped_views
|
231
|
+
ensure
|
232
|
+
SessionsController.send :remove_instance_variable, :@scoped_views
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
220
236
|
test 'does not render the scoped view if turned off' do
|
221
237
|
swap Devise, :scoped_views => false do
|
222
238
|
assert_nothing_raised do
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class HttpAuthenticationTest < ActionController::IntegrationTest
|
4
|
+
|
5
|
+
test 'sign in should authenticate with http' do
|
6
|
+
sign_in_as_new_user_with_http
|
7
|
+
assert_response :success
|
8
|
+
assert_template 'users/index'
|
9
|
+
assert_contain 'Welcome'
|
10
|
+
assert warden.authenticated?(:user)
|
11
|
+
end
|
12
|
+
|
13
|
+
test 'returns a custom response with www-authenticate header on failures' do
|
14
|
+
sign_in_as_new_user_with_http("unknown")
|
15
|
+
assert_equal 401, status
|
16
|
+
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'returns a custom response with www-authenticate and chosen realm' do
|
20
|
+
swap Devise, :http_authentication_realm => "MyApp" do
|
21
|
+
sign_in_as_new_user_with_http("unknown")
|
22
|
+
assert_equal 401, status
|
23
|
+
assert_equal 'Basic realm="MyApp"', headers["WWW-Authenticate"]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
test 'sign in should authenticate with http even with specific authentication keys' do
|
28
|
+
swap Devise, :authentication_keys => [:username] do
|
29
|
+
sign_in_as_new_user_with_http "usertest"
|
30
|
+
assert_response :success
|
31
|
+
assert_template 'users/index'
|
32
|
+
assert_contain 'Welcome'
|
33
|
+
assert warden.authenticated?(:user)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
|
40
|
+
user = create_user
|
41
|
+
get users_path, {}, :authorization => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
|
42
|
+
user
|
43
|
+
end
|
44
|
+
end
|