Add authentication_keys.

This commit is contained in:
José Valim 2009-11-15 03:31:13 -02:00
parent dbe0b48bca
commit b70b293690
11 changed files with 76 additions and 35 deletions

View File

@ -1,3 +1,7 @@
* enhancements
* Added serializers based on Warden ones
* Allow authentication keys to be set
== 0.5.0
* bug fix

View File

@ -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.

1
TODO
View File

@ -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 File

@ -15,6 +15,13 @@ Devise.setup do |config|
# 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 File

@ -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 File

@ -16,28 +16,30 @@ module Devise
# 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
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}
def self.config(mod, *accessors) #:nodoc:
accessors.each do |accessor|
mod.class_eval <<-METHOD, __FILE__, __LINE__
def #{accessor}
self.class.#{accessor}
end
end
METHOD
def #{accessor}=(value)
@#{accessor} = value
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}
end
end
def #{accessor}=(value)
@#{accessor} = value
end
METHOD
end
end
# Shortcut method for including all devise modules inside your model.

View File

@ -19,6 +19,10 @@ module Devise
#
# 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 Devise
# 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 @@ module Devise
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 File

@ -13,7 +13,7 @@ module Devise
# 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 @@ module Devise
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 File

@ -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 File

@ -127,4 +127,22 @@ class AuthenticatableTest < ActiveSupport::TestCase
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 File

@ -18,6 +18,7 @@ ActiveRecord::Schema.define(:version => 1) do
[: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