Compare commits

..

9 Commits

Author SHA1 Message Date
José Valim
e02810d528 Move to 0.9.2. 2010-02-05 21:37:28 +01:00
José Valim
c146cad448 Ensure inactive user cannot sign in. 2010-02-05 21:36:19 +01:00
Carlos Antonio da Silva
4de1e43b7a Fix "return_to" to always save the request_uri, overwriting the return to url when the user types another forbidden url before sign in.
This way the user will be redirected to the last attempted url and not the first one.
2010-02-04 08:46:22 -02:00
Matt Powell
02a99b9766 deprecate find(:first) and find(:all) in MongoMapper 2010-02-03 16:53:49 +08:00
José Valim
a9e2337aeb Change EMAIL_REGEXP so it can be used in javascript. 2010-02-02 13:28:47 +01:00
José Valim
3781a0f47b Tidy up token authentication implementation. 2010-02-02 13:21:00 +01:00
Jonas Grimfelt
4878bdb60b Second version of token_authenticatable reflecting feedback: Nuked all hook-stuff. Should be easy to custom-reset authentication tokens by inheritance.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-02 12:37:06 +01:00
Jonas Grimfelt
e1440fb430 Initial support for authorization using "authentication token" (a.k.a. "single access token") - new module. Corresponding changes to Devise core to hook events like "after_changed_password" (only one added now - only one that makes much sense for latest module) easily. Unit and integration tests included. NOTE: One failing test for hooking Warden::Manager.after_authentication - gets ignored for some reason.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-02 12:36:44 +01:00
José Valim
c03b4ff339 Add gemspec since it's required by bundler. 2010-02-01 16:32:36 +01:00
23 changed files with 513 additions and 23 deletions

1
.gitignore vendored
View File

@@ -4,5 +4,4 @@
coverage/*
*.sqlite3
rdoc/*
devise.gemspec
pkg

View File

@@ -1,3 +1,13 @@
== 0.9.2
* bug fix
* Ensure inactive user cannot sign in
* Ensure redirect to proper url after sign up
* enhancements
* Added gemspec to repo
* Added token authenticatable (by github.com/grimen)
== 0.9.1
* bug fix

View File

@@ -18,7 +18,7 @@ class SessionsController < ApplicationController
set_flash_message :notice, :signed_in
sign_in_and_redirect(resource_name, resource, true)
else
set_now_flash_message :alert, warden.message || :invalid
set_now_flash_message :alert, (warden.message || :invalid)
build_resource
render_with_scope :new
end

168
devise.gemspec Normal file
View File

@@ -0,0 +1,168 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{devise}
s.version = "0.9.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jos\303\251 Valim", "Carlos Ant\303\264nio"]
s.date = %q{2010-02-01}
s.description = %q{Flexible authentication solution for Rails with Warden}
s.email = %q{contact@plataformatec.com.br}
s.extra_rdoc_files = [
"README.rdoc",
"TODO"
]
s.files = [
"CHANGELOG.rdoc",
"MIT-LICENSE",
"README.rdoc",
"Rakefile",
"TODO",
"app/controllers/confirmations_controller.rb",
"app/controllers/passwords_controller.rb",
"app/controllers/sessions_controller.rb",
"app/controllers/unlocks_controller.rb",
"app/models/devise_mailer.rb",
"app/views/confirmations/new.html.erb",
"app/views/devise_mailer/confirmation_instructions.html.erb",
"app/views/devise_mailer/reset_password_instructions.html.erb",
"app/views/devise_mailer/unlock_instructions.html.erb",
"app/views/passwords/edit.html.erb",
"app/views/passwords/new.html.erb",
"app/views/sessions/new.html.erb",
"app/views/shared/_devise_links.erb",
"app/views/unlocks/new.html.erb",
"generators/devise/USAGE",
"generators/devise/devise_generator.rb",
"generators/devise/lib/route_devise.rb",
"generators/devise/templates/migration.rb",
"generators/devise/templates/model.rb",
"generators/devise_install/USAGE",
"generators/devise_install/devise_install_generator.rb",
"generators/devise_install/templates/README",
"generators/devise_install/templates/devise.rb",
"generators/devise_views/USAGE",
"generators/devise_views/devise_views_generator.rb",
"init.rb",
"lib/devise.rb",
"lib/devise/controllers/common.rb",
"lib/devise/controllers/helpers.rb",
"lib/devise/controllers/internal_helpers.rb",
"lib/devise/controllers/url_helpers.rb",
"lib/devise/encryptors/authlogic_sha512.rb",
"lib/devise/encryptors/base.rb",
"lib/devise/encryptors/bcrypt.rb",
"lib/devise/encryptors/clearance_sha1.rb",
"lib/devise/encryptors/restful_authentication_sha1.rb",
"lib/devise/encryptors/sha1.rb",
"lib/devise/encryptors/sha512.rb",
"lib/devise/failure_app.rb",
"lib/devise/hooks/activatable.rb",
"lib/devise/hooks/rememberable.rb",
"lib/devise/hooks/timeoutable.rb",
"lib/devise/hooks/trackable.rb",
"lib/devise/locales/en.yml",
"lib/devise/mapping.rb",
"lib/devise/models.rb",
"lib/devise/models/activatable.rb",
"lib/devise/models/authenticatable.rb",
"lib/devise/models/confirmable.rb",
"lib/devise/models/lockable.rb",
"lib/devise/models/recoverable.rb",
"lib/devise/models/rememberable.rb",
"lib/devise/models/timeoutable.rb",
"lib/devise/models/trackable.rb",
"lib/devise/models/validatable.rb",
"lib/devise/orm/active_record.rb",
"lib/devise/orm/data_mapper.rb",
"lib/devise/orm/mongo_mapper.rb",
"lib/devise/rails.rb",
"lib/devise/rails/routes.rb",
"lib/devise/rails/warden_compat.rb",
"lib/devise/schema.rb",
"lib/devise/strategies/authenticatable.rb",
"lib/devise/strategies/base.rb",
"lib/devise/strategies/rememberable.rb",
"lib/devise/test_helpers.rb",
"lib/devise/version.rb"
]
s.homepage = %q{http://github.com/plataformatec/devise}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.5}
s.summary = %q{Flexible authentication solution for Rails with Warden}
s.test_files = [
"test/controllers/helpers_test.rb",
"test/controllers/internal_helpers_test.rb",
"test/controllers/url_helpers_test.rb",
"test/devise_test.rb",
"test/encryptors_test.rb",
"test/failure_app_test.rb",
"test/integration/authenticatable_test.rb",
"test/integration/confirmable_test.rb",
"test/integration/lockable_test.rb",
"test/integration/recoverable_test.rb",
"test/integration/rememberable_test.rb",
"test/integration/timeoutable_test.rb",
"test/integration/trackable_test.rb",
"test/mailers/confirmation_instructions_test.rb",
"test/mailers/reset_password_instructions_test.rb",
"test/mailers/unlock_instructions_test.rb",
"test/mapping_test.rb",
"test/models/authenticatable_test.rb",
"test/models/confirmable_test.rb",
"test/models/lockable_test.rb",
"test/models/recoverable_test.rb",
"test/models/rememberable_test.rb",
"test/models/timeoutable_test.rb",
"test/models/trackable_test.rb",
"test/models/validatable_test.rb",
"test/models_test.rb",
"test/orm/active_record.rb",
"test/orm/mongo_mapper.rb",
"test/rails_app/app/active_record/admin.rb",
"test/rails_app/app/active_record/user.rb",
"test/rails_app/app/controllers/admins_controller.rb",
"test/rails_app/app/controllers/application_controller.rb",
"test/rails_app/app/controllers/home_controller.rb",
"test/rails_app/app/controllers/users_controller.rb",
"test/rails_app/app/helpers/application_helper.rb",
"test/rails_app/app/mongo_mapper/admin.rb",
"test/rails_app/app/mongo_mapper/user.rb",
"test/rails_app/config/boot.rb",
"test/rails_app/config/environment.rb",
"test/rails_app/config/environments/development.rb",
"test/rails_app/config/environments/production.rb",
"test/rails_app/config/environments/test.rb",
"test/rails_app/config/initializers/devise.rb",
"test/rails_app/config/initializers/inflections.rb",
"test/rails_app/config/initializers/new_rails_defaults.rb",
"test/rails_app/config/initializers/session_store.rb",
"test/rails_app/config/routes.rb",
"test/routes_test.rb",
"test/support/assertions_helper.rb",
"test/support/integration_tests_helper.rb",
"test/support/model_tests_helper.rb",
"test/support/test_silencer.rb",
"test/test_helper.rb",
"test/test_helpers_test.rb"
]
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<warden>, ["~> 0.9.0"])
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
end
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
end
end

View File

@@ -53,6 +53,10 @@ Devise.setup do |config|
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
# ==> General configuration
# Load and configure the ORM. Supports :active_record (default), :mongo_mapper
# (requires mongo_ext installed) and :data_mapper (experimental).

View File

@@ -26,22 +26,34 @@ module Devise
autoload :MongoMapper, 'devise/orm/mongo_mapper'
end
ALL = [:authenticatable, :activatable, :confirmable, :recoverable,
:rememberable, :validatable, :trackable, :timeoutable, :lockable]
ALL = []
# Authentication ones first
ALL.push :authenticatable, :token_authenticatable, :rememberable
# Misc after
ALL.push :recoverable, :validatable
# The ones which can sign out after
ALL.push :activatable, :confirmable, :lockable, :timeoutable
# Stats for last, so we make sure the user is really signed in
ALL.push :trackable
# Maps controller names to devise modules
CONTROLLERS = {
:sessions => [:authenticatable],
:sessions => [:authenticatable, :token_authenticatable],
:passwords => [:recoverable],
:confirmations => [:confirmable],
:unlocks => [:lockable]
}
STRATEGIES = [:rememberable, :authenticatable]
STRATEGIES = [:rememberable, :token_authenticatable, :authenticatable]
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
# Maps the messages types that are used in flash message.
FLASH_MESSAGES = [ :unauthenticated, :unconfirmed, :invalid, :timeout, :inactive, :locked ]
FLASH_MESSAGES = [ :unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked ]
# Declare encryptors length which are used in migrations.
ENCRYPTORS_LENGTH = {
@@ -53,8 +65,8 @@ module Devise
:bcrypt => 60
}
# Email regex used to validate email formats. Retrieved from authlogic.
EMAIL_REGEX = /\A[\w\.%\+\-]+@(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2,4}|museum|travel)\z/i
# Email regex used to validate email formats. Adapted from authlogic.
EMAIL_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
# Used to encrypt password. Please generate one with rake secret.
mattr_accessor :pepper
@@ -131,6 +143,10 @@ module Devise
mattr_accessor :mailer_sender
@@mailer_sender
# Authentication token params key name of choice. E.g. /users/sign_in?some_key=...
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
class << self
# Default way to setup Devise. Run script/generate devise_install to create
# a fresh initializer with all configuration values.

View File

@@ -59,7 +59,7 @@ module Devise
# yet, but we still need to store the uri based on scope, so different scopes
# would never use the same uri to redirect.
def store_location!(scope)
session[:"#{scope}.return_to"] ||= request.request_uri if request && request.get?
session[:"#{scope}.return_to"] = request.request_uri if request && request.get?
end
end
end

View File

@@ -8,6 +8,7 @@ en:
unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.'
invalid: 'Invalid email or password.'
invalid_token: 'Invalid authentication token.'
timeout: 'Your session expired, please sign in again to continue.'
inactive: 'Your account was not activated yet.'
passwords:

View File

@@ -36,7 +36,8 @@ module Devise
end
end
# Regenerates password salt and encrypted password each time password is set.
# Regenerates password salt and encrypted password each time password is set,
# and then trigger any "after_changed_password"-callbacks.
def password=(new_password)
@password = new_password
@@ -48,7 +49,13 @@ module Devise
# Verifies whether an incoming_password (ie from sign in) is the user password.
def valid_password?(incoming_password)
password_digest(incoming_password) == encrypted_password
password_digest(incoming_password) == self.encrypted_password
end
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
# is the user authentication token.
def valid_authentication_token?(incoming_auth_token)
incoming_auth_token == self.authentication_token
end
# Checks if a resource is valid upon authentication.
@@ -75,6 +82,9 @@ module Devise
end
module ClassMethods
Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
# Authenticate a user based on configured attribute keys. Returns the
# authenticated user if it's valid or nil. Attributes are by default
# :email and :password, but the latter is always required.
@@ -106,7 +116,6 @@ module Devise
find(:first, :conditions => conditions)
end
Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
end
end
end

View File

@@ -0,0 +1,89 @@
require 'devise/strategies/token_authenticatable'
module Devise
module Models
# Token Authenticatable Module, responsible for generate authentication token and validating
# authenticity of a user while signing in using a authentication token (say follows an URL).
#
# == Configuration:
#
# You can overwrite configuration values by setting in globally in Devise (+Devise.setup+),
# using devise method, or overwriting the respective instance method.
#
# +token_authentication_key+ - Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
#
# == Examples:
#
# User.authenticate_with_token(:auth_token => '123456789') # returns authenticated user or nil
# User.find(1).valid_authentication_token?('rI1t6PKQ8yP7VetgwdybB') # returns true/false
#
module TokenAuthenticatable
def self.included(base)
base.class_eval do
extend ClassMethods
before_save :ensure_authentication_token
end
end
# Generate new authentication token (a.k.a. "single access token").
def reset_authentication_token
self.authentication_token = self.class.authentication_token
end
# Generate new authentication token and save the record.
def reset_authentication_token!
reset_authentication_token
self.save
end
# Generate authentication token unless already exists.
def ensure_authentication_token
self.reset_authentication_token if self.authentication_token.blank?
end
# Generate authentication token unless already exists and save the record.
def ensure_authentication_token!
self.reset_authentication_token! if self.authentication_token.blank?
end
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
# is the user authentication token.
def valid_authentication_token?(incoming_auth_token)
incoming_auth_token.present? && incoming_auth_token == self.authentication_token
end
module ClassMethods
::Devise::Models.config(self, :token_authentication_key)
# Authenticate a user based on authentication token.
def authenticate_with_token(attributes)
token = attributes[self.token_authentication_key]
resource = self.find_for_token_authentication(token)
resource if resource.try(:valid_authentication_token?, token)
end
def authentication_token
::Devise.friendly_token
end
protected
# Find first record based on conditions given (ie by the sign in form).
# Overwrite to add customized conditions, create a join, or maybe use a
# namedscope to filter records while authenticating.
#
# == Example:
#
# def self.find_for_token_authentication(token, conditions = {})
# conditions = {:active => true}
# self.find_by_authentication_token(token, :conditions => conditions)
# end
#
def find_for_token_authentication(token)
self.find(:first, :conditions => { :authentication_token => token})
end
end
end
end
end

View File

@@ -20,7 +20,19 @@ module Devise
klass.send(mod) if klass.respond_to?(mod)
end
end
def find(*args)
options = args.extract_options!
case args.first
when :first
first(options)
when :all
all(options)
else
super
end
end
include Devise::Schema
# Tell how to apply schema methods. This automatically converts DateTime

View File

@@ -17,6 +17,11 @@ module Devise
apply_schema :password_salt, String, :null => null
end
# Creates authentication_token.
def token_authenticatable
apply_schema :authentication_token, String, :limit => 20
end
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
def confirmable
apply_schema :confirmation_token, String, :limit => 20

View File

@@ -0,0 +1,38 @@
require 'devise/strategies/base'
module Devise
module Strategies
# Strategy for signing in a user, based on a authenticatable token.
# Redirects to sign_in page if it's not authenticated.
class TokenAuthenticatable < Base
def valid?
super && authentication_token(scope).present?
end
# Authenticate a user based on authenticatable token params, returning to warden
# success and the authenticated user if everything is okay. Otherwise redirect
# to sign in page.
def authenticate!
if resource = mapping.to.authenticate_with_token(params[scope] || params)
success!(resource)
else
fail!(:invalid_token)
end
end
private
# Detect authentication token in params: scoped or not.
def authentication_token(scope)
if params[scope]
params[scope][mapping.to.token_authentication_key]
else
params[mapping.to.token_authentication_key]
end
end
end
end
end
Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "0.9.1".freeze
VERSION = "0.9.2".freeze
end

View File

@@ -25,7 +25,7 @@ class DeviseTest < ActiveSupport::TestCase
Devise.configure_warden(config)
assert_equal Devise::FailureApp, config.failure_app
assert_equal [:rememberable, :authenticatable], config.default_strategies
assert_equal [:rememberable, :token_authenticatable, :authenticatable], config.default_strategies
assert_equal :user, config.default_scope
assert config.silence_missing_strategies?
end

View File

@@ -154,25 +154,42 @@ class AuthenticationTest < ActionController::IntegrationTest
assert_contain 'You need to sign in or sign up before continuing.'
end
test 'return to default url if no other was requested' do
test 'redirect to default url if no other was configured' do
sign_in_as_user
assert_template 'home/index'
assert_nil session[:return_to]
assert_nil session[:"user.return_to"]
end
test 'return to given url after sign in' do
test 'redirect to requested url after sign in' do
get users_path
assert_redirected_to new_user_session_path(:unauthenticated => true)
assert_equal users_path, session[:"user.return_to"]
follow_redirect!
follow_redirect!
sign_in_as_user :visit => false
assert_template 'users/index'
assert_nil session[:"user.return_to"]
end
test 'return to configured home path after sign in' do
test 'redirect to last requested url overwriting the stored return_to option' do
get expire_user_path(create_user)
assert_redirected_to new_user_session_path(:unauthenticated => true)
assert_equal expire_user_path(create_user), session[:"user.return_to"]
get users_path
assert_redirected_to new_user_session_path(:unauthenticated => true)
assert_equal users_path, session[:"user.return_to"]
follow_redirect!
sign_in_as_user :visit => false
assert_template 'users/index'
assert_nil session[:"user.return_to"]
end
test 'redirect to configured home path for a given scope after sign in' do
sign_in_as_admin
assert_equal "/admin_area/home", @request.path
end

View File

@@ -128,4 +128,14 @@ class PasswordTest < ActionController::IntegrationTest
assert warden.authenticated?(:user)
end
test 'does not sign in user automatically after changing it\'s password if it\'s not active' do
user = create_user(:confirm => false)
request_forgot_password
reset_password :reset_password_token => user.reload.reset_password_token
assert_redirected_to new_user_session_path(:unconfirmed => true)
assert !warden.authenticated?(:user)
end
end

View File

@@ -0,0 +1,55 @@
require 'test/test_helper'
class TokenAuthenticationTest < ActionController::IntegrationTest
test 'sign in user should authenticate with valid authentication token and proper authentication token key' do
swap Devise, :token_authentication_key => :secret_token do
sign_in_as_new_user_with_token(:auth_token_key => :secret_token)
assert_response :success
assert_template 'users/index'
assert_contain 'Welcome'
assert warden.authenticated?(:user)
end
end
test 'user signing in with valid authentication token - but improper authentication token key - return to sign in form with error message' do
swap Devise, :token_authentication_key => :donald_duck_token do
sign_in_as_new_user_with_token(:auth_token_key => :secret_token)
assert_redirected_to new_user_session_path(:unauthenticated => true)
follow_redirect!
assert_contain 'You need to sign in or sign up before continuing'
assert_contain 'Sign in'
assert_not warden.authenticated?(:user)
end
end
test 'user signing in with invalid authentication token should return to sign in form with error message' do
store_translations :en, :devise => {:sessions => {:invalid_token => 'LOL, that was not a single character correct.'}} do
sign_in_as_new_user_with_token(:auth_token => '*** INVALID TOKEN ***')
assert_redirected_to new_user_session_path(:invalid_token => true)
follow_redirect!
assert_response :success
assert_contain 'LOL, that was not a single character correct.'
assert_contain 'Sign in'
assert_not warden.authenticated?(:user)
end
end
private
def sign_in_as_new_user_with_token(options = {}, &block)
options[:auth_token_key] ||= Devise.token_authentication_key
options[:auth_token] ||= VALID_AUTHENTICATION_TOKEN
user = create_user(options)
user.authentication_token = VALID_AUTHENTICATION_TOKEN
user.save
visit users_path(options[:auth_token_key].to_sym => options[:auth_token])
user
end
end

View File

@@ -0,0 +1,51 @@
require 'test/test_helper'
class TokenAuthenticatableTest < ActiveSupport::TestCase
test 'should generate friendly authentication token on create' do
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
user = create_user
assert_present user.authentication_token
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
end
test 'should reset authentication token' do
user = new_user
user.reset_authentication_token
previous_token = user.authentication_token
user.reset_authentication_token
assert_not_equal previous_token, user.authentication_token
end
test 'should ensure authentication token' do
user = new_user
user.ensure_authentication_token
previous_token = user.authentication_token
user.ensure_authentication_token
assert_equal previous_token, user.authentication_token
end
test 'should test for a valid authentication token' do
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
user = create_user
assert user.valid_authentication_token?(VALID_AUTHENTICATION_TOKEN)
assert_not user.valid_authentication_token?(VALID_AUTHENTICATION_TOKEN.reverse)
end
test 'should authenticate a valid user with authentication token and return it' do
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
user = create_user
user.confirm!
authenticated_user = User.authenticate_with_token(:auth_token => user.authentication_token)
assert_equal authenticated_user, user
end
test 'should return nil when authenticating an invalid user by authentication token' do
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
user = create_user
user.confirm!
authenticated_user = User.authenticate_with_token(:auth_token => user.authentication_token.reverse)
assert_nil authenticated_user
end
end

View File

@@ -17,6 +17,7 @@ ActiveRecord::Schema.define(:version => 1) do
t.rememberable
t.trackable
t.lockable
t.token_authenticatable
end
t.timestamps

View File

@@ -1,5 +1,5 @@
class User < ActiveRecord::Base
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable,
:validatable, :timeoutable, :lockable
:validatable, :timeoutable, :lockable, :token_authenticatable
attr_accessible :username, :email, :password, :password_confirmation
end

View File

@@ -2,6 +2,6 @@ class User
include MongoMapper::Document
key :created_at, DateTime
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable,
:validatable, :timeoutable, :lockable
:validatable, :timeoutable, :lockable, :token_authenticatable
# attr_accessible :username, :email, :password, :password_confirmation
end

View File

@@ -0,0 +1,5 @@
class ActiveSupport::TestCase
VALID_AUTHENTICATION_TOKEN = 'AbCdEfGhIjKlMnOpQrSt'.freeze
end