Compare commits

...

31 Commits

Author SHA1 Message Date
José Valim
ce3926fea4 Bump tiny. 2010-03-26 13:04:05 +01:00
José Valim
e2793fc69e sign_in_count shoud default to zero. 2010-03-26 12:57:36 +01:00
Carlos Antonio da Silva
867e896bc8 Merge branch 'v1.0' of github.com:plataformatec/devise into v1.0 2010-03-26 08:45:49 -03:00
José Valim
053c6f1a3a Move password_required? to authenticatable. This allow you to reuse it when building your own validations. 2010-03-26 12:19:15 +01:00
Carlos Antonio da Silva
a73fead23e Merge branch 'v1.0' of github.com:plataformatec/devise into v1.0 2010-03-26 08:19:10 -03:00
Carlos Antonio da Silva
42eb89b909 Use prepend_before_filter in require_no_authentication.
We need to be sure require_no_authentication runs before other user filters that may call some Devise helper (ie current_xxx).
2010-03-26 08:14:58 -03:00
José Valim
913444059c Allow devise to work with association proxies. 2010-03-26 10:26:38 +01:00
Josh Kalderimis
b305b7f357 changed add_module to add modules to the bottom of ALL, also added test to confirm order in ALL is being adhered to
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-26 09:32:25 +01:00
José Valim
06d43525d6 Require no authentication on unlockable. 2010-03-25 16:28:36 -03:00
Josh Kalderimis
6d08646ddc added routes option to add_module so route view helpers are created
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-25 09:05:13 +01:00
José Valim
1bee9fbef9 Clean up lockable and class methods API. 2010-03-10 16:18:28 +01:00
José Valim
5a4b797265 Remove deprecated behavior. 2010-03-04 08:20:51 +01:00
José Valim
d36e1012f8 Release 1.0.4 with a couple bug fixes. 2010-03-03 12:24:29 +01:00
Lucas de Castro
5d187ff278 Fixing session controllers when within namespaces
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-03 12:16:24 +01:00
Cyril Mougel
a0220243c3 fix spec failed with mongo_mapper DEVISE_ORM
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:44:08 +01:00
José Valim
4c10f86e74 Do not forget frozen records.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:35:07 +01:00
Lucas Uyezu
cf66e935a9 SQLite requries a default value when the column is NOT NULL
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:34:47 +01:00
José Valim
fbe485f3df Update warden which fixes a security issue. 2010-02-23 19:52:53 +01:00
José Valim
545462e964 Bump to 1.0.3. 2010-02-23 15:45:07 +01:00
José Valim
42df192df8 Do not remove options from MongoMapper find. 2010-02-23 15:41:52 +01:00
Andre Arko
7f451ed9cc Add rails/init.rb to the gemspec
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 18:06:38 +01:00
Daniel Jagszent
27fe3023ae renamed init.rb -> rails/init.rb. So that rails can find and initalize the GemPlugin even without a config.gem "devise" line in environment.rb (for using with bundler)
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 17:10:03 +01:00
Paul Campbell
41d416a18e add paragraphs to html emails
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 10:18:00 +01:00
José Valim
c36cd84c31 Returns the proper response body based on the rquest for 401. 2010-02-18 19:52:37 +01:00
José Valim
fd96335d05 Autoload Devise::Models. 2010-02-18 07:22:26 +01:00
José Valim
23568bda82 Bump to 1.0.2. 2010-02-17 21:30:54 +01:00
José Valim
ee7f5270fc Uses the same content type as request on http authenticatable 401 responses 2010-02-17 21:25:31 +01:00
José Valim
f294700723 Update test files. 2010-02-17 21:15:11 +01:00
Glenn Roberts
c86ce298dc add content type test, update config doc
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-17 21:13:27 +01:00
Glenn Roberts
b0ff0d46dd add content_type config parameter
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-17 21:13:16 +01:00
José Valim
187ef5c452 Update README. 2010-02-17 13:56:00 +01:00
47 changed files with 280 additions and 195 deletions

View File

@@ -1,3 +1,29 @@
* bug fix
* Use prepend_before_filter in require_no_authentication.
* require_no_authentication on unlockable.
* Fix a bug when giving an association proxy to devise.
* Do not use lock! on lockable since it's part of ActiveRecord API.
== 1.0.4
* bug fix
* Fixed a bug when deleting an account with rememberable
* Fixed a bug with custom controllers
== 1.0.3
* enhancements
* HTML e-mails now have proper formatting
* Do not remove MongoMapper options in find
== 1.0.2
* enhancements
* Allows you set mailer content type (by github.com/glennr)
* bug fix
* Uses the same content type as request on http authenticatable 401 responses
== 1.0.1
* enhancements
@@ -17,6 +43,7 @@
* Added Http Basic Authentication support
* Allow scoped_views to be customized per controller/mailer class
* [#99] Allow authenticatable to used in change_table statements
* Add mailer_content_type configuration parameter (by github.com/glennr)
== 0.9.2

View File

@@ -30,17 +30,13 @@ Devise is based on Warden (http://github.com/hassox/warden), a Rack Authenticati
== Installation
All gems are on gemcutter, so you need to add gemcutter to your sources if you haven't yet:
sudo gem sources -a http://gemcutter.org/
Install warden gem if you don't have it installed (requires 0.6.4 or higher):
Install warden gem if you don't have it installed:
sudo gem install warden
Install devise gem:
sudo gem install devise
sudo gem install devise --version=1.0.1
Configure warden and devise gems inside your app:
@@ -55,6 +51,10 @@ And you're ready to go. The generator will install an initializer which describe
http://rdoc.info/projects/plataformatec/devise
If you want to use Devise with bundler on Rails 2.3, you need to follow the instructions here:
http://github.com/carlhuda/bundler/issues/issue/83
== Basic Usage
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration. You MUST also check out the *Generators* section below to help you start.

View File

@@ -43,8 +43,8 @@ begin
s.homepage = "http://github.com/plataformatec/devise"
s.description = "Flexible authentication solution for Rails with Warden"
s.authors = ['José Valim', 'Carlos Antônio']
s.files = FileList["[A-Z]*", "{app,config,generators,lib}/**/*", "init.rb"]
s.add_dependency("warden", "~> 0.9.0")
s.files = FileList["[A-Z]*", "{app,config,generators,lib}/**/*", "rails/init.rb"]
s.add_dependency("warden", "~> 0.10.2")
end
Jeweler::GemcutterTasks.new

View File

@@ -21,7 +21,7 @@ class ConfirmationsController < ApplicationController
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm!(:confirmation_token => params[:confirmation_token])
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message :notice, :confirmed

View File

@@ -1,8 +1,7 @@
class PasswordsController < ApplicationController
prepend_before_filter :require_no_authentication
include Devise::Controllers::InternalHelpers
before_filter :require_no_authentication
# GET /resource/password/new
def new
build_resource
@@ -30,7 +29,7 @@ class PasswordsController < ApplicationController
# PUT /resource/password
def update
self.resource = resource_class.reset_password!(params[resource_name])
self.resource = resource_class.reset_password_by_token(params[resource_name])
if resource.errors.empty?
set_flash_message :notice, :updated

View File

@@ -1,9 +1,8 @@
class RegistrationsController < ApplicationController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
include Devise::Controllers::InternalHelpers
before_filter :require_no_authentication, :only => [ :new, :create ]
before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
# GET /resource/sign_in
def new
build_resource

View File

@@ -1,8 +1,7 @@
class SessionsController < ApplicationController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
include Devise::Controllers::InternalHelpers
before_filter :require_no_authentication, :only => [ :new, :create ]
# GET /resource/sign_in
def new
unless resource_just_signed_up?
@@ -35,11 +34,11 @@ class SessionsController < ApplicationController
protected
def resource_just_signed_up?
flash[:"#{resource_name}_signed_up"]
end
def resource_just_signed_up?
flash[:"#{resource_name}_signed_up"]
end
def clean_up_passwords(object)
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
end
def clean_up_passwords(object)
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
end
end

View File

@@ -1,4 +1,5 @@
class UnlocksController < ApplicationController
prepend_before_filter :require_no_authentication
include Devise::Controllers::InternalHelpers
# GET /resource/unlock/new
@@ -21,7 +22,7 @@ class UnlocksController < ApplicationController
# GET /resource/unlock?unlock_token=abcdef
def show
self.resource = resource_class.unlock!(:unlock_token => params[:unlock_token])
self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
if resource.errors.empty?
set_flash_message :notice, :unlocked

View File

@@ -20,14 +20,14 @@ class DeviseMailer < ::ActionMailer::Base
# Configure default email options
def setup_mail(record, key)
mapping = Devise::Mapping.find_by_class(record.class)
raise "Invalid devise resource #{record}" unless mapping
scope_name = Devise::Mapping.find_scope!(record)
mapping = Devise.mappings[scope_name]
subject translate(mapping, key)
from mailer_sender(mapping)
recipients record.email
sent_on Time.now
content_type 'text/html'
content_type Devise.mailer_content_type
body render_with_scope(key, mapping, mapping.name => record, :resource => record)
end

View File

@@ -1,5 +1,5 @@
Welcome <%= @resource.email %>!
<p>Welcome <%= @resource.email %>!</p>
You can confirm your account through the link below:
<p>You can confirm your account through the link below:</p>
<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>

View File

@@ -1,8 +1,8 @@
Hello <%= @resource.email %>!
<p>Hello <%= @resource.email %>!</p>
Someone has requested a link to change your password, and you can do this through the link below.
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

View File

@@ -1,7 +1,7 @@
Hello <%= @resource.email %>!
<p>Hello <%= @resource.email %>!</p>
Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
Click the link below to unlock your account:
<p>Click the link below to unlock your account:</p>
<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>

View File

@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{devise}
s.version = "1.0.1"
s.version = "1.0.5"
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-15}
s.date = %q{2010-03-26}
s.description = %q{Flexible authentication solution for Rails with Warden}
s.email = %q{contact@plataformatec.com.br}
s.extra_rdoc_files = [
@@ -50,7 +50,6 @@ Gem::Specification.new do |s|
"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/helpers.rb",
"lib/devise/controllers/internal_helpers.rb",
@@ -95,12 +94,13 @@ Gem::Specification.new do |s|
"lib/devise/strategies/rememberable.rb",
"lib/devise/strategies/token_authenticatable.rb",
"lib/devise/test_helpers.rb",
"lib/devise/version.rb"
"lib/devise/version.rb",
"rails/init.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.rubygems_version = %q{1.3.6}
s.summary = %q{Flexible authentication solution for Rails with Warden}
s.test_files = [
"test/controllers/helpers_test.rb",
@@ -168,12 +168,12 @@ Gem::Specification.new do |s|
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"])
s.add_runtime_dependency(%q<warden>, ["~> 0.10.2"])
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
s.add_dependency(%q<warden>, ["~> 0.10.2"])
end
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
s.add_dependency(%q<warden>, ["~> 0.10.2"])
end
end

View File

@@ -3,6 +3,9 @@
Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me@config-initializers-devise.com"
# Configure the content type of DeviseMailer mails (defaults to text/html")
# config.mailer_content_type = "text/plain"
# ==> Configuration for :authenticatable
# Invoke `rake secret` and use the printed value to setup a pepper to generate

View File

@@ -1,5 +1,6 @@
module Devise
autoload :FailureApp, 'devise/failure_app'
autoload :Models, 'devise/models'
autoload :Schema, 'devise/schema'
autoload :TestHelpers, 'devise/test_helpers'
@@ -146,6 +147,10 @@ module Devise
mattr_accessor :mailer_sender
@@mailer_sender = nil
# Content Type of Devise e-mails.
mattr_accessor :mailer_content_type
@@mailer_content_type = 'text/html'
# Authentication token params key name of choice. E.g. /users/sign_in?some_key=...
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
@@ -213,6 +218,9 @@ module Devise
# Default is +nil+ (i.e. +false+).
# +controller+ - Symbol representing a name of an exisiting or custom *controller* for this module.
# Default is +nil+ (i.e. +false+).
# +route+ - Symbol representing the name of a *route* related to this module which a set of
# route view helpers should be created for.
# Default is +nil+ (i.e. +false+).
#
# == Examples:
#
@@ -221,7 +229,7 @@ module Devise
# Devise.add_module(:party_module, :model => 'party_module/model')
#
def add_module(module_name, options = {})
Devise::ALL.unshift module_name unless Devise::ALL.include?(module_name)
Devise::ALL << module_name unless Devise::ALL.include?(module_name)
Devise::STRATEGIES.unshift module_name if options[:strategy] && !Devise::STRATEGIES.include?(module_name)
if options[:controller]
@@ -230,6 +238,10 @@ module Devise
Devise::CONTROLLERS[controller].unshift module_name unless Devise::CONTROLLERS[controller].include?(module_name)
end
if options[:route]
Devise::ROUTES.unshift options[:route] unless Devise::ROUTES.include?(options[:route])
end
if options[:model]
Devise::Models.module_eval do
autoload :"#{module_name.to_s.classify}", options[:model]

View File

@@ -14,7 +14,7 @@ module Devise
hide_action :resource, :scope_name, :resource_name, :resource_class, :devise_mapping, :devise_controller?
skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
before_filter :is_devise_resource?
prepend_before_filter :is_devise_resource?
end
end

View File

@@ -3,7 +3,7 @@
# that specific user and adds a cookie with this user info to sign in this user
# automatically without asking for credentials. Refer to rememberable strategy
# for more info.
Warden::Manager.after_authentication do |record, warden, options|
Warden::Manager.prepend_after_authentication do |record, warden, options|
scope = options[:scope]
remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
@@ -22,9 +22,11 @@ end
# Before logout hook to forget the user in the given scope, only if rememberable
# is activated for this scope. Also clear remember token to ensure the user
# won't be remembered again.
# Notice that we forget the user if the record is frozen. This usually means the
# user was just deleted.
Warden::Manager.before_logout do |record, warden, scope|
if record.respond_to?(:forget_me!)
record.forget_me!
record.forget_me! unless record.frozen?
warden.response.delete_cookie "remember_#{scope}_token"
end
end

View File

@@ -34,26 +34,19 @@ module Devise
nil
end
# Find a mapping by a given class. It takes into account single table inheritance as well.
def self.find_by_class(klass)
Devise.mappings.each_value do |mapping|
return mapping if klass <= mapping.to
end
nil
end
# Receives an object and find a scope for it. If a scope cannot be found,
# raises an error. If a symbol is given, it's considered to be the scope.
def self.find_scope!(duck)
case duck
when String, Symbol
duck
return duck
when Class
Devise.mappings.each_value { |m| return m.name if duck <= m.to }
else
klass = duck.is_a?(Class) ? duck : duck.class
mapping = Devise::Mapping.find_by_class(klass)
raise "Could not find a valid mapping for #{duck}" unless mapping
mapping.name
Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
end
raise "Could not find a valid mapping for #{duck}"
end
# Default url options which can be used as prefix.

View File

@@ -78,16 +78,11 @@ module Devise
# error on :current_password. It also automatically rejects :password and
# :password_confirmation if they are blank.
def update_with_password(params={})
# TODO Remove me in next release
if params[:old_password].present?
params[:current_password] ||= params[:old_password]
ActiveSupport::Deprecation.warn "old_password is deprecated, please use current_password instead", caller
end
params.delete(:password) if params[:password].blank?
params.delete(:password_confirmation) if params[:password_confirmation].blank?
current_password = params.delete(:current_password)
params.delete(:password) if params[:password].blank?
params.delete(:password_confirmation) if params[:password_confirmation].blank?
result = if valid_password?(current_password)
update_attributes(params)
else
@@ -103,6 +98,13 @@ module Devise
protected
# Checks whether a password is needed or not. For validations only.
# Passwords are always required if it's a new record, or if the password
# or confirmation are being set somewhere.
def password_required?
new_record? || !password.nil? || !password_confirmation.nil?
end
# Digests the password using the configured encryptor.
def password_digest(password)
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)

View File

@@ -63,7 +63,7 @@ module Devise
# Remove confirmation date and send confirmation instructions, to ensure
# after sending these instructions the user won't be able to sign in without
# confirming it's account
def resend_confirmation!
def resend_confirmation_token
unless_confirmed do
generate_confirmation_token
save(false)
@@ -81,11 +81,7 @@ module Devise
# The message to be shown if the account is inactive.
def inactive_message
if !confirmed?
:unconfirmed
else
super
end
!confirmed? ? :unconfirmed : super
end
# If you don't want confirmation to be sent on create, neither a code
@@ -151,7 +147,7 @@ module Devise
# Options must contain the user email
def send_confirmation_instructions(attributes={})
confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
confirmable.resend_confirmation! unless confirmable.new_record?
confirmable.resend_confirmation_token unless confirmable.new_record?
confirmable
end
@@ -159,8 +155,8 @@ module Devise
# If no user is found, returns a new user with an error.
# If the user is already confirmed, create an error for the user
# Options must have the confirmation_token
def confirm!(attributes={})
confirmable = find_or_initialize_with_error_by(:confirmation_token, attributes[:confirmation_token])
def confirm_by_token(confirmation_token)
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
confirmable.confirm! unless confirmable.new_record?
confirmable
end

View File

@@ -27,23 +27,20 @@ module Devise
end
# Lock an user setting it's locked_at to actual time.
def lock
def lock_access!
self.locked_at = Time.now
if unlock_strategy_enabled?(:email)
generate_unlock_token
send_unlock_instructions
end
end
# Lock an user also saving the record.
def lock!
lock
save(false)
end
# Unlock an user by cleaning locket_at and failed_attempts.
def unlock!
if_locked do
def unlock_access!
if_access_locked do
self.locked_at = nil
self.failed_attempts = 0
self.unlock_token = nil
@@ -52,7 +49,7 @@ module Devise
end
# Verifies whether a user is locked or not.
def locked?
def access_locked?
locked_at && !lock_expired?
end
@@ -62,8 +59,8 @@ module Devise
end
# Resend the unlock instructions if the user is locked.
def resend_unlock!
if_locked do
def resend_unlock_token
if_access_locked do
generate_unlock_token unless unlock_token.present?
save(false)
send_unlock_instructions
@@ -73,17 +70,13 @@ module Devise
# Overwrites active? from Devise::Models::Activatable for locking purposes
# by verifying whether an user is active to sign in or not based on locked?
def active?
super && !locked?
super && !access_locked?
end
# Overwrites invalid_message from Devise::Models::Authenticatable to define
# the correct reason for blocking the sign in.
def inactive_message
if locked?
:locked
else
super
end
access_locked? ? :locked : super
end
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
@@ -94,7 +87,10 @@ module Devise
self.failed_attempts = 0
else
self.failed_attempts += 1
lock if failed_attempts > self.class.maximum_attempts
if failed_attempts > self.class.maximum_attempts
lock_access!
return false
end
end
save(false) if changed?
result
@@ -118,8 +114,8 @@ module Devise
# Checks whether the record is locked or not, yielding to the block
# if it's locked, otherwise adds an error to email.
def if_locked
if locked?
def if_access_locked
if access_locked?
yield
else
self.class.add_error_on(self, :email, :not_locked)
@@ -139,7 +135,7 @@ module Devise
# Options must contain the user email
def send_unlock_instructions(attributes={})
lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
lockable.resend_unlock! unless lockable.new_record?
lockable.resend_unlock_token unless lockable.new_record?
lockable
end
@@ -147,9 +143,9 @@ module Devise
# If no user is found, returns a new user with an error.
# If the user is not locked, creates an error for the user
# Options must have the unlock_token
def unlock!(attributes={})
lockable = find_or_initialize_with_error_by(:unlock_token, attributes[:unlock_token])
lockable.unlock! unless lockable.new_record?
def unlock_access_by_token(unlock_token)
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
lockable.unlock_access! unless lockable.new_record?
lockable
end

View File

@@ -69,7 +69,7 @@ module Devise
# try saving the record. If not user is found, returns a new user
# containing an error in reset_password_token attribute.
# Attributes must contain reset_password_token, password and confirmation
def reset_password!(attributes={})
def reset_password_by_token(attributes={})
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) unless recoverable.new_record?
recoverable

View File

@@ -34,15 +34,6 @@ module Devise
"to the following methods: #{unavailable_validations.to_sentence}."
end
end
protected
# Checks whether a password is needed or not. For validations only.
# Passwords are always required if it's a new record, or if the password
# or confirmation are being set somewhere.
def password_required?
new_record? || !password.nil? || !password_confirmation.nil?
end
end
end
end

View File

@@ -22,14 +22,11 @@ module Devise
end
def find(*args)
options = args.extract_options!
case args.first
when :first
first(options)
when :all
all(options)
else
super
when :first, :all
send(args.shift, *args)
else
super
end
end

View File

@@ -9,12 +9,13 @@ module Devise
# * :null - When true, allow columns to be null.
# * :encryptor - The encryptor going to be used, necessary for setting the proper encrypter password length.
def authenticatable(options={})
null = options[:null] || false
encryptor = options[:encryptor] || (respond_to?(:encryptor) ? self.encryptor : :sha1)
null = options[:null] || false
default = options[:default]
encryptor = options[:encryptor] || (respond_to?(:encryptor) ? self.encryptor : :sha1)
apply_schema :email, String, :null => null
apply_schema :encrypted_password, String, :null => null, :limit => Devise::ENCRYPTORS_LENGTH[encryptor]
apply_schema :password_salt, String, :null => null
apply_schema :email, String, :null => null, :default => default
apply_schema :encrypted_password, String, :null => null, :default => default, :limit => Devise::ENCRYPTORS_LENGTH[encryptor]
apply_schema :password_salt, String, :null => null, :default => default
end
# Creates authentication_token.
@@ -43,7 +44,7 @@ module Devise
# Creates sign_in_count, current_sign_in_at, last_sign_in_at,
# current_sign_in_ip, last_sign_in_ip.
def trackable
apply_schema :sign_in_count, Integer
apply_schema :sign_in_count, Integer, :default => 0
apply_schema :current_sign_in_at, DateTime
apply_schema :last_sign_in_at, DateTime
apply_schema :current_sign_in_ip, String
@@ -53,7 +54,7 @@ module Devise
# Creates failed_attempts, unlock_token and locked_at
def lockable
apply_schema :failed_attempts, Integer, :default => 0
apply_schema :unlock_token, String, :limit => 20
apply_schema :unlock_token, String, :limit => 20
apply_schema :locked_at, DateTime
end

View File

@@ -23,7 +23,7 @@ module Devise
protected
def valid_controller?
params[:controller] == 'sessions'
params[:controller] =~ /sessions$/
end
def valid_params?

View File

@@ -14,7 +14,7 @@ module Devise
if resource = mapping.to.authenticate_with_http(username, password)
success!(resource)
else
custom!([401, custom_headers, ["HTTP Basic: Access denied.\n"]])
custom!([401, custom_headers, [response_body]])
end
end
@@ -24,6 +24,12 @@ module Devise
decode_credentials(request).split(/:/, 2)
end
def response_body
body = "HTTP Basic: Access denied."
method = :"to_#{request_format.to_sym}"
{}.respond_to?(method) ? { :error => body }.send(method) : body
end
def http_authentication
request.env['HTTP_AUTHORIZATION'] ||
request.env['X-HTTP_AUTHORIZATION'] ||
@@ -38,10 +44,14 @@ module Devise
def custom_headers
{
"Content-Type" => "text/plain",
"Content-Type" => request_format.to_s,
"WWW-Authenticate" => %(Basic realm="#{Devise.http_authentication_realm.gsub(/"/, "")}")
}
end
def request_format
@request_format ||= Mime::Type.lookup_by_extension(request.template_format.to_s)
end
end
end
end

View File

@@ -24,6 +24,10 @@ module Devise
catch_with_redirect { super }
end
def user(*args)
catch_with_redirect { super }
end
def catch_with_redirect(&block)
result = catch(:warden, &block)

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "1.0.1".freeze
VERSION = "1.0.5".freeze
end

View File

@@ -63,6 +63,11 @@ class DeviseTest < ActiveSupport::TestCase
Devise::ALL.delete(:kivi)
Devise::CONTROLLERS.delete(:fruits)
assert_nothing_raised(Exception) { Devise.add_module(:carrot, :route => :vegetable) }
assert_equal 1, Devise::ROUTES.select { |v| v == :vegetable }.size
Devise::ALL.delete(:carrot)
Devise::ROUTES.delete(:vegetable)
assert_nothing_raised(Exception) { Devise.add_module(:authenticatable_again, :model => 'devise/model/authenticatable') }
assert defined?(Devise::Models::AuthenticatableAgain)
end

View File

@@ -16,6 +16,14 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
end
test 'uses the request format as response content type' do
sign_in_as_new_user_with_http("unknown", "123456", :xml)
assert_equal 401, status
assert_equal "application/xml", headers["Content-Type"]
# Cannot assert this due to a bug between integration tests and rack on 2.3
# assert response.body.include?("<error>HTTP Basic: Access denied.</error>")
end
test 'returns a custom response with www-authenticate and chosen realm' do
swap Devise, :http_authentication_realm => "MyApp" do
sign_in_as_new_user_with_http("unknown")
@@ -36,9 +44,9 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
private
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
def sign_in_as_new_user_with_http(username="user@test.com", password="123456", format=:html)
user = create_user
get users_path, {}, :authorization => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
get users_path(:format => format), {}, :authorization => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
user
end
end

View File

@@ -47,14 +47,14 @@ class LockTest < ActionController::IntegrationTest
test "locked user should be able to unlock account" do
user = create_user(:locked => true)
assert user.locked?
assert user.access_locked?
visit_user_unlock_with_token(user.unlock_token)
assert_template 'home/index'
assert_contain 'Your account was successfully unlocked.'
assert_not user.reload.locked?
assert_not user.reload.access_locked?
end
test "sign in user automatically after unlocking it's account" do

View File

@@ -28,6 +28,14 @@ class RememberMeTest < ActionController::IntegrationTest
assert warden.user(:user) == user
end
test 'does not remember other scopes' do
user = create_user_and_remember
get root_path
assert_response :success
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
test 'do not remember with invalid token' do
user = create_user_and_remember('add')
get users_path

View File

@@ -39,7 +39,7 @@ class TrackableHooksTest < ActionController::IntegrationTest
test "increase sign in count" do
user = create_user
assert_nil user.sign_in_count
assert_equal 0, user.sign_in_count
sign_in_as_user
user.reload

View File

@@ -63,6 +63,12 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
end
end
test 'content type should be set to plain when manually configured' do
swap Devise, :mailer_content_type => "text/plain" do
assert_equal "text/plain", mail.content_type
end
end
test 'renders a scoped if scoped_views is set in the mailer class' do
begin
DeviseMailer.scoped_views = true

View File

@@ -10,7 +10,7 @@ class UnlockInstructionsTest < ActionMailer::TestCase
def user
@user ||= begin
user = create_user
user.lock!
user.lock_access!
user
end
end

View File

@@ -39,22 +39,17 @@ class MappingTest < ActiveSupport::TestCase
assert_equal Devise.mappings[:admin], Devise::Mapping.find_by_path("/admin_area/session")
end
test 'find mapping by class' do
assert_nil Devise::Mapping.find_by_class(String)
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_class(User)
end
test 'find mapping by class works with single table inheritance' do
klass = Class.new(User)
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_class(klass)
end
test 'find scope for a given object' do
assert_equal :user, Devise::Mapping.find_scope!(User)
assert_equal :user, Devise::Mapping.find_scope!(:user)
assert_equal :user, Devise::Mapping.find_scope!(User.new)
end
test 'find scope works with single table inheritance' do
assert_equal :user, Devise::Mapping.find_scope!(Class.new(User))
assert_equal :user, Devise::Mapping.find_scope!(Class.new(User).new)
end
test 'find scope raises an error if cannot be found' do
assert_raise RuntimeError do
Devise::Mapping.find_scope!(String)

View File

@@ -15,7 +15,7 @@ class ConfirmableTest < ActiveSupport::TestCase
user = create_user
3.times do
token = user.confirmation_token
user.resend_confirmation!
user.resend_confirmation_token
assert_not_equal token, user.confirmation_token
end
end
@@ -62,19 +62,19 @@ class ConfirmableTest < ActiveSupport::TestCase
test 'should find and confirm an user automatically' do
user = create_user
confirmed_user = User.confirm!(:confirmation_token => user.confirmation_token)
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert_equal confirmed_user, user
assert user.reload.confirmed?
end
test 'should return a new record with errors when a invalid token is given' do
confirmed_user = User.confirm!(:confirmation_token => 'invalid_confirmation_token')
confirmed_user = User.confirm_by_token('invalid_confirmation_token')
assert confirmed_user.new_record?
assert_match /invalid/, confirmed_user.errors[:confirmation_token]
end
test 'should return a new record with errors when a blank token is given' do
confirmed_user = User.confirm!(:confirmation_token => '')
confirmed_user = User.confirm_by_token('')
assert confirmed_user.new_record?
assert_match /blank/, confirmed_user.errors[:confirmation_token]
end
@@ -83,7 +83,7 @@ class ConfirmableTest < ActiveSupport::TestCase
user = create_user
user.confirmed_at = Time.now
user.save
confirmed_user = User.confirm!(:confirmation_token => user.confirmation_token)
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert confirmed_user.confirmed?
assert confirmed_user.errors[:email]
end
@@ -173,7 +173,7 @@ class ConfirmableTest < ActiveSupport::TestCase
test 'should not be able to send instructions if the user is already confirmed' do
user = create_user
user.confirm!
assert_not user.resend_confirmation!
assert_not user.resend_confirmation_token
assert user.confirmed?
assert_equal 'already confirmed', user.errors[:email]
end
@@ -216,7 +216,7 @@ class ConfirmableTest < ActiveSupport::TestCase
Devise.confirm_within = 0.days
user = create_user
user.confirmation_sent_at = Date.today
assert_not user.active?
assert_not user.reload.active?
end
test 'should not be active without confirmation' do

View File

@@ -17,14 +17,14 @@ class LockableTest < ActiveSupport::TestCase
user = create_user
attempts = Devise.maximum_attempts + 1
attempts.times { authenticated_user = User.authenticate(:email => user.email, :password => "anotherpassword") }
assert user.reload.locked?
assert user.reload.access_locked?
end
test "should respect maximum attempts configuration" do
user = create_user
swap Devise, :maximum_attempts => 2 do
3.times { authenticated_user = User.authenticate(:email => user.email, :password => "anotherpassword") }
assert user.reload.locked?
assert user.reload.access_locked?
end
end
@@ -38,25 +38,26 @@ class LockableTest < ActiveSupport::TestCase
test "should verify wheter a user is locked or not" do
user = create_user
assert_not user.locked?
user.lock!
assert user.locked?
assert_not user.access_locked?
user.lock_access!
assert user.access_locked?
end
test "active? should be the opposite of locked?" do
user = create_user
user.confirm!
assert user.active?
user.lock!
user.lock_access!
assert_not user.active?
end
test "should unlock an user by cleaning locked_at, falied_attempts and unlock_token" do
user = create_user
user.lock!
user.lock_access!
assert_not_nil user.reload.locked_at
assert_not_nil user.reload.unlock_token
user.unlock!
user.unlock_access!
assert_nil user.reload.locked_at
assert_nil user.reload.unlock_token
assert 0, user.reload.failed_attempts
@@ -64,12 +65,13 @@ class LockableTest < ActiveSupport::TestCase
test 'should not unlock an unlocked user' do
user = create_user
assert_not user.unlock!
assert_not user.unlock_access!
assert_match /not locked/, user.errors[:email]
end
test "new user should not be locked and should have zero failed_attempts" do
assert_not new_user.locked?
assert_not new_user.access_locked?
assert_equal 0, create_user.failed_attempts
end
@@ -77,10 +79,10 @@ class LockableTest < ActiveSupport::TestCase
swap Devise, :unlock_in => 3.hours do
user = new_user
user.locked_at = 2.hours.ago
assert user.locked?
assert user.access_locked?
Devise.unlock_in = 1.hour
assert_not user.locked?
assert_not user.access_locked?
end
end
@@ -88,14 +90,14 @@ class LockableTest < ActiveSupport::TestCase
swap Devise, :unlock_strategy => :email do
user = new_user
user.locked_at = 2.hours.ago
assert user.locked?
assert user.access_locked?
end
end
test "should set unlock_token when locking" do
user = create_user
assert_nil user.unlock_token
user.lock!
user.lock_access!
assert_not_nil user.unlock_token
end
@@ -104,7 +106,7 @@ class LockableTest < ActiveSupport::TestCase
user.lock!
3.times do
token = user.unlock_token
user.resend_unlock!
user.resend_unlock_token
assert_equal token, user.unlock_token
end
end
@@ -113,7 +115,7 @@ class LockableTest < ActiveSupport::TestCase
unlock_tokens = []
3.times do
user = create_user
user.lock!
user.lock_access!
token = user.unlock_token
assert !unlock_tokens.include?(token)
unlock_tokens << token
@@ -123,7 +125,7 @@ class LockableTest < ActiveSupport::TestCase
test "should not generate unlock_token when :email is not an unlock strategy" do
swap Devise, :unlock_strategy => :time do
user = create_user
user.lock!
user.lock_access!
assert_nil user.unlock_token
end
end
@@ -132,7 +134,7 @@ class LockableTest < ActiveSupport::TestCase
swap Devise, :unlock_strategy => :email do
user = create_user
assert_email_sent do
user.lock!
user.lock_access!
end
end
end
@@ -141,42 +143,42 @@ class LockableTest < ActiveSupport::TestCase
swap Devise, :unlock_strategy => :time do
user = create_user
assert_email_not_sent do
user.lock!
user.lock_access!
end
end
end
test 'should find and unlock an user automatically' do
user = create_user
user.lock!
locked_user = User.unlock!(:unlock_token => user.unlock_token)
user.lock_access!
locked_user = User.unlock_access_by_token(user.unlock_token)
assert_equal locked_user, user
assert_not user.reload.locked?
assert_not user.reload.access_locked?
end
test 'should return a new record with errors when a invalid token is given' do
locked_user = User.unlock!(:unlock_token => 'invalid_token')
locked_user = User.unlock_access_by_token('invalid_token')
assert locked_user.new_record?
assert_match /invalid/, locked_user.errors[:unlock_token]
end
test 'should return a new record with errors when a blank token is given' do
locked_user = User.unlock!(:unlock_token => '')
locked_user = User.unlock_access_by_token('')
assert locked_user.new_record?
assert_match /blank/, locked_user.errors[:unlock_token]
end
test 'should authenticate a unlocked user' do
user = create_user
user.lock!
user.unlock!
user.lock_access!
user.unlock_access!
authenticated_user = User.authenticate(:email => user.email, :password => user.password)
assert_equal authenticated_user, user
end
test 'should find a user to send unlock instructions' do
user = create_user
user.lock!
user.lock_access!
unlock_user = User.send_unlock_instructions(:email => user.email)
assert_equal unlock_user, user
end
@@ -194,8 +196,8 @@ class LockableTest < ActiveSupport::TestCase
test 'should not be able to send instructions if the user is not locked' do
user = create_user
assert_not user.resend_unlock!
assert_not user.locked?
assert_not user.resend_unlock_token
assert_not user.access_locked?
assert_equal 'not locked', user.errors[:email]
end

View File

@@ -104,18 +104,18 @@ class RecoverableTest < ActiveSupport::TestCase
user = create_user
user.send :generate_reset_password_token!
reset_password_user = User.reset_password!(:reset_password_token => user.reset_password_token)
reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token)
assert_equal reset_password_user, user
end
test 'should a new record with errors if no reset_password_token is found' do
reset_password_user = User.reset_password!(:reset_password_token => 'invalid_token')
reset_password_user = User.reset_password_by_token(:reset_password_token => 'invalid_token')
assert reset_password_user.new_record?
assert_match /invalid/, reset_password_user.errors[:reset_password_token]
end
test 'should a new record with errors if reset_password_token is blank' do
reset_password_user = User.reset_password!(:reset_password_token => '')
reset_password_user = User.reset_password_by_token(:reset_password_token => '')
assert reset_password_user.new_record?
assert_match /blank/, reset_password_user.errors[:reset_password_token]
end
@@ -125,7 +125,7 @@ class RecoverableTest < ActiveSupport::TestCase
old_password = user.password
user.send :generate_reset_password_token!
reset_password_user = User.reset_password!(
reset_password_user = User.reset_password_by_token(
:reset_password_token => user.reset_password_token,
:password => 'new_password',
:password_confirmation => 'new_password'

View File

@@ -26,6 +26,20 @@ class ActiveRecordTest < ActiveSupport::TestCase
assert_include_modules Admin, :authenticatable, :registerable, :timeoutable
end
test 'order of module inclusion' do
correct_module_order = [:authenticatable, :registerable, :timeoutable]
incorrect_module_order = [:authenticatable, :timeoutable, :registerable]
assert_include_modules Admin, *incorrect_module_order
# get module constants from symbol list
module_constants = correct_module_order.collect { |mod| Devise::Models::const_get(mod.to_s.classify) }
# confirm that they adhere to the order in ALL
# get included modules, filter out the noise, and reverse the order
assert_equal module_constants, (Admin.included_modules & module_constants).reverse
end
test 'set a default value for stretches' do
assert_equal 15, Configurable.stretches
end

View File

@@ -7,4 +7,6 @@ class ApplicationController < ActionController::Base
# Scrub sensitive parameters from your log
filter_parameter_logging :password
before_filter :current_user
end

View File

@@ -1,9 +1,13 @@
class Admin
include MongoMapper::Document
devise :authenticatable, :timeoutable
devise :authenticatable, :registerable, :timeoutable
def self.find_for_authentication(conditions)
last(:conditions => conditions, :order => "email")
last(:conditions => conditions)
end
def self.last(options={})
options.merge!(:order => 'email')
super options
end
end

View File

@@ -1,8 +1,14 @@
class User
include MongoMapper::Document
key :created_at, DateTime
devise :authenticatable, :http_authenticatable, :confirmable, :recoverable,
:rememberable, :trackable, :validatable, :timeoutable, :lockable,
:token_authenticatable
devise :authenticatable, :http_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable
# attr_accessible :username, :email, :password, :password_confirmation
def self.last(options={})
options.merge!(:order => 'email')
super options
end
end

View File

@@ -35,6 +35,9 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me-omg@yourapp.com"
# Configure the content type of DeviseMailer mails (defaults to text/html")
# config.mailer_content_type = "text/plain"
# Load and configure the ORM. Supports :active_record, :data_mapper and :mongo_mapper.
require "devise/orm/#{DEVISE_ORM}"

View File

@@ -14,7 +14,7 @@ class ActionController::IntegrationTest
:created_at => Time.now.utc
)
user.confirm! unless options[:confirm] == false
user.lock! if options[:locked] == true
user.lock_access! if options[:locked] == true
user
end
end