Skip to content
Browse files

Add authentication_keys.

  • Loading branch information...
1 parent dbe0b48 commit b70b293690bd66ec863330ef640270c149fd6b8c @josevalim josevalim committed Nov 15, 2009
View
4 CHANGELOG.rdoc
@@ -1,3 +1,7 @@
+* enhancements
+ * Added serializers based on Warden ones
+ * Allow authentication keys to be set
+
== 0.5.0
* bug fix
View
4 README.rdoc
@@ -46,7 +46,7 @@ And you're ready to go.
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.
-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.
+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.
We're assuming here you want a User model. First of all you have to setup a migration with the following fields:
@@ -93,7 +93,7 @@ Note that validations aren't added by default, so you're able to customize it. I
== Model configuration
-In addition to :except, you can provide :pepper, :stretches, :confirm_within and :remember_for as options to devise method.
+In addition to :except, you can provide :pepper, :stretches, :encryptor, :authentication_keys, :confirm_within and :remember_for as options to devise method.
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.
View
1 TODO
@@ -1,4 +1,3 @@
-* Allow authentication keys to be configured, so things like username and subdomain can be used
* Devise::Timeoutable
* Devise::TestHelper
* Use request_ip in session cookies
View
7 generators/devise_install/templates/devise.rb
@@ -15,6 +15,13 @@
# should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :sha1
+ # Configure which keys are used when authenticating an user. By default is
+ # just :email. You can configure it to use [:username, :subdomain], so for
+ # authenticating an user, both parameters are required. Remember that those
+ # parameters are used only when authenticating and not when retrieving from
+ # session. If you need permissions, you should implement that in a before filter.
+ # config.authentication_keys = [ :email ]
+
# The time you want give to your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is nil.
# config.confirm_within = 2.days
View
4 lib/devise.rb
@@ -36,6 +36,10 @@ module Devise
mattr_accessor :stretches
@@stretches = 10
+ # Keys used when authenticating an user.
+ mattr_accessor :authentication_keys
+ @@authentication_keys = [ :email ]
+
# Time interval where the remember me token is valid.
mattr_accessor :remember_for
@@remember_for = 2.weeks
View
40 lib/devise/models.rb
@@ -16,28 +16,30 @@ module Models
# To add the class methods you need to have a module ClassMethods defined
# inside the given class.
#
- def self.config(mod, accessor) #:nodoc:
- mod.class_eval <<-METHOD, __FILE__, __LINE__
- def #{accessor}
- self.class.#{accessor}
- end
- METHOD
+ def self.config(mod, *accessors) #:nodoc:
+ accessors.each do |accessor|
+ mod.class_eval <<-METHOD, __FILE__, __LINE__
+ def #{accessor}
+ self.class.#{accessor}
+ end
+ METHOD
- mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
- def #{accessor}
- if defined?(@#{accessor})
- @#{accessor}
- elsif superclass.respond_to?(:#{accessor})
- superclass.#{accessor}
- else
- Devise.#{accessor}
+ mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
+ def #{accessor}
+ if defined?(@#{accessor})
+ @#{accessor}
+ elsif superclass.respond_to?(:#{accessor})
+ superclass.#{accessor}
+ else
+ Devise.#{accessor}
+ end
end
- end
- def #{accessor}=(value)
- @#{accessor} = value
- end
- METHOD
+ def #{accessor}=(value)
+ @#{accessor} = value
+ end
+ METHOD
+ end
end
# Shortcut method for including all devise modules inside your model.
View
12 lib/devise/models/authenticatable.rb
@@ -19,6 +19,10 @@ module Models
#
# stretches: defines how many times the password will be encrypted.
#
+ # encryptor: the encryptor going to be used. By default :sha1.
+ #
+ # authentication_keys: parameters used for authentication. By default [:email]
+ #
# Examples:
#
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
@@ -65,7 +69,9 @@ module ClassMethods
# authenticated user if it's valid or nil.
# Attributes are :email and :password
def authenticate(attributes={})
- authenticatable = find_by_email(attributes[:email])
+ return unless authentication_keys.all? { |k| attributes[k].present? }
+ conditions = attributes.slice(*authentication_keys)
+ authenticatable = find(:first, :conditions => conditions)
authenticatable if authenticatable.try(:valid_password?, attributes[:password])
end
@@ -91,9 +97,7 @@ def serialize_from_session(keys)
end
end
- Devise::Models.config(self, :pepper)
- Devise::Models.config(self, :stretches)
- Devise::Models.config(self, :encryptor)
+ Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
end
end
end
View
11 lib/devise/strategies/authenticatable.rb
@@ -13,7 +13,7 @@ class Authenticatable < Warden::Strategies::Base
# The first does not perform any action when calling authenticate, just
# when authenticate! is invoked. The second always perform the action.
def authenticate!
- if valid_attributes? && resource = mapping.to.authenticate(attributes)
+ if valid_attributes? && resource = mapping.to.authenticate(params[scope])
success!(resource)
else
store_location
@@ -23,14 +23,9 @@ def authenticate!
private
- # Find the attributes for the current mapping.
- def attributes
- @attributes ||= params[scope]
- end
-
- # Check for the right keys.
+ # Check if params and password are given. Others are checked inside authenticate.
def valid_attributes?
- attributes && attributes[:email].present? && attributes[:password].present?
+ params[scope] && params[scope][:password].present?
end
# Stores requested uri to redirect the user after signing in. We cannot use
View
7 test/integration/authenticatable_test.rb
@@ -76,6 +76,13 @@ class AuthenticationTest < ActionController::IntegrationTest
assert_contain 'Welcome Admin'
end
+ test 'sign in as user should not authenticate if not using proper authentication keys' do
+ swap Devise, :authentication_keys => [:username] do
+ sign_in_as_user
+ assert_not warden.authenticated?(:user)
+ end
+ end
+
test 'admin signing in with invalid email should return to sign in form with error message' do
sign_in_as_admin do
fill_in 'email', :with => 'wrongemail@test.com'
View
18 test/models/authenticatable_test.rb
@@ -127,4 +127,22 @@ def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encrypt
authenticated_user = User.authenticate(:email => user.email, :password => 'another_password')
assert_nil authenticated_user
end
+
+ test 'should use authentication keys to retrieve users' do
+ swap Devise, :authentication_keys => [:username] do
+ user = create_user(:username => "josevalim")
+ assert_nil User.authenticate(:email => user.email, :password => user.password)
+ assert_not_nil User.authenticate(:username => user.username, :password => user.password)
+ end
+ end
+
+ test 'should serialize user into session' do
+ user = create_user
+ assert_equal [User, user.id], User.serialize_into_session(user)
+ end
+
+ test 'should serialize user from session' do
+ user = create_user
+ assert_equal user.id, User.serialize_from_session([User, user.id]).id
+ end
end
View
1 test/test_helper.rb
@@ -18,6 +18,7 @@
[:users, :admins].each do |table|
create_table table do |t|
t.authenticatable :null => table == :admins
+ t.string :username if table == :users
if table == :users
t.confirmable

0 comments on commit b70b293

Please sign in to comment.
Something went wrong with that request. Please try again.