Compare commits

..

3 Commits

Author SHA1 Message Date
José Valim
6b95b96547 Release v3.0.2 2013-08-09 10:24:23 +02:00
José Valim
df8e6cf225 Skip storage for cookies on unverified requests 2013-08-08 23:32:18 +02:00
José Valim
cf87cd0742 Update OTHER lock 2013-08-08 23:32:09 +02:00
58 changed files with 548 additions and 659 deletions

View File

@@ -1,39 +1,3 @@
== 3.1.2
Security announcement: http://blog.plataformatec.com.br/2013/11/e-mail-enumeration-in-devise-in-paranoid-mode
* bug fix
* Avoid e-mail enumeration on sign in when in paranoid mode
== 3.1.1
* bug fix
* Improve default message which asked users to sign in even when they were already signed (by @gregates)
* Improve error message for when the `config.secret_key` is missing
== 3.1.0
Security announcement: http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/
* backwards incompatible changes
* Do not store confirmation, unlock and reset password tokens directly in the database. This means tokens previously stored in the database are no longer valid. You can reenable this temporarily by setting `config.allow_insecure_tokens_lookup = true` in your configuration file. It is recommended to keep this configuration set to true just temporarily in your production servers only to aid migration
* The Devise mailer and its views were changed to explicitly receive a token argument as `@token`. You will need to update your mailers and re-copy the views to your application with `rails g devise:views`
* Sanitization of parameters should be done by calling `devise_parameter_sanitizer.sanitize(:action)` instead of `devise_parameter_sanitizer.for(:action)`
* deprecations
* Token authentication is deprecated
* enhancements
* Better security defaults
* Allow easier customization of parameter sanitizer (by @alexpeattie)
* bug fix
* Do not confirm e-mail after password reset (by @moll)
* Do not sign in after confirmation
* Do not store confirmation, unlock and reset password tokens directly in the database
* Do not compare directly against confirmation, unlock and reset password tokens
* Skip storage for cookies on unverified requests
== 3.0.2
* bug fix
@@ -55,14 +19,11 @@ Security announcement: http://blog.plataformatec.com.br/2013/08/csrf-token-fixat
* enhancements
* Rails 4 and Strong Parameters compatibility (by @carlosantoniodasilva, @josevalim, @latortuga, @lucasmazza, @nashby, @rafaelfranca, @spastorino)
* Drop support for Rails < 3.2 and Ruby < 1.9.3
* Enable to skip sending reconfirmation email when reconfirmable is on and `skip_confirmation_notification!` is invoked (by @tkhr)
* Enable to skip sending reconfirmation email when reconfirmable is on and skip_confirmation_notification! is invoked (by @tkhr)
* bug fix
* Errors on unlock are now properly reflected on the first `unlock_keys`
* backwards incompatible changes
* Changes on session storage will expire all existing sessions on upgrade
== 2.2.4
* enhancements
@@ -679,7 +640,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Added Registerable
* Added Http Basic Authentication support
* Allow scoped_views to be customized per controller/mailer class
* Allow authenticatable to used in change_table statements
* [#99] Allow authenticatable to used in change_table statements
== 0.9.2
@@ -819,19 +780,19 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Added DataMapper support
* Remove store_location from authenticatable strategy and add it to failure app
* Allow a strategy to be placed after authenticatable
* Do not rely attribute? methods, since they are not added on Datamapper
* [#45] Do not rely attribute? methods, since they are not added on Datamapper
== 0.5.6
* enhancements
* Do not send nil to build (DataMapper compatibility)
* Allow to have scoped views
* [#42] Do not send nil to build (DataMapper compatibility)
* [#44] Allow to have scoped views
== 0.5.5
* enhancements
* Allow overwriting find for authentication method
* Remove Ruby 1.8.7 dependency
* [#38] Remove Ruby 1.8.7 dependency
== 0.5.4
@@ -839,7 +800,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Deprecate :singular in devise_for and use :scope instead
* enhancements
* Create after_sign_in_path_for and after_sign_out_path_for hooks to be
* [#37] Create after_sign_in_path_for and after_sign_out_path_for hooks to be
overwriten in ApplicationController
* Create sign_in_and_redirect and sign_out_and_redirect helpers
* Warden::Manager.default_scope is automatically configured to the first given scope
@@ -851,7 +812,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Ensure all controllers are unloadable
* enhancements
* Moved friendly_token to Devise
* [#35] Moved friendly_token to Devise
* Added Devise.all, so you can freeze your app strategies
* Added Devise.apply_schema, so you can turn it to false in Datamapper or MongoMapper
in cases you don't want it be handlded automatically
@@ -859,9 +820,9 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
== 0.5.2
* enhancements
* Improved sign_in and sign_out helpers to accepts resources
* Added stored_location_for as a helper
* Added test helpers
* [#28] Improved sign_in and sign_out helpers to accepts resources
* [#28] Added stored_location_for as a helper
* [#20] Added test helpers
== 0.5.1
@@ -882,7 +843,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
== 0.4.3
* bug fix
* Authentication just fails if user cannot be serialized from session, without raising errors;
* [#29] Authentication just fails if user cannot be serialized from session, without raising errors;
* Default configuration values should not overwrite user values;
== 0.4.2
@@ -900,7 +861,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
== 0.4.1
* bug fix
* Ensure options can be set even if models were not loaded
* [#21] Ensure options can be set even if models were not loaded
== 0.4.0
@@ -911,25 +872,25 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* :authenticable calls are deprecated, use :authenticatable instead
* enhancements
* Allow devise to be more agnostic and do not require ActiveRecord to be loaded
* [#16] Allow devise to be more agnostic and do not require ActiveRecord to be loaded
* Allow Warden::Manager to be configured through Devise
* Created a generator which creates an initializer
== 0.3.0
* bug fix
* Allow yml messages to be configured by not using engine locales
* [#15] Allow yml messages to be configured by not using engine locales
* deprecations
* Renamed confirm_in to confirm_within
* Do not send confirmation messages when user changes his e-mail
* Renamed authenticable to authenticatable and added deprecation warnings
* [#14] Do not send confirmation messages when user changes his e-mail
* [#13] Renamed authenticable to authenticatable and added deprecation warnings
== 0.2.3
* enhancements
* Ensure fail! works inside strategies
* Make unauthenticated message (when you haven't signed in) different from invalid message
* [#12] Make unauthenticated message (when you haven't signed in) different from invalid message
* bug fix
* Do not redirect on invalid authenticate
@@ -938,7 +899,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
== 0.2.2
* bug fix
* Fix a bug when using customized resources
* [#9] Fix a bug when using customized resources
== 0.2.1
@@ -946,17 +907,17 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Clean devise_views generator to use devise existing views
* enhancements
* Create instance variables (like @user) for each devise controller
* [#7] Create instance variables (like @user) for each devise controller
* Use Devise::Controller::Helpers only internally
* bug fix
* Fix a bug with Mongrel and Ruby 1.8.6
* [#6] Fix a bug with Mongrel and Ruby 1.8.6
== 0.2.0
* enhancements
* Allow option :null => true in authenticable migration
* Remove attr_accessible calls from devise modules
* [#4] Allow option :null => true in authenticable migration
* [#3] Remove attr_accessible calls from devise modules
* Customizable time frame for rememberable with :remember_for config
* Customizable time frame for confirmable with :confirm_in config
* Generators for creating a resource and copy views
@@ -965,12 +926,12 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Do not load hooks or strategies if they are not used
* bug fixes
* Fixed requiring devise strategies
* [#2] Fixed requiring devise strategies
== 0.1.1
* bug fixes
* Fixed requiring devise mapping
* [#1] Fixed requiring devise mapping
== 0.1.0

View File

@@ -1,22 +1,21 @@
GIT
remote: git://github.com/mongoid/mongoid.git
revision: 346a79a7d01aa194de80e649916239a18d38ce13
revision: fe7f43430580860db6d1d89cea27eda24ab60ab1
branch: master
specs:
mongoid (4.0.0)
activemodel (~> 4.0.0)
moped (~> 1.5)
activemodel (~> 4.0.0.rc1)
moped (~> 1.4.2)
origin (~> 1.0)
tzinfo (~> 0.3.22)
PATH
remote: .
specs:
devise (3.1.2)
devise (3.0.2)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
GEM
@@ -47,17 +46,17 @@ GEM
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
arel (4.0.0)
atomic (1.1.12)
bcrypt-ruby (3.1.2)
atomic (1.1.10)
bcrypt-ruby (3.1.1)
builder (3.1.4)
erubis (2.7.0)
faraday (0.8.8)
multipart-post (~> 1.2.0)
faraday (0.8.7)
multipart-post (~> 1.1)
hashie (1.2.0)
hike (1.2.3)
httpauth (0.2.0)
i18n (0.6.5)
json (1.8.0)
i18n (0.6.4)
json (1.7.7)
jwt (0.1.8)
multi_json (>= 1.5)
mail (2.5.4)
@@ -68,8 +67,8 @@ GEM
minitest (4.7.5)
mocha (0.13.3)
metaclass (~> 0.0.1)
moped (1.5.1)
multi_json (1.7.9)
moped (1.4.5)
multi_json (1.7.7)
multipart-post (1.2.0)
nokogiri (1.5.9)
oauth2 (0.8.1)
@@ -126,7 +125,7 @@ GEM
sprockets (~> 2.8)
sqlite3 (1.3.7)
thor (0.18.1)
thread_safe (0.1.2)
thread_safe (0.1.0)
atomic
tilt (1.4.1)
treetop (1.4.14)

View File

@@ -2,6 +2,7 @@
By [Plataformatec](http://plataformatec.com.br/).
[![Gem Version](https://fury-badge.herokuapp.com/rb/devise.png)](http://badge.fury.io/rb/devise)
[![Build Status](https://api.travis-ci.org/plataformatec/devise.png?branch=master)](http://travis-ci.org/plataformatec/devise)
[![Code Climate](https://codeclimate.com/github/plataformatec/devise.png)](https://codeclimate.com/github/plataformatec/devise)
@@ -14,9 +15,10 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
* Allows you to have multiple models signed in at the same time;
* Is based on a modularity concept: use just what you really need.
It's composed of 10 modules:
It's composed of 11 modules:
* [Database Authenticatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/DatabaseAuthenticatable): encrypts and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
* [Token Authenticatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/TokenAuthenticatable): signs in a user based on an authentication token (also known as "single access token"). The token can be given both through query string or HTTP Basic Authentication.
* [Omniauthable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Omniauthable): adds Omniauth (https://github.com/intridea/omniauth) support;
* [Confirmable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
* [Recoverable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Recoverable): resets the user password and sends reset instructions.
@@ -186,7 +188,7 @@ There are just three actions in Devise that allows any set of parameters to be p
* `sign_up` (`Devise::RegistrationsController#create`) - Permits authentication keys plus `password` and `password_confirmation`
* `account_update` (`Devise::RegistrationsController#update`) - Permits authentication keys plus `password`, `password_confirmation` and `current_password`
In case you want to permit additional parameters (the lazy way™) you can do with a simple before filter in your `ApplicationController`:
In case you want to customize the permitted parameters (the lazy way™) you can do with a simple before filter in your `ApplicationController`:
```ruby
class ApplicationController < ActionController::Base
@@ -195,19 +197,11 @@ class ApplicationController < ActionController::Base
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
end
end
```
To completely change Devise defaults or invoke custom behaviour, you can also pass a block:
```ruby
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
end
```
If you have multiple Devise models, you may want to set up different parameter sanitizer per model. In this case, we recommend inheriting from `Devise::ParameterSanitizer` and add your own logic:
```ruby
@@ -258,7 +252,7 @@ rails generate devise:views users
If the customization at the views level is not enough, you can customize each controller by following these steps:
1. Create your custom controller, for example a `Admins::SessionsController`:
1. Create your custom controller, for example a `Admins::SessionsController`:
```ruby
class Admins::SessionsController < Devise::SessionsController
@@ -447,6 +441,12 @@ We have a long list of valued contributors. Check them all at:
https://github.com/plataformatec/devise/contributors
### Maintainers
* José Valim (https://github.com/josevalim)
* Carlos Antônio da Silva (https://github.com/carlosantoniodasilva)
* Rodrigo Flores (https://github.com/rodrigoflores)
## License
MIT License. Copyright 2009-2013 Plataformatec. http://plataformatec.com.br

View File

@@ -20,12 +20,8 @@ class Devise::ConfirmationsController < DeviseController
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
if Devise.allow_insecure_sign_in_after_confirmation
set_flash_message(:notice, :confirmed_and_signed_in) if is_navigational_format?
sign_in(resource_name, resource)
else
set_flash_message(:notice, :confirmed) if is_navigational_format?
end
set_flash_message(:notice, :confirmed) if is_navigational_format?
sign_in(resource_name, resource)
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
@@ -41,12 +37,6 @@ class Devise::ConfirmationsController < DeviseController
# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
if Devise.allow_insecure_sign_in_after_confirmation
after_sign_in_path_for(resource)
elsif signed_in?
signed_in_root_path(resource)
else
new_session_path(resource_name)
end
after_sign_in_path_for(resource)
end
end

View File

@@ -40,7 +40,7 @@ class Devise::RegistrationsController < DeviseController
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
if update_resource(resource, account_update_params)
if resource.update_with_password(account_update_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
:update_needs_confirmation : :updated
@@ -80,12 +80,6 @@ class Devise::RegistrationsController < DeviseController
previous != resource.unconfirmed_email
end
# By default we want to require a password checks on update.
# You can overwrite this method in your own RegistrationsController.
def update_resource(resource, params)
resource.update_with_password(params)
end
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
@@ -123,10 +117,10 @@ class Devise::RegistrationsController < DeviseController
end
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
devise_parameter_sanitizer.for(:sign_up)
end
def account_update_params
devise_parameter_sanitizer.sanitize(:account_update)
devise_parameter_sanitizer.for(:account_update)
end
end

View File

@@ -35,7 +35,7 @@ class Devise::SessionsController < DeviseController
protected
def sign_in_params
devise_parameter_sanitizer.sanitize(:sign_in)
devise_parameter_sanitizer.for(:sign_in)
end
def serialize_options(resource)

View File

@@ -1,18 +1,15 @@
class Devise::Mailer < Devise.parent_mailer.constantize
include Devise::Mailers::Helpers
def confirmation_instructions(record, token, opts={})
@token = token
def confirmation_instructions(record, opts={})
devise_mail(record, :confirmation_instructions, opts)
end
def reset_password_instructions(record, token, opts={})
@token = token
def reset_password_instructions(record, opts={})
devise_mail(record, :reset_password_instructions, opts)
end
def unlock_instructions(record, token, opts={})
@token = token
def unlock_instructions(record, opts={})
devise_mail(record, :unlock_instructions, opts)
end
end

View File

@@ -0,0 +1,3 @@
<% ActiveSupport::Deprecation.warn "Rendering partials devise/_links.erb is deprecated" \
"please use devise/shared/_links.erb instead."%>
<%= render "shared/links" %>

View File

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

View File

@@ -2,7 +2,7 @@
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
<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

@@ -4,4 +4,4 @@
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token) %></p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>

View File

@@ -6,7 +6,7 @@
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end -%>
@@ -22,4 +22,4 @@
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
<% end -%>
<% end -%>
<% end -%>

View File

@@ -3,18 +3,17 @@
en:
devise:
confirmations:
confirmed: "Your account was successfully confirmed."
confirmed_and_signed_in: "Your account was successfully confirmed. You are now signed in."
confirmed: "Your account was successfully confirmed. You are now signed in."
send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes."
failure:
already_authenticated: "You are already signed in."
inactive: "Your account is not activated yet."
inactive: "Your account was not activated yet."
invalid: "Invalid email or password."
invalid_token: "Invalid authentication token."
locked: "Your account is locked."
not_found_in_database: "Invalid email or password."
timeout: "Your session expired. Please sign in again to continue."
timeout: "Your session expired, please sign in again to continue."
unauthenticated: "You need to sign in or sign up before continuing."
unconfirmed: "You have to confirm your account before continuing."
mailer:

View File

@@ -22,6 +22,5 @@ Gem::Specification.new do |s|
s.add_dependency("warden", "~> 1.2.3")
s.add_dependency("orm_adapter", "~> 0.1")
s.add_dependency("bcrypt-ruby", "~> 3.0")
s.add_dependency("thread_safe", "~> 0.1")
s.add_dependency("railties", ">= 3.2.6", "< 5")
end

View File

@@ -1,22 +1,21 @@
PATH
remote: ..
specs:
devise (3.1.2)
devise (3.0.2)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
GEM
remote: https://rubygems.org/
specs:
actionmailer (3.2.14)
actionpack (= 3.2.14)
mail (~> 2.5.4)
actionpack (3.2.14)
activemodel (= 3.2.14)
activesupport (= 3.2.14)
actionmailer (3.2.13)
actionpack (= 3.2.13)
mail (~> 2.5.3)
actionpack (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
@@ -24,49 +23,49 @@ GEM
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.14)
activesupport (= 3.2.14)
activemodel (3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
activerecord (3.2.14)
activemodel (= 3.2.14)
activesupport (= 3.2.14)
activerecord (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.14)
activemodel (= 3.2.14)
activesupport (= 3.2.14)
activesupport (3.2.14)
i18n (~> 0.6, >= 0.6.4)
activeresource (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
activesupport (3.2.13)
i18n (= 0.6.1)
multi_json (~> 1.0)
arel (3.0.2)
atomic (1.1.14)
bcrypt-ruby (3.1.2)
bcrypt-ruby (3.1.1)
builder (3.0.4)
erubis (2.7.0)
faraday (0.8.8)
multipart-post (~> 1.2.0)
faraday (0.8.7)
multipart-post (~> 1.1)
hashie (1.2.0)
hike (1.2.3)
hike (1.2.2)
httpauth (0.2.0)
i18n (0.6.5)
i18n (0.6.1)
journey (1.0.4)
json (1.8.0)
json (1.7.7)
jwt (0.1.8)
multi_json (>= 1.5)
mail (2.5.4)
mail (2.5.3)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metaclass (0.0.1)
mime-types (1.23)
mocha (0.13.3)
metaclass (~> 0.0.1)
mongoid (3.1.4)
mongoid (3.1.3)
activemodel (~> 3.2)
moped (~> 1.4)
moped (~> 1.4.2)
origin (~> 1.0)
tzinfo (~> 0.3.22)
moped (1.5.1)
multi_json (1.7.9)
moped (1.4.5)
multi_json (1.7.3)
multipart-post (1.2.0)
nokogiri (1.5.9)
oauth2 (0.8.1)
@@ -99,22 +98,22 @@ GEM
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (3.2.14)
actionmailer (= 3.2.14)
actionpack (= 3.2.14)
activerecord (= 3.2.14)
activeresource (= 3.2.14)
activesupport (= 3.2.14)
rails (3.2.13)
actionmailer (= 3.2.13)
actionpack (= 3.2.13)
activerecord (= 3.2.13)
activeresource (= 3.2.13)
activesupport (= 3.2.13)
bundler (~> 1.0)
railties (= 3.2.14)
railties (3.2.14)
actionpack (= 3.2.14)
activesupport (= 3.2.14)
railties (= 3.2.13)
railties (3.2.13)
actionpack (= 3.2.13)
activesupport (= 3.2.13)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.1.0)
rake (10.0.4)
rdoc (3.12.2)
json (~> 1.4)
ruby-openid (2.2.3)
@@ -125,10 +124,8 @@ GEM
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.7)
thor (0.18.1)
thread_safe (0.1.3)
atomic
tilt (1.4.1)
treetop (1.4.14)
tilt (1.4.0)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.37)

View File

@@ -14,7 +14,6 @@ module Devise
autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
autoload :TestHelpers, 'devise/test_helpers'
autoload :TimeInflector, 'devise/time_inflector'
autoload :TokenGenerator, 'devise/token_generator'
module Controllers
autoload :Helpers, 'devise/controllers/helpers'
@@ -46,20 +45,6 @@ module Devise
# True values used to check params
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
# Secret key used by the key generator
mattr_accessor :secret_key
@@secret_key = nil
# Allow insecure token lookup. Must be used
# temporarily just for migration.
mattr_accessor :allow_insecure_token_lookup
@@allow_insecure_tokens_lookup = false
# Allow insecure sign in after confirmation. Must be used
# temporarily just for migration.
mattr_accessor :allow_insecure_sign_in_after_confirmation
@@allow_insecure_sign_in_after_confirmation = false
# Custom domain or key for cookies. Not set by default
mattr_accessor :rememberable_options
@@rememberable_options = {}
@@ -242,6 +227,18 @@ module Devise
mattr_accessor :clean_up_csrf_token_on_authentication
@@clean_up_csrf_token_on_authentication = true
def self.encryptor=(value)
warn "\n[DEVISE] To select a encryption which isn't bcrypt, you should use devise-encryptable gem.\n"
end
def self.use_salt_as_remember_token=(value)
warn "\n[DEVISE] Devise.use_salt_as_remember_token is deprecated and has no effect. Please remove it.\n"
end
def self.apply_schema=(value)
warn "\n[DEVISE] Devise.apply_schema is deprecated and has no effect. Please remove it.\n"
end
# PRIVATE CONFIGURATION
# Store scopes mappings.
@@ -266,10 +263,6 @@ module Devise
mattr_accessor :paranoid
@@paranoid = false
# Stores the token generator
mattr_accessor :token_generator
@@token_generator = nil
# Default way to setup Devise. Run rails generate devise_install to create
# a fresh initializer with all configuration values.
def self.setup
@@ -458,7 +451,7 @@ module Devise
# Generate a friendly string randomly to be used as token.
def self.friendly_token
SecureRandom.urlsafe_base64(15).tr('lIO0', 'sxyz')
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
end
# constant-time comparison algorithm to prevent timing attacks

View File

@@ -117,7 +117,6 @@ module Devise
# sign_in :user, @user # sign_in(scope, resource)
# sign_in @user # sign_in(resource)
# sign_in @user, :event => :authentication # sign_in(resource, options)
# sign_in @user, :store => false # sign_in(resource, options)
# sign_in @user, :bypass => true # sign_in(resource, options)
#
def sign_in(resource_or_scope, *args)

View File

@@ -2,6 +2,6 @@
# This is only triggered when the user is explicitly set (with set_user)
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.to_i.zero?
record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.zero?
end
end

View File

@@ -1,7 +1,6 @@
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
scope = options[:scope]
if record.respond_to?(:remember_me) && options[:store] != false &&
record.remember_me && warden.authenticated?(scope)
if record.respond_to?(:remember_me) && record.remember_me && warden.authenticated?(scope)
Devise::Controllers::Rememberable::Proxy.new(warden).remember_me(record)
end
end

View File

@@ -35,6 +35,12 @@ module Devise
:template_name => action
}.merge(opts)
if resource.respond_to?(:headers_for)
ActiveSupport::Deprecation.warn "Calling headers_for in the model is no longer supported. " <<
"Please customize your mailer instead."
headers.merge!(resource.headers_for(action))
end
@email = headers[:to]
headers
end

View File

@@ -56,8 +56,14 @@ module Devise
klass.devise_modules.each do |mod|
constant = const_get(mod.to_s.classify)
constant.required_fields(klass).each do |field|
failed_attributes << field unless instance.respond_to?(field)
if constant.respond_to?(:required_fields)
constant.required_fields(klass).each do |field|
failed_attributes << field unless instance.respond_to?(field)
end
else
ActiveSupport::Deprecation.warn "The module #{mod} doesn't implement self.required_fields(klass). " \
"Devise uses required_fields to warn developers of any missing fields in their models. " \
"Please implement #{mod}.required_fields(klass) that returns an array of symbols with the required fields."
end
end
@@ -83,13 +89,11 @@ module Devise
devise_modules_hook! do
include Devise::Models::Authenticatable
if selected_modules.include?(:token_authenticatable)
ActiveSupport::Deprecation.warn "devise :token_authenticatable is deprecated. " \
"Please check Devise 3.1 release notes for more information on how to upgrade."
end
selected_modules.each do |m|
if m == :encryptable && !(defined?(Devise::Models::Encryptable))
warn "[DEVISE] You're trying to include :encryptable in your model but it is not bundled with the Devise gem anymore. Please add `devise-encryptable` to your Gemfile to proceed.\n"
end
mod = Devise::Models.const_get(m.to_s.classify)
if mod.const_defined?("ClassMethods")

View File

@@ -144,20 +144,20 @@ module Devise
#
# protected
#
# def send_devise_notification(notification, *args)
# # If the record is new or changed then delay the
# def send_devise_notification(notification, opts = {})
# # if the record is new or changed then delay the
# # delivery until the after_commit callback otherwise
# # send now because after_commit will not be called.
# if new_record? || changed?
# pending_notifications << [notification, args]
# pending_notifications << [notification, opts]
# else
# devise_mailer.send(notification, self, *args).deliver
# devise_mailer.send(notification, self, opts).deliver
# end
# end
#
# def send_pending_notifications
# pending_notifications.each do |notification, args|
# devise_mailer.send(notification, self, *args).deliver
# pending_notifications.each do |n, opts|
# devise_mailer.send(n, self, opts).deliver
# end
#
# # Empty the pending notifications array because the
@@ -171,8 +171,8 @@ module Devise
# end
# end
#
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver
def send_devise_notification(notification, opts={})
devise_mailer.send(notification, self, opts).deliver
end
def downcase_keys
@@ -279,6 +279,14 @@ module Devise
def devise_parameter_filter
@devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
end
# Generate a token by looping and ensuring does not already exist.
def generate_token(column)
loop do
token = Devise.friendly_token
break token unless to_adapter.find_first({ column => token })
end
end
end
end
end

View File

@@ -7,7 +7,7 @@ module Devise
#
# == Options
#
# Confirmable adds the following options to +devise+:
# Confirmable adds the following options to devise_for:
#
# * +allow_unconfirmed_access_for+: the time you want to allow the user to access his account
# before confirming it. After this period, the user access is denied. You can
@@ -40,10 +40,9 @@ module Devise
end
def initialize(*args, &block)
@bypass_confirmation_postpone = false
@bypass_postpone = false
@reconfirmation_required = false
@skip_confirmation_notification = false
@raw_confirmation_token = nil
super
end
@@ -94,12 +93,10 @@ module Devise
# Send confirmation instructions by email
def send_confirmation_instructions
unless @raw_confirmation_token
generate_confirmation_token!
end
ensure_confirmation_token!
opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
send_devise_notification(:confirmation_instructions, opts)
end
def send_reconfirmation_instructions
@@ -112,11 +109,17 @@ module Devise
# Resend confirmation token.
# Regenerates the token if the period is expired.
def resend_confirmation_instructions
def resend_confirmation_token
pending_any_confirmation do
regenerate_confirmation_token! if confirmation_period_expired?
send_confirmation_instructions
end
end
# Generate a confirmation token unless already exists and save the record.
def ensure_confirmation_token!
generate_confirmation_token! if should_generate_confirmation_token?
end
# Overwrites active_for_authentication? for confirmation
# by verifying whether a user is active to sign in or not. If the user
@@ -146,16 +149,19 @@ module Devise
# If you don't want reconfirmation to be sent, neither a code
# to be generated, call skip_reconfirmation!
def skip_reconfirmation!
@bypass_confirmation_postpone = true
@bypass_postpone = true
end
protected
def should_generate_confirmation_token?
confirmation_token.nil? || confirmation_period_expired?
end
# A callback method used to deliver confirmation
# instructions on creation. This can be overriden
# in models to map to a nice sign up e-mail.
def send_on_create_confirmation_instructions
send_confirmation_instructions
send_devise_notification(:confirmation_instructions)
end
# Callback to overwrite if confirmation is required or not.
@@ -215,12 +221,10 @@ module Devise
end
end
# Generates a new random token for confirmation, and stores
# the time this token is being generated
# Generates a new random token for confirmation, and stores the time
# this token is being generated
def generate_confirmation_token
raw, enc = Devise.token_generator.generate(self.class, :confirmation_token)
@raw_confirmation_token = raw
self.confirmation_token = enc
self.confirmation_token = self.class.confirmation_token
self.confirmation_sent_at = Time.now.utc
end
@@ -228,16 +232,30 @@ module Devise
generate_confirmation_token && save(:validate => false)
end
# Regenerates a new token.
def regenerate_confirmation_token
generate_confirmation_token
end
def regenerate_confirmation_token!
regenerate_confirmation_token && save(:validate => false)
end
def after_password_reset
super
confirm! unless confirmed?
end
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
@reconfirmation_required = true
self.unconfirmed_email = self.email
self.email = self.email_was
generate_confirmation_token
regenerate_confirmation_token
end
def postpone_email_change?
postpone = self.class.reconfirmable && email_changed? && !@bypass_confirmation_postpone && !self.email.blank?
@bypass_confirmation_postpone = false
postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone && !self.email.blank?
@bypass_postpone = false
postpone
end
@@ -262,7 +280,7 @@ module Devise
unless confirmable.try(:persisted?)
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
end
confirmable.resend_confirmation_instructions if confirmable.persisted?
confirmable.resend_confirmation_token if confirmable.persisted?
confirmable
end
@@ -271,19 +289,16 @@ module Devise
# If the user is already confirmed, create an error for the user
# Options must have the confirmation_token
def confirm_by_token(confirmation_token)
original_token = confirmation_token
confirmation_token = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
if !confirmable.persisted? && Devise.allow_insecure_token_lookup
confirmable = find_or_initialize_with_error_by(:confirmation_token, original_token)
end
confirmable.confirm! if confirmable.persisted?
confirmable.confirmation_token = original_token
confirmable
end
# Generate a token checking if one does not already exist in the database.
def confirmation_token
generate_token(:confirmation_token)
end
# Find a record for confirmation by unconfirmed email field
def find_by_unconfirmed_email_with_errors(attributes = {})
unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }

View File

@@ -38,6 +38,7 @@ module Devise
self.locked_at = Time.now.utc
if unlock_strategy_enabled?(:email)
generate_unlock_token!
send_unlock_instructions
else
save(:validate => false)
@@ -59,15 +60,11 @@ module Devise
# Send unlock instructions by email
def send_unlock_instructions
raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
self.unlock_token = enc
self.save(:validate => false)
send_devise_notification(:unlock_instructions, raw, {})
raw
send_devise_notification(:unlock_instructions)
end
# Resend the unlock instructions if the user is locked.
def resend_unlock_instructions
def resend_unlock_token
if_access_locked { send_unlock_instructions }
end
@@ -125,6 +122,15 @@ module Devise
self.failed_attempts > self.class.maximum_attempts
end
# Generates unlock token
def generate_unlock_token
self.unlock_token = self.class.unlock_token
end
def generate_unlock_token!
generate_unlock_token && save(:validate => false)
end
# Tells if the lock is expired if :time unlock strategy is active
def lock_expired?
if unlock_strategy_enabled?(:time)
@@ -152,7 +158,7 @@ module Devise
# Options must contain the user's unlock keys
def send_unlock_instructions(attributes={})
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
lockable.resend_unlock_instructions if lockable.persisted?
lockable.resend_unlock_token if lockable.persisted?
lockable
end
@@ -161,16 +167,8 @@ module Devise
# If the user is not locked, creates an error for the user
# Options must have the unlock_token
def unlock_access_by_token(unlock_token)
original_token = unlock_token
unlock_token = Devise.token_generator.digest(self, :unlock_token, unlock_token)
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
if !lockable.persisted? && Devise.allow_insecure_token_lookup
lockable = find_or_initialize_with_error_by(:unlock_token, original_token)
end
lockable.unlock_access! if lockable.persisted?
lockable.unlock_token = original_token
lockable
end
@@ -184,6 +182,10 @@ module Devise
self.lock_strategy == strategy
end
def unlock_token
Devise.friendly_token
end
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys)
end
end

View File

@@ -42,19 +42,17 @@ module Devise
save
end
# Resets reset password token and send reset password instructions by email.
# Returns the token sent in the e-mail.
# Resets reset password token and send reset password instructions by email
def send_reset_password_instructions
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
self.reset_password_token = enc
self.reset_password_sent_at = Time.now.utc
self.save(:validate => false)
send_devise_notification(:reset_password_instructions, raw, {})
raw
ensure_reset_password_token!
send_devise_notification(:reset_password_instructions)
end
# Generate reset password token unless already exists and save the record.
def ensure_reset_password_token!
generate_reset_password_token! if should_generate_reset_token?
end
# Checks if the reset password token sent is within the limit time.
# We do this by calculating if the difference between today and the
# sending date does not exceed the confirm in time configured.
@@ -81,6 +79,23 @@ module Devise
protected
def should_generate_reset_token?
reset_password_token.nil? || !reset_password_period_valid?
end
# Generates a new random token for reset password
def generate_reset_password_token
self.reset_password_token = self.class.reset_password_token
self.reset_password_sent_at = Time.now.utc
self.reset_password_token
end
# Resets the reset password token with and save the record without
# validating
def generate_reset_password_token!
generate_reset_password_token && save(:validate => false)
end
# Removes reset_password token
def clear_reset_password_token
self.reset_password_token = nil
@@ -112,14 +127,7 @@ module Devise
# containing an error in reset_password_token attribute.
# Attributes must contain reset_password_token, password and confirmation
def reset_password_by_token(attributes={})
original_token = attributes[:reset_password_token]
reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
recoverable = find_or_initialize_with_error_by(:reset_password_token, reset_password_token)
if !recoverable.persisted? && Devise.allow_insecure_token_lookup
recoverable = find_or_initialize_with_error_by(:reset_password_token, original_token)
end
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
if recoverable.persisted?
if recoverable.reset_password_period_valid?
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
@@ -127,8 +135,6 @@ module Devise
recoverable.errors.add(:reset_password_token, :expired)
end
end
recoverable.reset_password_token = original_token
recoverable
end

View File

@@ -110,16 +110,12 @@ module Devise
# Recreate the user based on the stored cookie
def serialize_from_cookie(id, remember_token)
record = to_adapter.get(id)
record if record && !record.remember_expired? &&
Devise.secure_compare(record.rememberable_value, remember_token)
record if record && record.rememberable_value == remember_token && !record.remember_expired?
end
# Generate a token checking if one does not already exist in the database.
def remember_token #:nodoc:
loop do
token = Devise.friendly_token
break token unless to_adapter.find_first({ :remember_token => token })
end
generate_token(:remember_token)
end
Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options)

View File

@@ -79,10 +79,7 @@ module Devise
# Generate a token checking if one does not already exist in the database.
def authentication_token
loop do
token = Devise.friendly_token
break token unless to_adapter.find_first({ :authentication_token => token })
end
generate_token(:authentication_token)
end
Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)

View File

@@ -13,25 +13,14 @@ module Devise
if block_given?
@blocks[kind] = block
else
default_for(kind)
end
end
def sanitize(kind)
if block = @blocks[kind]
block.call(default_params)
else
default_sanitize(kind)
block = @blocks[kind]
block ? block.call(default_params) : fallback_for(kind)
end
end
private
def default_for(kind)
raise ArgumentError, "a block is expected in Devise base sanitizer"
end
def default_sanitize(kind)
def fallback_for(kind)
default_params
end
@@ -41,59 +30,34 @@ module Devise
end
class ParameterSanitizer < BaseSanitizer
def initialize(*)
super
@permitted = Hash.new { |h,k| h[k] = attributes_for(k) }
end
def sign_in
permit self.for(:sign_in)
end
def sign_up
permit self.for(:sign_up)
end
def account_update
permit self.for(:account_update)
end
private
# TODO: We do need to flatten so it works with strong_parameters
# gem. We should drop it once we move to Rails 4 only support.
def permit(keys)
default_params.permit(*Array(keys))
end
# Change for(kind) to return the values in the @permitted
# hash, allowing the developer to customize at runtime.
def default_for(kind)
@permitted[kind] || raise("No sanitizer provided for #{kind}")
end
def default_sanitize(kind)
def fallback_for(kind)
if respond_to?(kind, true)
send(kind)
else
raise NotImplementedError, "Devise doesn't know how to sanitize parameters for #{kind}"
raise NotImplementedError, "Devise Parameter Sanitizer doesn't know how to sanitize parameters for #{kind}"
end
end
def attributes_for(kind)
case kind
when :sign_in
auth_keys + [:password, :remember_me]
when :sign_up
auth_keys + [:password, :password_confirmation]
when :account_update
auth_keys + [:password, :password_confirmation, :current_password]
end
# These are the params used to sign in a user so we don't need to
# mass-assign the password param in order to authenticate. Excluding it
# here allows us to construct a new user without sensitive information if
# authentication fails.
def sign_in
default_params.permit(*auth_keys + [:password, :remember_me])
end
def sign_up
default_params.permit(*(auth_keys + [:password, :password_confirmation]))
end
def account_update
default_params.permit(*(auth_keys + [:password, :password_confirmation, :current_password]))
end
def auth_keys
@auth_keys ||= @resource_class.authentication_keys.respond_to?(:keys) ?
@resource_class.authentication_keys.keys : @resource_class.authentication_keys
resource_class.authentication_keys.respond_to?(:keys) ? resource_class.authentication_keys.keys : resource_class.authentication_keys
end
end
end

View File

@@ -29,17 +29,21 @@ module Devise
end
end
initializer "devise.secret_key" do
Devise.token_generator ||=
if secret_key = Devise.secret_key
Devise::TokenGenerator.new(
Devise::CachingKeyGenerator.new(Devise::KeyGenerator.new(secret_key))
)
initializer "devise.mongoid_version_warning" do
if defined?(Mongoid)
require 'mongoid/version'
if Mongoid::VERSION.to_f < 2.1
puts "\n[DEVISE] Please note that Mongoid versions prior to 2.1 handle dirty model " \
"object attributes in such a way that the Devise `validatable` module will not apply " \
"its usual uniqueness and format validations for the email field. It is recommended " \
"that you upgrade to Mongoid 2.1+ for this and other fixes, but if for some reason you " \
"are unable to do so, you should add these validations manually.\n"
end
end
end
initializer "devise.fix_routes_proxy_missing_respond_to_bug" do
# Deprecate: Remove once we move to Rails 4 only.
# We can get rid of this once we support only Rails > 3.2
ActionDispatch::Routing::RoutesProxy.class_eval do
def respond_to?(method, include_private = false)
super || routes.url_helpers.respond_to?(method)

View File

@@ -80,8 +80,7 @@ module ActionDispatch::Routing
# * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up,
# :password, :confirmation, :unlock.
#
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout',
# :password => 'secret', :confirmation => 'verification', registration: 'register }
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
#
# * :controllers => the controller which should be used. All routes by default points to Devise controllers.
# However, if you want them to point to custom controller, you should do:
@@ -192,7 +191,6 @@ module ActionDispatch::Routing
#
def devise_for(*resources)
@devise_finalized = false
raise_no_secret_key unless Devise.secret_key
options = resources.extract_options!
options[:as] ||= @scope[:as] if @scope[:as].present?
@@ -224,6 +222,14 @@ module ActionDispatch::Routing
routes = mapping.used_routes
devise_scope mapping.name do
if block_given?
ActiveSupport::Deprecation.warn "Passing a block to devise_for is deprecated. " \
"Please remove the block from devise_for (only the block, the call to " \
"devise_for must still exist) and call devise_scope :#{mapping.name} do ... end " \
"with the block instead", caller
yield
end
with_devise_exclusive_scope mapping.fullpath, mapping.name, options do
routes.each { |mod| send("devise_#{mod}", mapping, mapping.controllers) }
end
@@ -436,16 +442,6 @@ module ActionDispatch::Routing
end
end
def raise_no_secret_key #:nodoc:
raise <<-ERROR
Devise.secret_key was not set. Please add the following to your Devise initializer:
config.secret_key = '#{SecureRandom.hex(64)}'
Please ensure you restarted your application after installing Devise or setting the key.
ERROR
end
def raise_no_devise_method_error!(klass) #:nodoc:
raise "#{klass} does not respond to 'devise' method. This usually means you haven't " \
"loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " \

View File

@@ -3,7 +3,6 @@ module Warden::Mixins::Common
@request ||= ActionDispatch::Request.new(env)
end
# Deprecate: Remove this check once we move to Rails 4 only.
NULL_STORE =
defined?(ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash) ?
ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash : nil

View File

@@ -26,8 +26,20 @@ module Devise
# In case the resource can't be validated, it will fail with the given
# unauthenticated_message.
def validate(resource, &block)
unless resource
ActiveSupport::Deprecation.warn "an empty resource was given to #{self.class.name}#validate. " \
"Please ensure the resource is not nil", caller
end
result = resource && resource.valid_for_authentication?(&block)
case result
when Symbol, String
ActiveSupport::Deprecation.warn "valid_for_authentication? should return a boolean value"
fail!(result)
return false
end
if result
decorate(resource)
true

View File

@@ -5,16 +5,13 @@ module Devise
# Default strategy for signing in a user, based on his email and password in the database.
class DatabaseAuthenticatable < Authenticatable
def authenticate!
resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
encrypted = false
resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
return fail(:not_found_in_database) unless resource
if validate(resource){ encrypted = true; resource.valid_password?(password) }
if validate(resource){ resource.valid_password?(password) }
resource.after_database_authentication
success!(resource)
end
mapping.to.new.password = password if !encrypted && Devise.paranoid
fail(:not_found_in_database) unless resource
end
end
end

View File

@@ -1,70 +0,0 @@
# Deprecate: Copied verbatim from Rails source, remove once we move to Rails 4 only.
require 'thread_safe'
require 'openssl'
require 'securerandom'
module Devise
class TokenGenerator
def initialize(key_generator, digest="SHA256")
@key_generator = key_generator
@digest = digest
end
def digest(klass, column, value)
value.present? && OpenSSL::HMAC.hexdigest(@digest, key_for(column), value.to_s)
end
def generate(klass, column)
key = key_for(column)
loop do
raw = Devise.friendly_token
enc = OpenSSL::HMAC.hexdigest(@digest, key, raw)
break [raw, enc] unless klass.to_adapter.find_first({ column => enc })
end
end
private
def key_for(column)
@key_generator.generate_key("Devise #{column}")
end
end
# KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2
# It can be used to derive a number of keys for various purposes from a given secret.
# This lets Rails applications have a single secure secret, but avoid reusing that
# key in multiple incompatible contexts.
class KeyGenerator
def initialize(secret, options = {})
@secret = secret
# The default iterations are higher than required for our key derivation uses
# on the off chance someone uses this for password storage
@iterations = options[:iterations] || 2**16
end
# Returns a derived key suitable for use. The default key_size is chosen
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
# i.e. OpenSSL::Digest::SHA1#block_length
def generate_key(salt, key_size=64)
OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size)
end
end
# CachingKeyGenerator is a wrapper around KeyGenerator which allows users to avoid
# re-executing the key generation process when it's called using the same salt and
# key_size
class CachingKeyGenerator
def initialize(key_generator)
@key_generator = key_generator
@cache_keys = ThreadSafe::Cache.new
end
# Returns a derived key suitable for use. The default key_size is chosen
# to be compatible with the default settings of ActiveSupport::MessageVerifier.
# i.e. OpenSSL::Digest::SHA1#block_length
def generate_key(salt, key_size=64)
@cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size)
end
end
end

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "3.1.2".freeze
VERSION = "3.0.2".freeze
end

View File

@@ -50,7 +50,7 @@ module ActiveRecord
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
@@ -63,9 +63,12 @@ module ActiveRecord
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
# t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
RUBY
end
end

View File

@@ -14,5 +14,6 @@ class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
add_index :<%= table_name %>, :reset_password_token, :unique => true
# add_index :<%= table_name %>, :confirmation_token, :unique => true
# add_index :<%= table_name %>, :unlock_token, :unique => true
# add_index :<%= table_name %>, :authentication_token, :unique => true
end
end

View File

@@ -15,6 +15,7 @@ class AddDeviseTo<%= table_name.camelize %> < ActiveRecord::Migration
add_index :<%= table_name %>, :reset_password_token, :unique => true
# add_index :<%= table_name %>, :confirmation_token, :unique => true
# add_index :<%= table_name %>, :unlock_token, :unique => true
# add_index :<%= table_name %>, :authentication_token, :unique => true
end
def self.down

View File

@@ -4,7 +4,8 @@ module Devise
def model_contents
buffer = <<-CONTENT
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

View File

@@ -1,19 +1,13 @@
# Use this hook to configure devise mailer, warden hooks and so forth.
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
# The secret key used by Devise. Devise uses this key to generate
# random tokens. Changing this key will render invalid all existing
# confirmation, reset password and unlock tokens in the database.
config.secret_key = '<%= SecureRandom.hex(64) %>'
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
# note that it will be overwritten if you use your own mailer class with default "from" parameter.
config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
# config.mailer = "Devise::Mailer"
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
@@ -67,8 +61,8 @@ Devise.setup do |config|
# If http headers should be returned for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
# The realm used in Http Basic Authentication. 'Application' by default.
# config.http_authentication_realm = 'Application'
# The realm used in Http Basic Authentication. "Application" by default.
# config.http_authentication_realm = "Application"
# It will change confirmation, password recovery and other workflows
# to behave the same regardless if the e-mail provided was right or wrong.
@@ -98,7 +92,7 @@ Devise.setup do |config|
config.stretches = Rails.env.test? ? 1 : 10
# Setup a pepper to generate the encrypted password.
# config.pepper = '<%= SecureRandom.hex(64) %>'
# config.pepper = <%= SecureRandom.hex(64).inspect %>
# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
@@ -223,7 +217,7 @@ Devise.setup do |config|
# should add them to the navigational formats lists.
#
# The "*/*" below is required to match Internet Explorer requests.
# config.navigational_formats = ['*/*', :html]
# config.navigational_formats = ["*/*", :html]
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
@@ -247,12 +241,12 @@ Devise.setup do |config|
# is mountable, there are some extra configurations to be taken into account.
# The following options are available, assuming the engine is mounted as:
#
# mount MyEngine, at: '/my_engine'
# mount MyEngine, at: "/my_engine"
#
# The router that invoked `devise_for`, in the example above, would be:
# config.router_name = :my_engine
#
# When using omniauth, Devise cannot automatically set Omniauth path,
# so you need to do it manually. For the users scope, it would be:
# config.omniauth_path_prefix = '/my_engine/users/auth'
# config.omniauth_path_prefix = "/my_engine/users/auth"
end

View File

@@ -4,15 +4,16 @@ class PasswordsControllerTest < ActionController::TestCase
tests Devise::PasswordsController
include Devise::TestHelpers
setup do
def setup
request.env["devise.mapping"] = Devise.mappings[:user]
@user = create_user.tap(&:confirm!)
@raw = @user.send_reset_password_instructions
@user = create_user
@user.send_reset_password_instructions
end
def put_update_with_params
put :update, "user" => {
"reset_password_token" => @raw, "password" => "123456", "password_confirmation" => "123456"
"reset_password_token" => @user.reset_password_token, "password" => "123456", "password_confirmation" => "123456"
}
end

View File

@@ -215,7 +215,7 @@ class FailureTest < ActiveSupport::TestCase
}
call_failure(env)
assert @response.third.body.include?('<h2>Sign in</h2>')
assert @response.third.body.include?('Your account is not activated yet.')
assert @response.third.body.include?('Your account was not activated yet.')
end
end
end

View File

@@ -28,7 +28,9 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
test 'user should receive a confirmation from a custom mailer' do
User.any_instance.stubs(:devise_mailer).returns(Users::Mailer)
resend_confirmation
assert_equal ['custom@example.com'], ActionMailer::Base.deliveries.first.from
end
@@ -38,11 +40,21 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
assert_contain /Confirmation token(.*)invalid/
end
test 'user with valid confirmation token should be able to confirm an account' do
user = create_user(:confirm => false)
assert_not user.confirmed?
visit_user_confirmation_with_token(user.confirmation_token)
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/'
assert user.reload.confirmed?
end
test 'user with valid confirmation token should not be able to confirm an account after the token has expired' do
swap Devise, :confirm_within => 3.days do
user = create_user(:confirm => false, :confirmation_sent_at => 4.days.ago)
assert_not user.confirmed?
visit_user_confirmation_with_token(user.raw_confirmation_token)
visit_user_confirmation_with_token(user.confirmation_token)
assert_have_selector '#error_explanation'
assert_contain /needs to be confirmed within 3 days/
@@ -54,22 +66,10 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
swap Devise, :confirm_within => 3.days do
user = create_user(:confirm => false, :confirmation_sent_at => 2.days.ago)
assert_not user.confirmed?
visit_user_confirmation_with_token(user.raw_confirmation_token)
visit_user_confirmation_with_token(user.confirmation_token)
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/users/sign_in'
assert user.reload.confirmed?
end
end
test 'user should be signed in after confirmation if allow_insecure_sign_in_after_confirmation is enabled' do
swap Devise, :confirm_within => 3.days, :allow_insecure_sign_in_after_confirmation => true do
user = create_user(:confirm => false, :confirmation_sent_at => 2.days.ago)
assert_not user.confirmed?
visit_user_confirmation_with_token(user.raw_confirmation_token)
assert_contain 'Your account was successfully confirmed. You are now signed in.'
assert_current_url root_url
assert_current_url '/'
assert user.reload.confirmed?
end
end
@@ -78,7 +78,7 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
Devise::ConfirmationsController.any_instance.stubs(:after_confirmation_path_for).returns("/?custom=1")
user = create_user(:confirm => false)
visit_user_confirmation_with_token(user.raw_confirmation_token)
visit_user_confirmation_with_token(user.confirmation_token)
assert_current_url "/?custom=1"
end
@@ -87,7 +87,7 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
user = create_user(:confirm => false)
user.confirmed_at = Time.now
user.save
visit_user_confirmation_with_token(user.raw_confirmation_token)
visit_user_confirmation_with_token(user.confirmation_token)
assert_have_selector '#error_explanation'
assert_contain 'already confirmed'
@@ -98,7 +98,7 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
user.confirmed_at = Time.now
user.save
visit_user_confirmation_with_token(user.raw_confirmation_token)
visit_user_confirmation_with_token(user.confirmation_token)
assert_contain 'already confirmed'
fill_in 'email', :with => user.email
@@ -106,6 +106,21 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
assert_contain 'already confirmed'
end
test 'sign in user automatically after confirming its email' do
user = create_user(:confirm => false)
visit_user_confirmation_with_token(user.confirmation_token)
assert warden.authenticated?(:user)
end
test 'increases sign count when signed in through confirmation' do
user = create_user(:confirm => false)
visit_user_confirmation_with_token(user.confirmation_token)
user.reload
assert_equal 1, user.sign_in_count
end
test 'not confirmed user with setup to block without confirmation should not be able to sign in' do
swap Devise, :allow_unconfirmed_access_for => 0.days do
sign_in_as_user(:confirm => false)
@@ -135,16 +150,6 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
end
end
test 'unconfirmed but signed in user should be redirected to their root path' do
swap Devise, :allow_unconfirmed_access_for => 1.day do
user = sign_in_as_user(:confirm => false)
visit_user_confirmation_with_token(user.raw_confirmation_token)
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/'
end
end
test 'error message is configurable by resource name' do
store_translations :en, :devise => {
:failure => { :user => { :unconfirmed => "Not confirmed user" } }
@@ -170,7 +175,7 @@ class ConfirmationTest < ActionDispatch::IntegrationTest
test 'confirm account with valid confirmation token in XML format should return valid response' do
user = create_user(:confirm => false)
get user_confirmation_path(:confirmation_token => user.raw_confirmation_token, :format => 'xml')
get user_confirmation_path(:confirmation_token => user.confirmation_token, :format => 'xml')
assert_response :success
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
end
@@ -251,10 +256,10 @@ class ConfirmationOnChangeTest < ActionDispatch::IntegrationTest
admin = create_admin
admin.update_attributes(:email => 'new_test@example.com')
assert_equal 'new_test@example.com', admin.unconfirmed_email
visit_admin_confirmation_with_token(admin.raw_confirmation_token)
visit_admin_confirmation_with_token(admin.confirmation_token)
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/admin_area/sign_in'
assert_current_url '/admin_area/home'
assert admin.reload.confirmed?
assert_not admin.reload.pending_reconfirmation?
end
@@ -264,19 +269,17 @@ class ConfirmationOnChangeTest < ActionDispatch::IntegrationTest
admin.update_attributes(:email => 'first_test@example.com')
assert_equal 'first_test@example.com', admin.unconfirmed_email
raw_confirmation_token = admin.raw_confirmation_token
admin = Admin.find(admin.id)
confirmation_token = admin.confirmation_token
admin.update_attributes(:email => 'second_test@example.com')
assert_equal 'second_test@example.com', admin.unconfirmed_email
visit_admin_confirmation_with_token(raw_confirmation_token)
visit_admin_confirmation_with_token(confirmation_token)
assert_have_selector '#error_explanation'
assert_contain(/Confirmation token(.*)invalid/)
visit_admin_confirmation_with_token(admin.raw_confirmation_token)
visit_admin_confirmation_with_token(admin.confirmation_token)
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/admin_area/sign_in'
assert_current_url '/admin_area/home'
assert admin.reload.confirmed?
assert_not admin.reload.pending_reconfirmation?
end
@@ -288,7 +291,7 @@ class ConfirmationOnChangeTest < ActionDispatch::IntegrationTest
create_second_admin(:email => "new_admin_test@example.com")
visit_admin_confirmation_with_token(admin.raw_confirmation_token)
visit_admin_confirmation_with_token(admin.confirmation_token)
assert_have_selector '#error_explanation'
assert_contain(/Email.*already.*taken/)
assert admin.reload.pending_reconfirmation?

View File

@@ -13,7 +13,6 @@ class LockTest < ActionDispatch::IntegrationTest
visit new_user_session_path
click_link "Didn't receive unlock instructions?"
Devise.stubs(:friendly_token).returns("abcdef")
fill_in 'email', :with => user.email
click_button 'Resend unlock instructions'
end
@@ -23,11 +22,8 @@ class LockTest < ActionDispatch::IntegrationTest
assert_template 'sessions/new'
assert_contain 'You will receive an email with instructions about how to unlock your account in a few minutes'
mail = ActionMailer::Base.deliveries.last
assert_equal 1, ActionMailer::Base.deliveries.size
assert_equal ['please-change-me@config-initializers-devise.com'], mail.from
assert_match user_unlock_path(unlock_token: 'abcdef'), mail.body.encoded
assert_equal ['please-change-me@config-initializers-devise.com'], ActionMailer::Base.deliveries.first.from
end
test 'user should receive the instructions from a custom mailer' do
@@ -79,15 +75,23 @@ class LockTest < ActionDispatch::IntegrationTest
end
test "locked user should be able to unlock account" do
user = create_user
raw = user.lock_access!
visit_user_unlock_with_token(raw)
user = create_user(:locked => true)
assert user.access_locked?
visit_user_unlock_with_token(user.unlock_token)
assert_current_url "/users/sign_in"
assert_contain 'Your account has been unlocked successfully. Please sign in to continue.'
assert_not user.reload.access_locked?
end
test "redirect user to sign in page after unlocking its account" do
user = create_user(:locked => true)
visit_user_unlock_with_token(user.unlock_token)
assert_not warden.authenticated?(:user)
end
test "user should not send a new e-mail if already locked" do
user = create_user(:locked => true)
user.failed_attempts = User.maximum_attempts + 1
@@ -149,10 +153,9 @@ class LockTest < ActionDispatch::IntegrationTest
end
test 'user with valid unlock token should be able to unlock account via XML request' do
user = create_user()
raw = user.lock_access!
user = create_user(:locked => true)
assert user.access_locked?
get user_unlock_path(:format => 'xml', :unlock_token => raw)
get user_unlock_path(:format => 'xml', :unlock_token => user.unlock_token)
assert_response :success
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
end

View File

@@ -14,16 +14,12 @@ class PasswordTest < ActionDispatch::IntegrationTest
fill_in 'email', :with => 'user@test.com'
yield if block_given?
Devise.stubs(:friendly_token).returns("abcdef")
click_button 'Send me reset password instructions'
end
def reset_password(options={}, &block)
unless options[:visit] == false
visit edit_user_password_path(:reset_password_token => options[:reset_password_token] || "abcdef")
assert_response :success
end
visit edit_user_password_path(:reset_password_token => options[:reset_password_token]) unless options[:visit] == false
assert_response :success
fill_in 'New password', :with => '987654321'
fill_in 'Confirm new password', :with => '987654321'
@@ -49,10 +45,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
request_forgot_password do
fill_in 'email', :with => 'foo@bar.com'
end
mail = ActionMailer::Base.deliveries.last
assert_equal ['custom@example.com'], mail.from
assert_match edit_user_password_path(reset_password_token: 'abcdef'), mail.body.encoded
assert_equal ['custom@example.com'], ActionMailer::Base.deliveries.last.from
end
test 'reset password with email of different case should fail when email is NOT the list of case insensitive keys' do
@@ -153,7 +146,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
test 'not authenticated user with valid reset password token but invalid password should not be able to change his password' do
user = create_user
request_forgot_password
reset_password do
reset_password :reset_password_token => user.reload.reset_password_token do
fill_in 'Confirm new password', :with => 'other_password'
end
@@ -168,7 +161,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
test 'not authenticated user with valid data should be able to change his password' do
user = create_user
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert_current_url '/'
assert_contain 'Your password was changed successfully. You are now signed in.'
@@ -178,13 +171,14 @@ class PasswordTest < ActionDispatch::IntegrationTest
test 'after entering invalid data user should still be able to change his password' do
user = create_user
request_forgot_password
reset_password { fill_in 'Confirm new password', :with => 'other_password' }
reset_password :reset_password_token => user.reload.reset_password_token do
fill_in 'Confirm new password', :with => 'other_password'
end
assert_response :success
assert_have_selector '#error_explanation'
assert_not user.reload.valid_password?('987654321')
reset_password :visit => false
reset_password :reset_password_token => user.reload.reset_password_token, :visit => false
assert_contain 'Your password was changed successfully.'
assert user.reload.valid_password?('987654321')
end
@@ -192,7 +186,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
test 'sign in user automatically after changing its password' do
user = create_user
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert warden.authenticated?(:user)
end
@@ -202,7 +196,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
swap Devise, :unlock_strategy => strategy do
user = create_user(:locked => true)
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert_contain 'Your password was changed successfully.'
assert_not_contain 'You are now signed in.'
@@ -216,7 +210,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
swap Devise, :unlock_strategy => :email do
user = create_user(:locked => true)
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert_contain 'Your password was changed successfully.'
assert !user.reload.access_locked?
@@ -228,7 +222,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
swap Devise, :unlock_strategy => :both do
user = create_user(:locked => true)
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert_contain 'Your password was changed successfully.'
assert !user.reload.access_locked?
@@ -236,6 +230,15 @@ class PasswordTest < ActionDispatch::IntegrationTest
end
end
test 'sign in user automatically and confirm after changing its password if it\'s not confirmed' do
user = create_user(:confirm => false)
request_forgot_password
reset_password :reset_password_token => user.reload.reset_password_token
assert warden.authenticated?(:user)
assert user.reload.confirmed?
end
test 'reset password request with valid E-Mail in XML format should return valid response' do
create_user
post user_password_path(:format => 'xml'), :user => {:email => "user@test.com"}
@@ -262,9 +265,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
test 'change password with valid parameters in XML format should return valid response' do
user = create_user
request_forgot_password
put user_password_path(:format => 'xml'), :user => {
:reset_password_token => 'abcdef', :password => '987654321', :password_confirmation => '987654321'
}
put user_password_path(:format => 'xml'), :user => {:reset_password_token => user.reload.reset_password_token, :password => '987654321', :password_confirmation => '987654321'}
assert_response :success
assert warden.authenticated?(:user)
end
@@ -325,7 +326,7 @@ class PasswordTest < ActionDispatch::IntegrationTest
assert_equal 10, user.failed_attempts
request_forgot_password
reset_password
reset_password :reset_password_token => user.reload.reset_password_token
assert warden.authenticated?(:user)
user.reload

View File

@@ -84,12 +84,8 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
if mail.body.encoded =~ %r{<a href=\"http://#{host}/users/confirmation\?confirmation_token=([^"]+)">}
assert_equal Devise.token_generator.digest(user.class, :confirmation_token, $1), user.confirmation_token
else
flunk "expected confirmation url regex to match"
end
confirmation_url_regexp = %r{<a href=\"http://#{host}/users/confirmation\?confirmation_token=#{user.confirmation_token}">}
assert_match confirmation_url_regexp, mail.body.encoded
end
test 'renders a scoped if scoped_views is set to true' do

View File

@@ -80,12 +80,8 @@ class ResetPasswordInstructionsTest < ActionMailer::TestCase
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
if mail.body.encoded =~ %r{<a href=\"http://#{host}/users/password/edit\?reset_password_token=([^"]+)">}
assert_equal Devise.token_generator.digest(user.class, :reset_password_token, $1), user.reset_password_token
else
flunk "expected reset password url regex to match"
end
reset_url_regexp = %r{<a href=\"http://#{host}/users/password/edit\?reset_password_token=#{user.reset_password_token}">}
assert_match reset_url_regexp, mail.body.encoded
end
test 'mailer sender accepts a proc' do

View File

@@ -81,11 +81,7 @@ class UnlockInstructionsTest < ActionMailer::TestCase
test 'body should have link to unlock the account' do
host = ActionMailer::Base.default_url_options[:host]
if mail.body.encoded =~ %r{<a href=\"http://#{host}/users/unlock\?unlock_token=([^"]+)">}
assert_equal Devise.token_generator.digest(user.class, :unlock_token, $1), user.unlock_token
else
flunk "expected unlock url regex to match"
end
unlock_url_regexp = %r{<a href=\"http://#{host}/users/unlock\?unlock_token=#{user.unlock_token}">}
assert_match unlock_url_regexp, mail.body.encoded
end
end

View File

@@ -51,19 +51,9 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_equal "was already confirmed, please try signing in", user.errors[:email].join
end
test 'DEPRECATED: should find and confirm a user automatically' do
swap Devise, allow_insecure_token_lookup: true do
user = create_user
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert_equal confirmed_user, user
assert user.reload.confirmed?
end
end
test 'should find and confirm a user automatically based on the raw token' do
test 'should find and confirm a user automatically' do
user = create_user
raw = user.raw_confirmation_token
confirmed_user = User.confirm_by_token(raw)
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert_equal confirmed_user, user
assert user.reload.confirmed?
end
@@ -84,7 +74,7 @@ class ConfirmableTest < ActiveSupport::TestCase
user = create_user
user.confirmed_at = Time.now
user.save
confirmed_user = User.confirm_by_token(user.raw_confirmation_token)
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert confirmed_user.confirmed?
assert_equal "was already confirmed, please try signing in", confirmed_user.errors[:email].join
end
@@ -186,7 +176,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_instructions
assert_not user.resend_confirmation_token
assert user.confirmed?
assert_equal 'was already confirmed, please try signing in', user.errors[:email].join
end
@@ -274,7 +264,7 @@ class ConfirmableTest < ActiveSupport::TestCase
def confirm_user_by_token_with_confirmation_sent_at(confirmation_sent_at)
user = create_user
user.update_attribute(:confirmation_sent_at, confirmation_sent_at)
confirmed_user = User.confirm_by_token(user.raw_confirmation_token)
confirmed_user = User.confirm_by_token(user.confirmation_token)
assert_equal confirmed_user, user
user.reload.confirmed?
end
@@ -295,12 +285,32 @@ class ConfirmableTest < ActiveSupport::TestCase
end
end
test 'always generate a new token on resend' do
test 'should generate a new token if the previous one has expired' do
swap Devise, :confirm_within => 3.days do
user = create_user
user.update_attribute(:confirmation_sent_at, 4.days.ago)
old = user.confirmation_token
user.resend_confirmation_token
assert_not_equal user.confirmation_token, old
end
end
test 'should generate a new token when a valid one does not exist' do
swap Devise, :confirm_within => 3.days do
user = create_user
user.update_attribute(:confirmation_sent_at, 4.days.ago)
old = user.confirmation_token
user.ensure_confirmation_token!
assert_not_equal user.confirmation_token, old
end
end
test 'should not generate a new token when a valid one exists' do
user = create_user
old = user.confirmation_token
user = User.find(user.id)
user.resend_confirmation_instructions
assert_not_equal user.confirmation_token, old
assert_not_nil user.confirmation_token
old = user.confirmation_token
user.ensure_confirmation_token!
assert_equal user.confirmation_token, old
end
test 'should call after_confirmation if confirmed' do

View File

@@ -139,20 +139,10 @@ class LockableTest < ActiveSupport::TestCase
end
end
test 'DEPRECATED: should find and unlock a user automatically' do
swap Devise, allow_insecure_token_lookup: true do
user = create_user
user.lock_access!
locked_user = User.unlock_access_by_token(user.unlock_token)
assert_equal locked_user, user
assert_not user.reload.access_locked?
end
end
test 'should find and unlock a user automatically based on raw token' do
test 'should find and unlock a user automatically' do
user = create_user
raw = user.send_unlock_instructions
locked_user = User.unlock_access_by_token(raw)
user.lock_access!
locked_user = User.unlock_access_by_token(user.unlock_token)
assert_equal locked_user, user
assert_not user.reload.access_locked?
end
@@ -205,7 +195,7 @@ 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_instructions
assert_not user.resend_unlock_token
assert_not user.access_locked?
assert_equal 'was not locked', user.errors[:email].join
end
@@ -213,7 +203,7 @@ class LockableTest < ActiveSupport::TestCase
test 'should not be able to send instructions if the user if not locked and have username as unlock key' do
swap Devise, :unlock_keys => [:username] do
user = create_user
assert_not user.resend_unlock_instructions
assert_not user.resend_unlock_token
assert_not user.access_locked?
assert_equal 'was not locked', user.errors[:username].join
end

View File

@@ -108,21 +108,11 @@ class RecoverableTest < ActiveSupport::TestCase
end
end
test 'DEPRECATED: should find a user to reset his password based on reset_password_token' do
swap Devise, allow_insecure_token_lookup: true do
user = create_user
user.send_reset_password_instructions
reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token)
assert_equal reset_password_user, user
end
end
test 'should find a user to reset his password based on the raw token' do
test 'should find a user to reset his password based on reset_password_token' do
user = create_user
raw = user.send_reset_password_instructions
user.ensure_reset_password_token!
reset_password_user = User.reset_password_by_token(:reset_password_token => raw)
reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token)
assert_equal reset_password_user, user
end
@@ -140,9 +130,9 @@ class RecoverableTest < ActiveSupport::TestCase
test 'should return a new record with errors if password is blank' do
user = create_user
raw = user.send_reset_password_instructions
user.ensure_reset_password_token!
reset_password_user = User.reset_password_by_token(:reset_password_token => raw, :password => '')
reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token, :password => '')
assert_not reset_password_user.errors.empty?
assert_match "can't be blank", reset_password_user.errors[:password].join
end
@@ -150,10 +140,10 @@ class RecoverableTest < ActiveSupport::TestCase
test 'should reset successfully user password given the new password and confirmation' do
user = create_user
old_password = user.password
raw = user.send_reset_password_instructions
user.ensure_reset_password_token!
User.reset_password_by_token(
:reset_password_token => raw,
:reset_password_token => user.reset_password_token,
:password => 'new_password',
:password_confirmation => 'new_password'
)
@@ -163,17 +153,38 @@ class RecoverableTest < ActiveSupport::TestCase
assert user.valid_password?('new_password')
end
test 'should not reset reset password token during reset_password_within time' do
swap Devise, :reset_password_within => 1.hour do
user = create_user
user.send_reset_password_instructions
3.times do
token = user.reset_password_token
user.send_reset_password_instructions
assert_equal token, user.reset_password_token
end
end
end
test 'should reset reset password token after reset_password_within time' do
swap Devise, :reset_password_within => 1.hour do
user = create_user
user.reset_password_sent_at = 2.days.ago
token = user.reset_password_token
user.send_reset_password_instructions
assert_not_equal token, user.reset_password_token
end
end
test 'should not reset password after reset_password_within time' do
swap Devise, :reset_password_within => 1.hour do
user = create_user
raw = user.send_reset_password_instructions
old_password = user.password
user.ensure_reset_password_token!
user.reset_password_sent_at = 2.days.ago
user.save!
reset_password_user = User.reset_password_by_token(
:reset_password_token => raw,
:reset_password_token => user.reset_password_token,
:password => 'new_password',
:password_confirmation => 'new_password'
)
@@ -190,5 +201,22 @@ class RecoverableTest < ActiveSupport::TestCase
:reset_password_sent_at,
:reset_password_token
]
end
test 'should generate a new token when a valid one does not exist' do
user = create_user
assert_nil user.reset_password_token
user.ensure_reset_password_token!
assert_not_nil user.reset_password_token
end
test 'should not generate a new token when a valid one exists' do
user = create_user
user.send :generate_reset_password_token!
assert_not_nil user.reset_password_token
old = user.reset_password_token
user.ensure_reset_password_token!
assert_equal user.reset_password_token, old
end
end

View File

@@ -22,14 +22,6 @@ class RememberableTest < ActiveSupport::TestCase
user.forget_me!
end
test 'can generate remember token' do
user = create_user
user.singleton_class.send(:attr_accessor, :remember_token)
User.to_adapter.expects(:find_first).returns(nil)
user.remember_me!
assert user.remember_token
end
test 'serialize into cookie' do
user = create_user
user.remember_me!

View File

@@ -141,4 +141,23 @@ class CheckFieldsTest < ActiveSupport::TestCase
Devise::Models.check_fields!(Magician)
end
end
test "doesn't raise a NoMethodError exception when the module doesn't have a required_field(klass) class method" do
driver = Class.new do
extend Devise::Models
def self.before_validation(instance)
end
attr_accessor :encrypted_password, :email
devise :database_authenticatable
end
swap_module_method_existence Devise::Models::DatabaseAuthenticatable, :required_fields do
assert_deprecated do
Devise::Models.check_fields!(driver)
end
end
end
end

View File

@@ -2,13 +2,12 @@ require 'test_helper'
require 'devise/parameter_sanitizer'
class BaseSanitizerTest < ActiveSupport::TestCase
def sanitizer(params)
Devise::BaseSanitizer.new(User, :user, params)
def sanitizer
Devise::BaseSanitizer.new(User, :user, { user: { "email" => "jose" } })
end
test 'returns chosen params' do
sanitizer = sanitizer(user: { "email" => "jose" })
assert_equal({ "email" => "jose" }, sanitizer.sanitize(:sign_in))
assert_equal({ "email" => "jose" }, sanitizer.for(:sign_in))
end
end
@@ -23,59 +22,37 @@ if defined?(ActionController::StrongParameters)
test 'filters some parameters on sign in by default' do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid", "remember_me" => "1" })
assert_equal({ "email" => "jose", "password" => "invalid", "remember_me" => "1" }, sanitizer.sanitize(:sign_in))
assert_equal({ "email" => "jose", "password" => "invalid", "remember_me" => "1" }, sanitizer.for(:sign_in))
end
test 'handles auth keys as a hash' do
swap Devise, :authentication_keys => {:email => true} do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.sanitize(:sign_in))
assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.for(:sign_in))
end
end
test 'filters some parameters on sign up by default' do
sanitizer = sanitizer(user: { "email" => "jose", "role" => "invalid" })
assert_equal({ "email" => "jose" }, sanitizer.sanitize(:sign_up))
assert_equal({ "email" => "jose" }, sanitizer.for(:sign_up))
end
test 'filters some parameters on account update by default' do
sanitizer = sanitizer(user: { "email" => "jose", "role" => "invalid" })
assert_equal({ "email" => "jose" }, sanitizer.sanitize(:account_update))
assert_equal({ "email" => "jose" }, sanitizer.for(:account_update))
end
test 'allows custom hooks' do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
sanitizer.for(:sign_in) { |user| user.permit(:email, :password) }
assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.sanitize(:sign_in))
end
test 'adding multiple permitted parameters' do
sanitizer = sanitizer(user: { "email" => "jose", "username" => "jose1", "role" => "valid" })
sanitizer.for(:sign_in).concat([:username, :role])
assert_equal({ "email" => "jose", "username" => "jose1", "role" => "valid" }, sanitizer.sanitize(:sign_in))
end
test 'removing multiple default parameters' do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid", "remember_me" => "1" })
sanitizer.for(:sign_in).delete(:email)
sanitizer.for(:sign_in).delete(:password)
assert_equal({ "remember_me" => "1" }, sanitizer.sanitize(:sign_in))
assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.for(:sign_in))
end
test 'raises on unknown hooks' do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
assert_raise NotImplementedError do
sanitizer.sanitize(:unknown)
sanitizer.for(:unknown)
end
end
test 'passes parameters to filter as arguments to sanitizer' do
params = {user: stub}
sanitizer = Devise::ParameterSanitizer.new(User, :user, params)
params[:user].expects(:permit).with(kind_of(Symbol), kind_of(Symbol), kind_of(Symbol))
sanitizer.sanitize(:sign_in)
end
end
end

View File

@@ -4,9 +4,6 @@ require "omniauth-openid"
# Use this hook to configure devise mailer, warden hooks and so forth. The first
# four configuration values can also be set straight in your models.
Devise.setup do |config|
config.secret_key = "d9eb5171c59a4c817f68b0de27b8c1e340c2341b52cdbc60d3083d4e8958532" \
"18dcc5f589cafde048faec956b61f864b9b5513ff9ce29bf9e5d58b0f234f8e3b"
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class with default "from" parameter.

View File

@@ -11,7 +11,4 @@ module SharedAdmin
validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?
end
def raw_confirmation_token
@raw_confirmation_token
end
end

View File

@@ -12,10 +12,6 @@ module SharedUser
extend ExtendMethods
end
def raw_confirmation_token
@raw_confirmation_token
end
module ExtendMethods
def new_with_session(params, session)
super.tap do |user|

View File

@@ -67,4 +67,25 @@ class ActiveSupport::TestCase
end
end
end
def swap_module_method_existence(klass, method)
klass.module_eval %Q[
class << self
alias #{method}_referenced #{method}
undef #{method}
end
]
begin
yield if block_given?
ensure
klass.module_eval %Q[
class << self
alias #{method} #{method}_referenced
undef #{method}_referenced
end
]
end
end
end