devise 0.5.0 → 0.5.1

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.

@@ -1,3 +1,13 @@
1
+ * enhancements
2
+ * [#28] Improved sign_in and sign_out helpers to accepts resources
3
+ * [#28] Added stored_location_for as a helper
4
+
5
+ == 0.5.1
6
+
7
+ * enhancements
8
+ * Added serializers based on Warden ones
9
+ * Allow authentication keys to be set
10
+
1
11
  == 0.5.0
2
12
 
3
13
  * bug fix
@@ -11,7 +21,7 @@
11
21
  == 0.4.3
12
22
 
13
23
  * bug fix
14
- * [#29] Authentication fail if user cannot be serialized from session;
24
+ * [#29] Authentication just fails if user cannot be serialized from session, without raising errors;
15
25
  * Default configuration values should not overwrite user values;
16
26
 
17
27
  == 0.4.2
@@ -46,7 +46,7 @@ And you're ready to go.
46
46
 
47
47
  This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration. You can also check out the *Generators* section below to help you start.
48
48
 
49
- Devise must be setted up within the model (or models) you want to use, and devise routes must be created inside your routes.rb file.
49
+ Devise must be set up within the model (or models) you want to use, and devise routes must be created inside your routes.rb file.
50
50
 
51
51
  We're assuming here you want a User model. First of all you have to setup a migration with the following fields:
52
52
 
@@ -93,7 +93,7 @@ Note that validations aren't added by default, so you're able to customize it. I
93
93
 
94
94
  == Model configuration
95
95
 
96
- In addition to :except, you can provide :pepper, :stretches, :confirm_within and :remember_for as options to devise method.
96
+ In addition to :except, you can provide :pepper, :stretches, :encryptor, :authentication_keys, :confirm_within and :remember_for as options to devise method.
97
97
 
98
98
  All those options are described in "config/initializers/devise.rb", which is generated when you invoke `ruby script/generate devise_install` in your application root.
99
99
 
data/Rakefile CHANGED
@@ -36,7 +36,7 @@ begin
36
36
  s.description = "Flexible authentication solution for Rails with Warden"
37
37
  s.authors = ['José Valim', 'Carlos Antônio']
38
38
  s.files = FileList["[A-Z]*", "{app,config,generators,lib}/**/*", "init.rb"]
39
- s.add_dependency("warden", "~> 0.5.2")
39
+ s.add_dependency("warden", "~> 0.6.0")
40
40
  end
41
41
 
42
42
  Jeweler::GemcutterTasks.new
data/TODO CHANGED
@@ -1,4 +1,3 @@
1
- * Allow authentication keys to be configured, so things like username and subdomain can be used
2
1
  * Devise::Timeoutable
3
2
  * Devise::TestHelper
4
3
  * Use request_ip in session cookies
@@ -15,6 +15,13 @@ Devise.setup do |config|
15
15
  # should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
16
16
  # config.encryptor = :sha1
17
17
 
18
+ # Configure which keys are used when authenticating an user. By default is
19
+ # just :email. You can configure it to use [:username, :subdomain], so for
20
+ # authenticating an user, both parameters are required. Remember that those
21
+ # parameters are used only when authenticating and not when retrieving from
22
+ # session. If you need permissions, you should implement that in a before filter.
23
+ # config.authentication_keys = [ :email ]
24
+
18
25
  # The time you want give to your user to confirm his account. During this time
19
26
  # he will be able to access your application without confirming. Default is nil.
20
27
  # config.confirm_within = 2.days
@@ -9,6 +9,7 @@ module Devise
9
9
  }.freeze
10
10
 
11
11
  STRATEGIES = [:authenticatable].freeze
12
+ SERIALIZERS = [:authenticatable, :rememberable].freeze
12
13
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].freeze
13
14
 
14
15
  # Maps the messages types that comes from warden to a flash type.
@@ -35,6 +36,10 @@ module Devise
35
36
  mattr_accessor :stretches
36
37
  @@stretches = 10
37
38
 
39
+ # Keys used when authenticating an user.
40
+ mattr_accessor :authentication_keys
41
+ @@authentication_keys = [ :email ]
42
+
38
43
  # Time interval where the remember me token is valid.
39
44
  mattr_accessor :remember_for
40
45
  @@remember_for = 2.weeks
@@ -104,8 +109,10 @@ module Devise
104
109
  # block.
105
110
  def configure_warden_manager(manager) #:nodoc:
106
111
  manager.default_strategies *Devise::STRATEGIES
112
+ manager.default_serializers *Devise::SERIALIZERS
107
113
  manager.failure_app = Devise::Failure
108
114
  manager.silence_missing_strategies!
115
+ manager.silence_missing_serializers!
109
116
 
110
117
  # If the user provided a warden hook, call it now.
111
118
  @warden_config.try :call, manager
@@ -118,5 +125,14 @@ module Devise
118
125
  end
119
126
  end
120
127
 
121
- require 'devise/warden'
128
+ begin
129
+ require 'warden'
130
+ rescue
131
+ gem 'warden'
132
+ require 'warden'
133
+ end
134
+
135
+ require 'devise/strategies/base'
136
+ require 'devise/serializers/base'
137
+
122
138
  require 'devise/rails'
@@ -49,17 +49,45 @@ module Devise
49
49
  warden.authenticated?(scope)
50
50
  end
51
51
 
52
- # Set the warden user with the scope, signing in the resource automatically,
53
- # without running hooks.
54
- def sign_in(scope, resource)
52
+ # Sign in an user that already was authenticated. This helper is useful for logging
53
+ # users in after sign up.
54
+ #
55
+ # Examples:
56
+ #
57
+ # sign_in :user, @user # sign_in(scope, resource)
58
+ # sign_in @user # sign_in(resource)
59
+ #
60
+ def sign_in(resource_or_scope, resource=nil)
61
+ scope ||= find_devise_scope(resource_or_scope)
62
+ resource ||= resource_or_scope
55
63
  warden.set_user(resource, :scope => scope)
56
64
  end
57
65
 
58
- # Sign out based on scope.
59
- def sign_out(scope, *args)
66
+ # Sign out a given user or scope. This helper is useful for signing out an user
67
+ # after deleting accounts.
68
+ #
69
+ # Examples:
70
+ #
71
+ # sign_out :user # sign_out(scope)
72
+ # sign_out @user # sign_out(resource)
73
+ #
74
+ def sign_out(resource_or_scope)
75
+ scope = find_devise_scope(resource_or_scope)
60
76
  warden.user(scope) # Without loading user here, before_logout hook is not called
61
77
  warden.raw_session.inspect # Without this inspect here. The session does not clear.
62
- warden.logout(scope, *args)
78
+ warden.logout(scope)
79
+ end
80
+
81
+ # Returns and delete the url stored in the session for the given scope. Useful
82
+ # for giving redirect backs after sign up:
83
+ #
84
+ # Example:
85
+ #
86
+ # redirect_to stored_location_for(:user) || root_path
87
+ #
88
+ def stored_location_for(resource_or_scope)
89
+ scope = find_devise_scope(resource_or_scope)
90
+ session.delete(:"#{scope}.return_to")
63
91
  end
64
92
 
65
93
  # Define authentication filters and accessor helpers based on mappings.
@@ -106,6 +134,16 @@ module Devise
106
134
  METHODS
107
135
  end
108
136
 
137
+ protected
138
+
139
+ def find_devise_scope(resource_or_scope)
140
+ if resource_or_scope.is_a?(Symbol)
141
+ resource_or_scope
142
+ else
143
+ Devise::Mapping.find_by_class!(resource_or_scope.class).name
144
+ end
145
+ end
146
+
109
147
  end
110
148
  end
111
149
  end
@@ -45,18 +45,7 @@ module Devise
45
45
  # Redirects to stored uri before signing in or the default path and clear
46
46
  # return to.
47
47
  def redirect_back_or_to(default)
48
- redirect_to(return_to || default)
49
- clear_return_to
50
- end
51
-
52
- # Access to scoped stored uri
53
- def return_to
54
- session[:"#{resource_name}.return_to"]
55
- end
56
-
57
- # Clear scoped stored uri
58
- def clear_return_to
59
- session[:"#{resource_name}.return_to"] = nil
48
+ redirect_to(stored_location_for(resource_name) || default)
60
49
  end
61
50
 
62
51
  # Checks for the existence of the resource root path. If it exists,
@@ -34,6 +34,18 @@ module Devise
34
34
  nil
35
35
  end
36
36
 
37
+ # Find a mapping by a given class. It takes into account single table inheritance as well.
38
+ def self.find_by_class(klass)
39
+ Devise.mappings.values.find { |m| return m if klass <= m.to }
40
+ end
41
+
42
+ # Find by class but raising an error in case it can't be found.
43
+ def self.find_by_class!(klass)
44
+ mapping = find_by_class(klass)
45
+ raise "Could not find a valid mapping for #{klass}" unless mapping
46
+ mapping
47
+ end
48
+
37
49
  # Default url options which can be used as prefix.
38
50
  def self.default_url_options
39
51
  {}
@@ -16,28 +16,30 @@ module Devise
16
16
  # To add the class methods you need to have a module ClassMethods defined
17
17
  # inside the given class.
18
18
  #
19
- def self.config(mod, accessor) #:nodoc:
20
- mod.class_eval <<-METHOD, __FILE__, __LINE__
21
- def #{accessor}
22
- self.class.#{accessor}
23
- end
24
- METHOD
19
+ def self.config(mod, *accessors) #:nodoc:
20
+ accessors.each do |accessor|
21
+ mod.class_eval <<-METHOD, __FILE__, __LINE__
22
+ def #{accessor}
23
+ self.class.#{accessor}
24
+ end
25
+ METHOD
25
26
 
26
- mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
27
- def #{accessor}
28
- if defined?(@#{accessor})
29
- @#{accessor}
30
- elsif superclass.respond_to?(:#{accessor})
31
- superclass.#{accessor}
32
- else
33
- Devise.#{accessor}
27
+ mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
28
+ def #{accessor}
29
+ if defined?(@#{accessor})
30
+ @#{accessor}
31
+ elsif superclass.respond_to?(:#{accessor})
32
+ superclass.#{accessor}
33
+ else
34
+ Devise.#{accessor}
35
+ end
34
36
  end
35
- end
36
37
 
37
- def #{accessor}=(value)
38
- @#{accessor} = value
39
- end
40
- METHOD
38
+ def #{accessor}=(value)
39
+ @#{accessor} = value
40
+ end
41
+ METHOD
42
+ end
41
43
  end
42
44
 
43
45
  # Shortcut method for including all devise modules inside your model.
@@ -1,4 +1,5 @@
1
1
  require 'devise/strategies/authenticatable'
2
+ require 'devise/serializers/authenticatable'
2
3
 
3
4
  module Devise
4
5
  module Models
@@ -18,6 +19,10 @@ module Devise
18
19
  #
19
20
  # stretches: defines how many times the password will be encrypted.
20
21
  #
22
+ # encryptor: the encryptor going to be used. By default :sha1.
23
+ #
24
+ # authentication_keys: parameters used for authentication. By default [:email]
25
+ #
21
26
  # Examples:
22
27
  #
23
28
  # User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
@@ -64,7 +69,9 @@ module Devise
64
69
  # authenticated user if it's valid or nil.
65
70
  # Attributes are :email and :password
66
71
  def authenticate(attributes={})
67
- authenticatable = find_by_email(attributes[:email])
72
+ return unless authentication_keys.all? { |k| attributes[k].present? }
73
+ conditions = attributes.slice(*authentication_keys)
74
+ authenticatable = find(:first, :conditions => conditions)
68
75
  authenticatable if authenticatable.try(:valid_password?, attributes[:password])
69
76
  end
70
77
 
@@ -77,11 +84,21 @@ module Devise
77
84
  end
78
85
  perishable
79
86
  end
87
+
88
+ # Hook to serialize user into session. Overwrite if you want.
89
+ def serialize_into_session(record)
90
+ [record.class, record.id]
91
+ end
92
+
93
+ # Hook to serialize user from session. Overwrite if you want.
94
+ def serialize_from_session(keys)
95
+ klass, id = keys
96
+ raise "#{self} cannot serialize from #{klass} session since it's not its ancestors" unless klass <= self
97
+ klass.find_by_id(id)
98
+ end
80
99
  end
81
100
 
82
- Devise::Models.config(self, :pepper)
83
- Devise::Models.config(self, :stretches)
84
- Devise::Models.config(self, :encryptor)
101
+ Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
85
102
  end
86
103
  end
87
104
  end
@@ -1,6 +1,5 @@
1
1
  require 'digest/sha1'
2
- require 'devise/hooks/rememberable'
3
- require 'devise/middlewares/rememberable'
2
+ require 'devise/serializers/rememberable'
4
3
 
5
4
  module Devise
6
5
  module Models
@@ -12,14 +12,18 @@ module Devise
12
12
 
13
13
  def self.included(base)
14
14
  base.class_eval do
15
+ attribute = authentication_keys.first
15
16
 
16
- validates_presence_of :email
17
- validates_uniqueness_of :email, :allow_blank => true
18
- validates_format_of :email, :with => EMAIL_REGEX, :allow_blank => true
17
+ validates_presence_of attribute
18
+ validates_uniqueness_of attribute, :allow_blank => true
19
+ validates_format_of attribute, :with => EMAIL_REGEX, :allow_blank => true,
20
+ :scope => authentication_keys[1..-1]
19
21
 
20
- validates_presence_of :password, :if => :password_required?
21
- validates_confirmation_of :password, :if => :password_required?
22
- validates_length_of :password, :within => 6..20, :allow_blank => true, :if => :password_required?
22
+ with_options :if => :password_required? do |v|
23
+ v.validates_presence_of :password
24
+ v.validates_confirmation_of :password
25
+ v.validates_length_of :password, :within => 6..20, :allow_blank => true
26
+ end
23
27
  end
24
28
  end
25
29
 
@@ -10,8 +10,5 @@ Rails.configuration.after_initialize do
10
10
  Devise.configure_warden_manager(manager)
11
11
  end
12
12
 
13
- # If using a rememberable module, include the middleware that log users.
14
- Rails.configuration.middleware.use Devise::Middlewares::Rememberable
15
-
16
13
  I18n.load_path.unshift File.expand_path(File.join(File.dirname(__FILE__), 'locales', 'en.yml'))
17
14
  end
@@ -9,10 +9,6 @@ module Warden::Mixins::Common
9
9
  end
10
10
  end
11
11
 
12
- def raw_session
13
- request.session
14
- end
15
-
16
12
  def reset_session!
17
13
  raw_session.inspect # why do I have to inspect it to get it to clear?
18
14
  raw_session.clear
@@ -0,0 +1,9 @@
1
+ module Devise
2
+ module Serializers
3
+ class Authenticatable < Warden::Serializers::Session
4
+ include Devise::Serializers::Base
5
+ end
6
+ end
7
+ end
8
+
9
+ Warden::Serializers.add(:authenticatable, Devise::Serializers::Authenticatable)
@@ -0,0 +1,41 @@
1
+ module Devise
2
+ module Serializers
3
+ module Base
4
+ include Devise::Strategies::Base
5
+ attr_reader :scope
6
+
7
+ def serialize(record)
8
+ record.class.send(:"serialize_into_#{serialization_type}", record)
9
+ end
10
+
11
+ def deserialize(keys)
12
+ mapping.to.send(:"serialize_from_#{serialization_type}", keys)
13
+ end
14
+
15
+ def store(user, scope)
16
+ @scope = scope
17
+ return unless valid?
18
+ super
19
+ end
20
+
21
+ def fetch(scope)
22
+ @scope = scope
23
+ return unless valid?
24
+ super
25
+ end
26
+
27
+ def delete(scope, user=nil)
28
+ @scope = scope
29
+ return unless valid?
30
+ super
31
+ end
32
+
33
+ def serialization_type
34
+ @serialization_type ||= begin
35
+ warden = self.class.ancestors.find{ |k| k < Warden::Serializers::Base && k != self.class }
36
+ warden.name.split("::").last.underscore
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Devise
2
+ module Serializers
3
+ class Rememberable < Warden::Serializers::Cookie
4
+ include Devise::Serializers::Base
5
+
6
+ def store(record, scope)
7
+ remember_me = params[scope].try(:fetch, :remember_me, nil)
8
+ if Devise::TRUE_VALUES.include?(remember_me) && record.respond_to?(:remember_me!)
9
+ record.remember_me!
10
+ super
11
+ end
12
+ end
13
+
14
+ def default_options(record)
15
+ super.merge!(:expires => record.remember_expires_at)
16
+ end
17
+
18
+ def delete(scope, record=nil)
19
+ record.forget_me! if record && record.respond_to?(:forget_me!)
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ Warden::Serializers.add(:rememberable, Devise::Serializers::Rememberable)
@@ -2,7 +2,8 @@ module Devise
2
2
  module Strategies
3
3
  # Default strategy for signing in a user, based on his email and password.
4
4
  # Redirects to sign_in page if it's not authenticated
5
- class Authenticatable < Devise::Strategies::Base
5
+ class Authenticatable < Warden::Strategies::Base
6
+ include Devise::Strategies::Base
6
7
 
7
8
  # Authenticate a user based on email and password params, returning to warden
8
9
  # success and the authenticated user if everything is okay. Otherwise redirect
@@ -12,7 +13,7 @@ module Devise
12
13
  # The first does not perform any action when calling authenticate, just
13
14
  # when authenticate! is invoked. The second always perform the action.
14
15
  def authenticate!
15
- if valid_attributes? && resource = mapping.to.authenticate(attributes)
16
+ if valid_attributes? && resource = mapping.to.authenticate(params[scope])
16
17
  success!(resource)
17
18
  else
18
19
  store_location
@@ -22,14 +23,9 @@ module Devise
22
23
 
23
24
  private
24
25
 
25
- # Find the attributes for the current mapping.
26
- def attributes
27
- @attributes ||= params[scope]
28
- end
29
-
30
- # Check for the right keys.
26
+ # Check if params and password are given. Others are checked inside authenticate.
31
27
  def valid_attributes?
32
- attributes && attributes[:email].present? && attributes[:password].present?
28
+ params[scope] && params[scope][:password].present?
33
29
  end
34
30
 
35
31
  # Stores requested uri to redirect the user after signing in. We cannot use
@@ -1,23 +1,22 @@
1
1
  module Devise
2
2
  module Strategies
3
- # Base strategy for Devise. Responsible for verifying correct scope and
4
- # mapping.
5
- class Base < Warden::Strategies::Base
6
-
3
+ # Base strategy for Devise. Responsible for verifying correct scope and mapping.
4
+ module Base
7
5
  # Validate strategy. By default will raise an error if no scope or an
8
6
  # invalid mapping is found.
9
7
  def valid?
10
- mapping.for.include?(self.class.name.split("::").last.underscore.to_sym)
8
+ mapping.for.include?(klass_type)
11
9
  end
12
10
 
13
11
  # Checks if a valid scope was given for devise and find mapping based on
14
12
  # this scope.
15
13
  def mapping
16
- @mapping ||= begin
17
- raise "You need to give a scope for Devise authentication" unless scope
18
- raise "You need to give a valid Devise mapping" unless mapping = Devise.mappings[scope]
19
- mapping
20
- end
14
+ Devise.mappings[scope]
15
+ end
16
+
17
+ # Store this class type.
18
+ def klass_type
19
+ @klass_type ||= self.class.name.split("::").last.underscore.to_sym
21
20
  end
22
21
  end
23
22
  end
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "0.5.0".freeze
2
+ VERSION = "0.5.1".freeze
3
3
  end
@@ -14,11 +14,13 @@ class MockController < ApplicationController
14
14
  end
15
15
 
16
16
  class ControllerAuthenticableTest < ActionController::TestCase
17
+ tests MockController
17
18
 
18
19
  def setup
19
20
  @controller = MockController.new
20
21
  @mock_warden = OpenStruct.new
21
22
  @controller.env = { 'warden' => @mock_warden }
23
+ @controller.session = {}
22
24
  end
23
25
 
24
26
  test 'setup warden' do
@@ -47,12 +49,6 @@ class ControllerAuthenticableTest < ActionController::TestCase
47
49
  @controller.current_user
48
50
  end
49
51
 
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
52
  test 'proxy user_authenticate! to authenticate with user scope' do
57
53
  @mock_warden.expects(:authenticate!).with(:scope => :user)
58
54
  @controller.authenticate_user!
@@ -83,11 +79,48 @@ class ControllerAuthenticableTest < ActionController::TestCase
83
79
  @controller.admin_session
84
80
  end
85
81
 
86
- test 'sign in automatically proxy to set user on warden' do
87
- @mock_warden.expects(:set_user).with(user = mock, :scope => :user).returns(true)
82
+ test 'sign in proxy to set_user on warden' do
83
+ user = User.new
84
+ @mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
88
85
  @controller.sign_in(:user, user)
89
86
  end
90
87
 
88
+ test 'sign in accepts a resource as argument' do
89
+ user = User.new
90
+ @mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
91
+ @controller.sign_in(user)
92
+ end
93
+
94
+ test 'sign out proxy to logout on warden' do
95
+ @mock_warden.expects(:user).with(:user).returns(true)
96
+ @mock_warden.expects(:logout).with(:user).returns(true)
97
+ @controller.sign_out(:user)
98
+ end
99
+
100
+ test 'sign out accepts a resource as argument' do
101
+ @mock_warden.expects(:user).with(:user).returns(true)
102
+ @mock_warden.expects(:logout).with(:user).returns(true)
103
+ @controller.sign_out(User.new)
104
+ end
105
+
106
+ test 'stored location for returns the location for a given scope' do
107
+ assert_nil @controller.stored_location_for(:user)
108
+ @controller.session[:"user.return_to"] = "/foo.bar"
109
+ assert_equal "/foo.bar", @controller.stored_location_for(:user)
110
+ end
111
+
112
+ test 'stored location for accepts a resource as argument' do
113
+ assert_nil @controller.stored_location_for(:user)
114
+ @controller.session[:"user.return_to"] = "/foo.bar"
115
+ assert_equal "/foo.bar", @controller.stored_location_for(User.new)
116
+ end
117
+
118
+ test 'stored location cleans information after reading' do
119
+ @controller.session[:"user.return_to"] = "/foo.bar"
120
+ assert_equal "/foo.bar", @controller.stored_location_for(:user)
121
+ assert_nil @controller.session[:"user.return_to"]
122
+ end
123
+
91
124
  test 'is not a devise controller' do
92
125
  assert_not @controller.devise_controller?
93
126
  end
@@ -15,6 +15,10 @@ class DeviseTest < ActiveSupport::TestCase
15
15
  @silence_missing_strategies = true
16
16
  end
17
17
 
18
+ def silence_missing_serializers!
19
+ @silence_missing_serializers = true
20
+ end
21
+
18
22
  def default_strategies(*args)
19
23
  if args.empty?
20
24
  @default_strategies
@@ -22,6 +26,14 @@ class DeviseTest < ActiveSupport::TestCase
22
26
  @default_strategies = args
23
27
  end
24
28
  end
29
+
30
+ def default_serializers(*args)
31
+ if args.empty?
32
+ @default_serializers
33
+ else
34
+ @default_serializers = args
35
+ end
36
+ end
25
37
  end
26
38
 
27
39
  test 'DeviseMailer.sender can be configured through Devise' do
@@ -76,6 +76,13 @@ class AuthenticationTest < ActionController::IntegrationTest
76
76
  assert_contain 'Welcome Admin'
77
77
  end
78
78
 
79
+ test 'sign in as user should not authenticate if not using proper authentication keys' do
80
+ swap Devise, :authentication_keys => [:username] do
81
+ sign_in_as_user
82
+ assert_not warden.authenticated?(:user)
83
+ end
84
+ end
85
+
79
86
  test 'admin signing in with invalid email should return to sign in form with error message' do
80
87
  sign_in_as_admin do
81
88
  fill_in 'email', :with => 'wrongemail@test.com'
@@ -6,7 +6,7 @@ class RememberMeTest < ActionController::IntegrationTest
6
6
  Devise.remember_for = 1
7
7
  user = create_user
8
8
  user.remember_me!
9
- cookies['remember_user_token'] = User.serialize_into_cookie(user) + add_to_token
9
+ cookies['warden.user.user.key'] = User.serialize_into_cookie(user) + add_to_token
10
10
  user
11
11
  end
12
12
 
@@ -30,15 +30,31 @@ class MappingTest < ActiveSupport::TestCase
30
30
  assert_not mapping.allows?(:passwords)
31
31
  end
32
32
 
33
- test 'return mapping by path' do
33
+ test 'find mapping by path' do
34
34
  assert_nil Devise::Mapping.find_by_path("/foo/bar")
35
35
  assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session")
36
36
  end
37
37
 
38
- test 'return mapping by customized path' do
38
+ test 'find mapping by customized path' do
39
39
  assert_equal Devise.mappings[:admin], Devise::Mapping.find_by_path("/admin_area/session")
40
40
  end
41
41
 
42
+ test 'find mapping by class' do
43
+ assert_nil Devise::Mapping.find_by_class(String)
44
+ assert_equal Devise.mappings[:user], Devise::Mapping.find_by_class(User)
45
+ end
46
+
47
+ test 'find mapping by class works with single table inheritance' do
48
+ klass = Class.new(User)
49
+ assert_equal Devise.mappings[:user], Devise::Mapping.find_by_class(klass)
50
+ end
51
+
52
+ test 'find mapping raises an error for invalid class' do
53
+ assert_raise RuntimeError do
54
+ Devise::Mapping.find_by_class!(String)
55
+ end
56
+ end
57
+
42
58
  test 'return default path names' do
43
59
  mapping = Devise.mappings[:user]
44
60
  assert_equal 'sign_in', mapping.path_names[:sign_in]
@@ -127,4 +127,35 @@ class AuthenticatableTest < ActiveSupport::TestCase
127
127
  authenticated_user = User.authenticate(:email => user.email, :password => 'another_password')
128
128
  assert_nil authenticated_user
129
129
  end
130
+
131
+ test 'should use authentication keys to retrieve users' do
132
+ swap Devise, :authentication_keys => [:username] do
133
+ user = create_user(:username => "josevalim")
134
+ assert_nil User.authenticate(:email => user.email, :password => user.password)
135
+ assert_not_nil User.authenticate(:username => user.username, :password => user.password)
136
+ end
137
+ end
138
+
139
+ test 'should serialize user into session' do
140
+ user = create_user
141
+ assert_equal [User, user.id], User.serialize_into_session(user)
142
+ end
143
+
144
+ test 'should serialize user from session' do
145
+ user = create_user
146
+ assert_equal user.id, User.serialize_from_session([User, user.id]).id
147
+ end
148
+
149
+ test 'should not serialize another klass from session' do
150
+ user = create_user
151
+ assert_raise RuntimeError, /ancestors/ do
152
+ User.serialize_from_session([Admin, user.id])
153
+ end
154
+ end
155
+
156
+ test 'should serialize another klass from session' do
157
+ user = create_user
158
+ klass = Class.new(User)
159
+ assert_equal user.id, User.serialize_from_session([klass, user.id]).id
160
+ end
130
161
  end
@@ -18,6 +18,7 @@ ActiveRecord::Schema.define(:version => 1) do
18
18
  [:users, :admins].each do |table|
19
19
  create_table table do |t|
20
20
  t.authenticatable :null => table == :admins
21
+ t.string :username if table == :users
21
22
 
22
23
  if table == :users
23
24
  t.confirmable
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Jos\xC3\xA9 Valim"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-11-13 00:00:00 -02:00
13
+ date: 2009-11-15 00:00:00 -02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -21,7 +21,7 @@ dependencies:
21
21
  requirements:
22
22
  - - ~>
23
23
  - !ruby/object:Gem::Version
24
- version: 0.5.2
24
+ version: 0.6.0
25
25
  version:
26
26
  description: Flexible authentication solution for Rails with Warden
27
27
  email: contact@plataformatec.com.br
@@ -70,10 +70,8 @@ files:
70
70
  - lib/devise/encryptors/sha512.rb
71
71
  - lib/devise/failure.rb
72
72
  - lib/devise/hooks/confirmable.rb
73
- - lib/devise/hooks/rememberable.rb
74
73
  - lib/devise/locales/en.yml
75
74
  - lib/devise/mapping.rb
76
- - lib/devise/middlewares/rememberable.rb
77
75
  - lib/devise/models.rb
78
76
  - lib/devise/models/authenticatable.rb
79
77
  - lib/devise/models/confirmable.rb
@@ -86,10 +84,12 @@ files:
86
84
  - lib/devise/rails/routes.rb
87
85
  - lib/devise/rails/warden_compat.rb
88
86
  - lib/devise/schema.rb
87
+ - lib/devise/serializers/authenticatable.rb
88
+ - lib/devise/serializers/base.rb
89
+ - lib/devise/serializers/rememberable.rb
89
90
  - lib/devise/strategies/authenticatable.rb
90
91
  - lib/devise/strategies/base.rb
91
92
  - lib/devise/version.rb
92
- - lib/devise/warden.rb
93
93
  has_rdoc: true
94
94
  homepage: http://github.com/plataformatec/devise
95
95
  licenses: []
@@ -1,29 +0,0 @@
1
- # After authenticate hook to verify if the user in the given scope asked to be
2
- # remembered while he does not sign out. Generates a new remember token for
3
- # that specific user and adds a cookie with this user info to sign in this user
4
- # automatically without asking for credentials. Refer to rememberable strategy
5
- # for more info.
6
- Warden::Manager.after_authentication do |record, warden, options|
7
- scope = options[:scope]
8
- remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
9
-
10
- if Devise::TRUE_VALUES.include?(remember_me) && record.respond_to?(:remember_me!)
11
- record.remember_me!
12
-
13
- warden.response.set_cookie "remember_#{scope}_token", {
14
- :value => record.class.serialize_into_cookie(record),
15
- :expires => record.remember_expires_at,
16
- :path => "/"
17
- }
18
- end
19
- end
20
-
21
- # Before logout hook to forget the user in the given scope, only if rememberable
22
- # is activated for this scope. Also clear remember token to ensure the user
23
- # won't be remembered again.
24
- Warden::Manager.before_logout do |record, warden, scope|
25
- if record.respond_to?(:forget_me!)
26
- record.forget_me!
27
- warden.response.delete_cookie "remember_#{scope}_token"
28
- end
29
- end
@@ -1,35 +0,0 @@
1
- module Devise
2
- module Middlewares
3
- class Rememberable
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- auth = env['warden']
10
- scopes = select_cookies(auth.request)
11
- scopes.each do |scope, token|
12
- mapping = Devise.mappings[scope]
13
- next unless mapping && mapping.for.include?(:rememberable)
14
- user = mapping.to.serialize_from_cookie(token)
15
- auth.set_user(user, :scope => scope) if user
16
- end
17
-
18
- @app.call(env)
19
- end
20
-
21
- protected
22
-
23
- def select_cookies(request)
24
- scopes = {}
25
- matching = /remember_(#{Devise.mappings.keys.join("|")})_token/
26
- request.cookies.each do |key, value|
27
- if key.to_s =~ matching
28
- scopes[$1.to_sym] = value
29
- end
30
- end
31
- scopes
32
- end
33
- end
34
- end
35
- end
@@ -1,20 +0,0 @@
1
- begin
2
- require 'warden'
3
- rescue
4
- gem 'warden'
5
- require 'warden'
6
- end
7
-
8
- # Session Serialization in. This block determines how the user will be stored
9
- # in the session. If you're using a complex object like an ActiveRecord model,
10
- # it is not a good idea to store the complete object. An ID is sufficient.
11
- Warden::Manager.serialize_into_session{ |user| [user.class, user.id] }
12
-
13
- # Session Serialization out. This block gets the user out of the session.
14
- # It should be the reverse of serializing the object into the session
15
- Warden::Manager.serialize_from_session do |klass, id|
16
- klass.find_by_id(id)
17
- end
18
-
19
- # Setup devise strategies for Warden
20
- require 'devise/strategies/base'