Compare commits

..

7 Commits

Author SHA1 Message Date
José Valim
02a2976f5e Release v2.2.6 2013-08-09 10:31:54 +02:00
José Valim
a44002c68b Fix the build 2013-08-09 10:21:22 +02:00
José Valim
60f3c678e6 Skip storage for cookies on unverified requests 2013-08-09 09:33:19 +02:00
José Valim
81141bb9c8 Update Gemfile.lock 2013-08-02 23:45:31 +02:00
José Valim
373fd03ebc Release 2.2.5 2013-08-02 23:24:17 +02:00
José Valim
b3eace20c7 Update CHANGELOG 2013-08-02 23:22:39 +02:00
José Valim
415fa2ad21 Protect against CSRF token fixation attacks 2013-08-02 23:16:32 +02:00
102 changed files with 828 additions and 1378 deletions

View File

@@ -1,13 +1,28 @@
language: ruby
script: "bundle exec rake test"
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
- 2.0.0
env:
- DEVISE_ORM=mongoid
- DEVISE_ORM=active_record
matrix:
exclude:
- rvm: 1.8.7
env: DEVISE_ORM=mongoid
gemfile: Gemfile
- rvm: 1.8.7
env: DEVISE_ORM=mongoid
gemfile: gemfiles/Gemfile.rails-3.1.x
- rvm: 1.9.2
env: DEVISE_ORM=mongoid
gemfile: Gemfile
- rvm: 1.9.2
env: DEVISE_ORM=mongoid
gemfile: gemfiles/Gemfile.rails-3.1.x
gemfile:
- gemfiles/Gemfile.rails-3.2.x
- gemfiles/Gemfile.rails-3.1.x
- Gemfile
services:
- mongodb

View File

@@ -1,55 +1,13 @@
== 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
== 2.2.6
* bug fix
* Skip storage for cookies on unverified requests
== 3.0.1
Security announcement: http://blog.plataformatec.com.br/2013/08/csrf-token-fixation-attacks-in-devise/
* enhancements
* Add after_confirmation callback
== 2.2.5
* bug fix
* When using rails 3.2, the generator adds 'attr_accessible' to the model (by @jcoyne)
* Clean up CSRF token after authentication (by @homakov). Notice this change will clean up the CSRF Token after authentication (sign in, sign up, etc). So if you are using AJAX for such features, you will need to fetch a new CSRF token from the server.
== 3.0.0
* 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)
* 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
@@ -165,7 +123,6 @@ Security announcement: http://blog.plataformatec.com.br/2013/01/security-announc
* Do not accidentally mark `_prefixes` as private
* Better support for custom strategies on test helpers (by @mattconnolly)
* Return `head :no_content` in SessionsController now that most JS libraries handle it (by @julianvargasalvarez)
* Reverted moving devise/shared/_links.erb to devise/_links.erb
== 2.0.4
@@ -666,7 +623,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
@@ -806,19 +763,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
@@ -826,7 +783,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
@@ -838,7 +795,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
@@ -846,9 +803,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
@@ -869,7 +826,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
@@ -887,7 +844,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
@@ -898,25 +855,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
@@ -925,7 +882,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
@@ -933,17 +890,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
@@ -952,12 +909,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

@@ -2,7 +2,7 @@ source "https://rubygems.org"
gemspec
gem "rails", "~> 4.0.0"
gem "rails", "~> 3.2.6"
gem "omniauth", "~> 1.0.0"
gem "omniauth-oauth2", "~> 1.0.0"
gem "rdoc"
@@ -24,8 +24,9 @@ platforms :ruby do
gem "sqlite3"
end
platforms :mri_19, :mri_20 do
platforms :mri_19 do
group :mongoid do
gem "mongoid", github: "mongoid/mongoid", branch: "master"
gem "mongoid", "~> 3.0"
end
end

View File

@@ -1,75 +1,71 @@
GIT
remote: git://github.com/mongoid/mongoid.git
revision: 346a79a7d01aa194de80e649916239a18d38ce13
branch: master
specs:
mongoid (4.0.0)
activemodel (~> 4.0.0)
moped (~> 1.5)
origin (~> 1.0)
tzinfo (~> 0.3.22)
PATH
remote: .
specs:
devise (3.1.0)
devise (2.2.6)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
railties (~> 3.1)
warden (~> 1.2.1)
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.0.0)
actionpack (= 4.0.0)
actionmailer (3.2.13)
actionpack (= 3.2.13)
mail (~> 2.5.3)
actionpack (4.0.0)
activesupport (= 4.0.0)
builder (~> 3.1.0)
actionpack (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
erubis (~> 2.7.0)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
activemodel (4.0.0)
activesupport (= 4.0.0)
builder (~> 3.1.0)
activerecord (4.0.0)
activemodel (= 4.0.0)
activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.0)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
activesupport (4.0.0)
i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
arel (4.0.0)
atomic (1.1.12)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.13)
activesupport (= 3.2.13)
builder (~> 3.0.0)
activerecord (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
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)
bcrypt-ruby (3.1.1)
builder (3.1.4)
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)
json (1.8.0)
i18n (0.6.1)
journey (1.0.4)
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)
minitest (4.7.5)
mime-types (1.22)
mocha (0.13.3)
metaclass (~> 0.0.1)
moped (1.5.1)
multi_json (1.7.9)
mongoid (3.1.2)
activemodel (~> 3.2)
moped (~> 1.4.2)
origin (~> 1.0)
tzinfo (~> 0.3.22)
moped (1.4.5)
multi_json (1.7.2)
multipart-post (1.2.0)
nokogiri (1.5.9)
oauth2 (0.8.1)
@@ -89,47 +85,47 @@ GEM
omniauth-openid (1.0.1)
omniauth (~> 1.0)
rack-openid (~> 1.3.1)
origin (1.1.0)
origin (1.0.11)
orm_adapter (0.4.0)
polyglot (0.3.3)
rack (1.5.2)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-ssl (1.3.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (4.0.0)
actionmailer (= 4.0.0)
actionpack (= 4.0.0)
activerecord (= 4.0.0)
activesupport (= 4.0.0)
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.0)
sprockets-rails (~> 2.0.0)
railties (4.0.0)
actionpack (= 4.0.0)
activesupport (= 4.0.0)
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.13)
railties (3.2.13)
actionpack (= 3.2.13)
activesupport (= 3.2.13)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.1.0)
rdoc (4.0.1)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.0.4)
rdoc (3.12.2)
json (~> 1.4)
ruby-openid (2.2.3)
sprockets (2.10.0)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.7)
thor (0.18.1)
thread_safe (0.1.2)
atomic
tilt (1.4.1)
treetop (1.4.14)
tilt (1.3.7)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.37)
@@ -149,12 +145,12 @@ DEPENDENCIES
devise!
jruby-openssl
mocha (~> 0.13.1)
mongoid!
mongoid (~> 3.0)
omniauth (~> 1.0.0)
omniauth-facebook
omniauth-oauth2 (~> 1.0.0)
omniauth-openid (~> 1.0.1)
rails (~> 4.0.0)
rails (~> 3.2.6)
rdoc
sqlite3
webrat (= 0.7.3)

168
README.md
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)
@@ -11,12 +12,13 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
* Is Rack based;
* Is a complete MVC solution based on Rails engines;
* Allows you to have multiple models signed in at the same time;
* Allows you to have multiple roles (or models/scopes) 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.
@@ -27,8 +29,6 @@ It's composed of 10 modules:
* [Validatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
* [Lockable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
Devise is guaranteed to be thread-safe on YARV. Thread-safety support on JRuby is on progress.
## Information
### The Devise wiki
@@ -57,7 +57,7 @@ You can view the Devise documentation in RDoc format here:
http://rubydoc.info/github/plataformatec/devise/master/frames
If you need to use Devise with previous versions of Rails, you can always run "gem server" from the command line after you install the gem to access the old documentation.
If you need to use Devise with Rails 2.3, you can always run "gem server" from the command line after you install the gem to access the old documentation.
### Example applications
@@ -90,7 +90,7 @@ Once you have solidified your understanding of Rails and authentication mechanis
## Getting started
Devise 3.0 works with Rails 3.2 onwards. You can add it to your Gemfile with:
Devise 2.0 works with Rails 3.1 onwards. You can add it to your Gemfile with:
```ruby
gem 'devise'
@@ -110,7 +110,7 @@ The generator will install an initializer which describes ALL Devise's configura
rails generate devise MODEL
```
Replace MODEL by the class name used for the applications users, it's frequently `User` but could also be `Admin`. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run `rake db:migrate` as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file to point to the Devise controller.
Replace MODEL by the class name used for the applications users, it's frequently 'User' but could also be 'Admin'. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run "rake db:migrate" as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file to point to the Devise controller.
Note that you should re-start your app here if you've already started it. Otherwise you'll run into strange errors like users being unable to login and the route helpers being undefined.
@@ -143,7 +143,7 @@ user_session
After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect. Example: For a :user resource, it will use `user_root_path` if it exists, otherwise default `root_path` will be used. This means that you need to set the root inside your routes:
```ruby
root to: "home#index"
root :to => "home#index"
```
You can also overwrite `after_sign_in_path_for` and `after_sign_out_path_for` to customize your redirect hooks.
@@ -176,65 +176,34 @@ devise :database_authenticatable, :registerable, :confirmable, :recoverable, :st
Besides :stretches, you can define :pepper, :encryptor, :confirm_within, :remember_for, :timeout_in, :unlock_in and other values. For details, see the initializer file that was created when you invoked the "devise:install" generator described above.
### Strong Parameters
### Configuring multiple models
When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing Devise to handle this concern at the controller as well.
There are just three actions in Devise that allows any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and the permited parameters by default are:
* `sign_in` (`Devise::SessionsController#new`) - Permits only the authentication keys (like `email`)
* `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`:
Devise allows you to set up as many roles as you want. For example, you may have a User model and also want an Admin model with just authentication and timeoutable features. If so, just follow these steps:
```ruby
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
# Create a migration with the required fields
create_table :admins do |t|
t.string :email
t.string :encrypted_password
t.timestamps
end
# Inside your Admin model
devise :database_authenticatable, :timeoutable
# Inside your routes
devise_for :admins
# Inside your protected controller
before_filter :authenticate_admin!
# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
```
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
class User::ParameterSanitizer < Devise::ParameterSanitizer
def sign_in
default_params.permit(:username, :email)
end
end
```
And then configure your controllers to use it:
```ruby
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super # Use the default one
end
end
end
```
The example above overrides the permitted parameters for the user to be both `:username` and `:email`. The non-lazy way to configure parameters would be by defining the before filter above in a custom controller. We detail how to configure and customize controllers in some sections below.
On the other hand, you can simply run the generator!
### Configuring views
@@ -246,7 +215,7 @@ Since Devise is an engine, all its views are packaged inside the gem. These view
rails generate devise:views
```
If you have more than one Devise model in your application (such as "User" and "Admin"), you will notice that Devise uses the same views for all models. Fortunately, Devise offers an easy way to customize views. All you need to do is set "config.scoped_views = true" inside "config/initializers/devise.rb".
If you have more than one role in your application (such as "User" and "Admin"), you will notice that Devise uses the same views for all roles. Fortunately, Devise offers an easy way to customize views. All you need to do is set "config.scoped_views = true" inside "config/initializers/devise.rb".
After doing so, you will be able to have views based on the role like "users/sessions/new" and "admins/sessions/new". If no view is found within the scope, Devise will use the default view at "devise/sessions/new". You can also use the generator to generate scoped views:
@@ -258,24 +227,22 @@ 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
end
```
```ruby
class Admins::SessionsController < Devise::SessionsController
end
```
Note that in the above example, the controller needs to be created in the `app/controller/admins/` directory.
2) Tell the router to use this controller:
2. Tell the router to use this controller:
```ruby
devise_for :admins, :controllers => { :sessions => "admins/sessions" }
```
```ruby
devise_for :admins, :controllers => { :sessions => "admins/sessions" }
```
3) And since we changed the controller, it won't use the "devise/sessions" views, so remember to copy "devise/sessions" to "admin/sessions".
3. And since we changed the controller, it won't use the `"devise/sessions"` views, so remember to copy `"devise/sessions"` to `"admin/sessions"`.
Remember that Devise uses flash messages to let users know if sign in was successful or failed. Devise expects your application to call `"flash[:notice]"` and `"flash[:alert]"` as appropriate. Do not print the entire flash hash, print specific keys or at least remove the `:timedout` key from the hash as Devise adds this key in some circumstances, this key is not meant for display.
Remember that Devise uses flash messages to let users know if sign in was successful or failed. Devise expects your application to call "flash[:notice]" and "flash[:alert]" as appropriate. Do not print the entire flash hash, print specific keys or at least remove the `:timedout` key from the hash as Devise adds this key in some circumstances, this key is not meant for display.
### Configuring routes
@@ -367,14 +334,12 @@ sign_out @user # sign_out(resource)
There are two things that is important to keep in mind:
1. These helpers are not going to work for integration tests driven by Capybara or Webrat. They are meant to be used with functional tests only. Instead, fill in the form or explicitly set the user in session;
1) These helpers are not going to work for integration tests driven by Capybara or Webrat. They are meant to be used with functional tests only. Instead, fill in the form or explicitly set the user in session;
2. If you are testing Devise internal controllers or a controller that inherits from Devise's, you need to tell Devise which mapping should be used before a request. This is necessary because Devise gets this information from router, but since functional tests do not pass through the router, it needs to be told explicitly. For example, if you are testing the user scope, simply do:
2) If you are testing Devise internal controllers or a controller that inherits from Devise's, you need to tell Devise which mapping should be used before a request. This is necessary because Devise gets this information from router, but since functional tests do not pass through the router, it needs to be told explicitly. For example, if you are testing the user scope, simply do:
```ruby
@request.env["devise.mapping"] = Devise.mappings[:user]
get :new
```
### Omniauth
@@ -388,42 +353,15 @@ You can read more about Omniauth support in the wiki:
* https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
### Configuring multiple models
Devise allows you to set up as many Devise models as you want. If you want to have an Admin model with just authentication and timeout features, in addition to the User model above, just run:
```ruby
# Create a migration with the required fields
create_table :admins do |t|
t.string :email
t.string :encrypted_password
t.timestamps
end
# Inside your Admin model
devise :database_authenticatable, :timeoutable
# Inside your routes
devise_for :admins
# Inside your protected controller
before_filter :authenticate_admin!
# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
```
Alternatively, you can simply run the Devise generator.
Keep in mind that those models will have completely different routes. They **do not** and **cannot** share the same controller for sign in, sign out and so on. In case you want to have different roles sharing the same actions, we recommend you to use a role-based approach, by either providing a role column or using [CanCan](https://github.com/ryanb/cancan).
### Other ORMs
Devise supports ActiveRecord (default) and Mongoid. To choose other ORM, you just need to require it in the initializer file.
## Additional information
### Migrating from other solutions
Devise implements encryption strategies for Clearance, Authlogic and Restful-Authentication. To make use of these strategies, you need set the desired encryptor in the encryptor initializer config option and add :encryptable to your model. You might also need to rename your encrypted password and salt columns to match Devise's fields (encrypted_password and password_salt).
## Troubleshooting
### Heroku
@@ -435,6 +373,8 @@ config.assets.initialize_on_precompile = false
Read more about the potential issues at http://guides.rubyonrails.org/asset_pipeline.html
## Additional information
### Warden
Devise is based on Warden, which is a general Rack authentication framework created by Daniel Neighman. We encourage you to read more about Warden here:
@@ -447,6 +387,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

@@ -1,7 +1,7 @@
class Devise::ConfirmationsController < DeviseController
# GET /resource/confirmation/new
def new
self.resource = resource_class.new
build_resource({})
end
# POST /resource/confirmation
@@ -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,10 +37,7 @@ 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)
else
new_session_path(resource_name)
end
after_sign_in_path_for(resource)
end
end

View File

@@ -5,7 +5,7 @@ class Devise::PasswordsController < DeviseController
# GET /resource/password/new
def new
self.resource = resource_class.new
build_resource({})
end
# POST /resource/password
@@ -53,7 +53,7 @@ class Devise::PasswordsController < DeviseController
# Check if a reset_password_token is provided in the request
def assert_reset_token_passed
if params[:reset_password_token].blank?
set_flash_message(:alert, :no_token)
set_flash_message(:error, :no_token)
redirect_to new_session_path(resource_name)
end
end

View File

@@ -4,13 +4,13 @@ class Devise::RegistrationsController < DeviseController
# GET /resource/sign_up
def new
build_resource({})
respond_with self.resource
resource = build_resource({})
respond_with resource
end
# POST /resource
def create
build_resource(sign_up_params)
build_resource
if resource.save
if resource.active_for_authentication?
@@ -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(resource_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
:update_needs_confirmation : :updated
@@ -80,16 +80,11 @@ 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)
self.resource = resource_class.new_with_session(hash || {}, session)
hash ||= resource_params || {}
self.resource = resource_class.new_with_session(hash, session)
end
# Signs in a user on sign up. You can overwrite this method in your own
@@ -121,12 +116,4 @@ class Devise::RegistrationsController < DeviseController
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
end
def account_update_params
devise_parameter_sanitizer.sanitize(:account_update)
end
end

View File

@@ -5,7 +5,7 @@ class Devise::SessionsController < DeviseController
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
self.resource = build_resource(nil, :unsafe => true)
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
@@ -34,10 +34,6 @@ class Devise::SessionsController < DeviseController
protected
def sign_in_params
devise_parameter_sanitizer.sanitize(:sign_in)
end
def serialize_options(resource)
methods = resource_class.authentication_keys.dup
methods = methods.keys if methods.is_a?(Hash)

View File

@@ -3,7 +3,7 @@ class Devise::UnlocksController < DeviseController
# GET /resource/unlock/new
def new
self.resource = resource_class.new
build_resource({})
end
# POST /resource/unlock

View File

@@ -28,6 +28,10 @@ class DeviseController < Devise.parent_controller.constantize
devise_mapping.to
end
def resource_params
params[resource_name]
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
@@ -89,6 +93,23 @@ MESSAGE
instance_variable_set(:"@#{resource_name}", new_resource)
end
# Build a devise resource.
# Assignment bypasses attribute protection when :unsafe option is passed
def build_resource(hash = nil, options = {})
hash ||= resource_params || {}
if options[:unsafe]
self.resource = resource_class.new.tap do |resource|
hash.each do |key, value|
setter = :"#{key}="
resource.send(setter, value) if resource.respond_to?(setter)
end
end
else
self.resource = resource_class.new(hash)
end
end
# Helper for use in before_filters where no authentication is required.
#
# Example:
@@ -165,8 +186,4 @@ MESSAGE
format.any(*navigational_formats, &block)
end
end
def resource_params
params.fetch(resource_name, {})
end
end

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. Please sign in."
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

@@ -19,9 +19,8 @@ Gem::Specification.new do |s|
s.test_files = `git ls-files -- test/*`.split("\n")
s.require_paths = ["lib"]
s.add_dependency("warden", "~> 1.2.3")
s.add_dependency("warden", "~> 1.2.1")
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")
s.add_dependency("railties", "~> 3.1")
end

View File

@@ -1,8 +1,8 @@
source "https://rubygems.org"
gemspec :path => '..'
gem "devise", :path => ".."
gem "rails", "~> 3.2.6"
gem "rails", "~> 3.1.0"
gem "omniauth", "~> 1.0.0"
gem "omniauth-oauth2", "~> 1.0.0"
gem "rdoc"
@@ -12,6 +12,10 @@ group :test do
gem "omniauth-openid", "~> 1.0.1"
gem "webrat", "0.7.3", :require => false
gem "mocha", "~> 0.13.1", :require => false
platforms :mri_18 do
gem "ruby-debug", ">= 0.10.3"
end
end
platforms :jruby do
@@ -24,7 +28,7 @@ platforms :ruby do
gem "sqlite3"
end
platforms :mri_19, :mri_20 do
platforms :mri_19 do
group :mongoid do
gem "mongoid", "~> 3.0"
end

View File

@@ -1,72 +1,74 @@
PATH
remote: ..
specs:
devise (3.1.0)
devise (2.2.6)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
railties (~> 3.1)
warden (~> 1.2.1)
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.1.12)
actionpack (= 3.1.12)
mail (~> 2.4.4)
actionpack (3.1.12)
activemodel (= 3.1.12)
activesupport (= 3.1.12)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
i18n (~> 0.6)
rack (~> 1.3.6)
rack-cache (~> 1.2)
rack-mount (~> 0.8.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.14)
activesupport (= 3.2.14)
sprockets (~> 2.0.4)
activemodel (3.1.12)
activesupport (= 3.1.12)
builder (~> 3.0.0)
activerecord (3.2.14)
activemodel (= 3.2.14)
activesupport (= 3.2.14)
arel (~> 3.0.2)
i18n (~> 0.6)
activerecord (3.1.12)
activemodel (= 3.1.12)
activesupport (= 3.1.12)
arel (~> 2.2.3)
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.1.12)
activemodel (= 3.1.12)
activesupport (= 3.1.12)
activesupport (3.1.12)
multi_json (~> 1.0)
arel (3.0.2)
atomic (1.1.13)
arel (2.2.3)
bcrypt-ruby (3.1.1)
builder (3.0.4)
columnize (0.3.6)
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)
journey (1.0.4)
json (1.8.0)
i18n (0.6.4)
json (1.7.7)
jwt (0.1.8)
multi_json (>= 1.5)
mail (2.5.4)
linecache (0.46)
rbx-require-relative (> 0.0.4)
mail (2.4.4)
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)
activemodel (~> 3.2)
moped (~> 1.4)
mongoid (3.0.23)
activemodel (~> 3.1)
moped (~> 1.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)
@@ -89,9 +91,11 @@ GEM
origin (1.1.0)
orm_adapter (0.4.0)
polyglot (0.3.3)
rack (1.4.5)
rack (1.3.10)
rack-cache (1.2)
rack (>= 0.4)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
@@ -99,36 +103,39 @@ 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.1.12)
actionmailer (= 3.1.12)
actionpack (= 3.1.12)
activerecord (= 3.1.12)
activeresource (= 3.1.12)
activesupport (= 3.1.12)
bundler (~> 1.0)
railties (= 3.2.14)
railties (3.2.14)
actionpack (= 3.2.14)
activesupport (= 3.2.14)
railties (= 3.1.12)
railties (3.1.12)
actionpack (= 3.1.12)
activesupport (= 3.1.12)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.1.0)
thor (~> 0.14.6)
rake (10.0.4)
rbx-require-relative (0.0.9)
rdoc (3.12.2)
json (~> 1.4)
ruby-debug (0.10.4)
columnize (>= 0.1)
ruby-debug-base (~> 0.10.4.0)
ruby-debug-base (0.10.4)
linecache (>= 0.3)
ruby-openid (2.2.3)
sprockets (2.2.2)
sprockets (2.0.4)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.7)
thor (0.18.1)
thread_safe (0.1.2)
atomic
tilt (1.4.1)
treetop (1.4.14)
thor (0.14.6)
tilt (1.4.0)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.37)
@@ -153,7 +160,8 @@ DEPENDENCIES
omniauth-facebook
omniauth-oauth2 (~> 1.0.0)
omniauth-openid (~> 1.0.1)
rails (~> 3.2.6)
rails (~> 3.1.0)
rdoc
ruby-debug (>= 0.10.3)
sqlite3
webrat (= 0.7.3)

View File

@@ -6,15 +6,12 @@ require 'set'
require 'securerandom'
module Devise
autoload :Delegator, 'devise/delegator'
autoload :FailureApp, 'devise/failure_app'
autoload :OmniAuth, 'devise/omniauth'
autoload :ParameterFilter, 'devise/parameter_filter'
autoload :BaseSanitizer, 'devise/parameter_sanitizer'
autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
autoload :TestHelpers, 'devise/test_helpers'
autoload :TimeInflector, 'devise/time_inflector'
autoload :TokenGenerator, 'devise/token_generator'
autoload :Delegator, 'devise/delegator'
autoload :FailureApp, 'devise/failure_app'
autoload :OmniAuth, 'devise/omniauth'
autoload :ParamFilter, 'devise/param_filter'
autoload :TestHelpers, 'devise/test_helpers'
autoload :TimeInflector, 'devise/time_inflector'
module Controllers
autoload :Helpers, 'devise/controllers/helpers'
@@ -46,20 +43,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 +225,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 +261,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 +449,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

@@ -80,17 +80,6 @@ module Devise
is_a?(DeviseController)
end
# Setup a param sanitizer to filter parameters using strong_parameters. See
# lib/devise/parameter_sanitizer.rb for more info. Override this
# method in your application controller to use your own parameter sanitizer.
def devise_parameter_sanitizer
@devise_parameter_sanitizer ||= if defined?(ActionController::StrongParameters)
Devise::ParameterSanitizer.new(resource_class, resource_name, params)
else
Devise::BaseSanitizer.new(resource_class, resource_name, params)
end
end
# Tell warden that params authentication is allowed for that specific page.
def allow_params_authentication!
request.env["devise.allow_params_authentication"] = true
@@ -117,7 +106,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

@@ -78,14 +78,7 @@ module Devise
def redirect_url
if warden_message == :timeout
flash[:timedout] = true
path = if request.get?
attempted_path
else
request.referrer
end
path || scope_path
attempted_path || scope_path
else
scope_path
end

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)
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

@@ -29,17 +29,17 @@ module Devise
# 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!(obj)
case obj
def self.find_scope!(duck)
case duck
when String, Symbol
return obj
return duck
when Class
Devise.mappings.each_value { |m| return m.name if obj <= m.to }
Devise.mappings.each_value { |m| return m.name if duck <= m.to }
else
Devise.mappings.each_value { |m| return m.name if obj.is_a?(m.to) }
Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
end
raise "Could not find a valid mapping for #{obj.inspect}"
raise "Could not find a valid mapping for #{duck.inspect}"
end
def self.find_by_path!(path, path_type=:fullpath)

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

@@ -22,7 +22,7 @@ module Devise
# as key on authentication. This can also be a hash where the value is a boolean specifying
# if the value is required or not.
#
# * +http_authenticatable+: if this model allows http authentication. By default false.
# * +http_authenticatable+: if this model allows http authentication. By default true.
# It also accepts an array specifying the strategies that should allow http.
#
# * +params_authenticatable+: if this model allows authentication through request params. By default true.
@@ -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
@@ -244,7 +244,7 @@ module Devise
end
def find_first_by_auth_conditions(tainted_conditions, opts={})
to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
to_adapter.find_first(devise_param_filter.filter(tainted_conditions).merge(opts))
end
# Find an initialize a record setting an error if it can't be found.
@@ -276,8 +276,16 @@ module Devise
protected
def devise_parameter_filter
@devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
def devise_param_filter
@devise_param_filter ||= Devise::ParamFilter.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

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
@@ -35,15 +35,14 @@ module Devise
included do
before_create :generate_confirmation_token, :if => :confirmation_required?
after_create :send_on_create_confirmation_instructions, :if => :send_confirmation_notification?
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, :if => :postpone_email_change?
after_update :send_reconfirmation_instructions, :if => :reconfirmation_required?
before_update :postpone_email_change_until_confirmation, :if => :postpone_email_change?
after_update :send_confirmation_instructions, :if => :reconfirmation_required?
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
@@ -67,7 +66,7 @@ module Devise
self.confirmation_token = nil
self.confirmed_at = Time.now.utc
saved = if self.class.reconfirmable && unconfirmed_email.present?
if self.class.reconfirmable && unconfirmed_email.present?
skip_reconfirmation!
self.email = unconfirmed_email
self.unconfirmed_email = nil
@@ -77,9 +76,6 @@ module Devise
else
save(:validate => false)
end
after_confirmation if saved
saved
end
end
@@ -94,26 +90,19 @@ module Devise
# Send confirmation instructions by email
def send_confirmation_instructions
unless @raw_confirmation_token
generate_confirmation_token!
end
opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
end
def send_reconfirmation_instructions
self.confirmation_token = nil if reconfirmation_required?
@reconfirmation_required = false
unless @skip_confirmation_notification
send_confirmation_instructions
end
generate_confirmation_token! if self.confirmation_token.blank?
opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
send_devise_notification(:confirmation_instructions, opts)
end
# Resend confirmation token.
# Regenerates the token if the period is expired.
def resend_confirmation_instructions
# Resend confirmation token. This method does not need to generate a new token.
def resend_confirmation_token
pending_any_confirmation do
self.confirmation_token = nil if confirmation_period_expired?
send_confirmation_instructions
end
end
@@ -137,7 +126,7 @@ module Devise
self.confirmed_at = Time.now.utc
end
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# Skips sending the confirmation notification email after_create. Unlike
# #skip_confirmation!, record still requires confirmation.
def skip_confirmation_notification!
@skip_confirmation_notification = true
@@ -146,7 +135,7 @@ 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
@@ -155,7 +144,7 @@ module Devise
# 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 +204,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,28 +215,29 @@ module Devise
generate_confirmation_token && save(:validate => false)
end
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
def after_password_reset
super
confirm! unless confirmed?
end
def postpone_email_change_until_confirmation
@reconfirmation_required = true
self.unconfirmed_email = self.email
self.email = self.email_was
generate_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
@bypass_postpone = false
postpone
end
def reconfirmation_required?
self.class.reconfirmable && @reconfirmation_required && !self.email.blank?
self.class.reconfirmable && @reconfirmation_required
end
def send_confirmation_notification?
confirmation_required? && !@skip_confirmation_notification && !self.email.blank?
end
def after_confirmation
confirmation_required? && !@skip_confirmation_notification
end
module ClassMethods
@@ -262,7 +250,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 +259,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

@@ -81,7 +81,7 @@ module Devise
#
# Example:
#
# def update_without_password(params, *options)
# def update_without_password(params={})
# params.delete(:email)
# super(params)
# end

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)
@@ -54,20 +55,16 @@ module Devise
# Verifies whether a user is locked or not.
def access_locked?
!!locked_at && !lock_expired?
locked_at && !lock_expired?
end
# 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)
@@ -140,19 +146,19 @@ module Devise
if access_locked?
yield
else
self.errors.add(Devise.unlock_keys.first, :not_locked)
self.errors.add(:email, :not_locked)
false
end
end
module ClassMethods
# Attempt to find a user by its unlock keys. If a record is found, send new
# Attempt to find a user by its email. If a record is found, send new
# unlock instructions to it. If not user is found, returns a new user
# with an email not found error.
# Options must contain the user's unlock keys
# Options must contain the user email
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,17 +42,10 @@ 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
generate_reset_password_token! if should_generate_reset_token?
send_devise_notification(:reset_password_instructions)
end
# Checks if the reset password token sent is within the limit time.
@@ -81,6 +74,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 +122,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 +130,6 @@ module Devise
recoverable.errors.add(:reset_password_token, :expired)
end
end
recoverable.reset_password_token = original_token
recoverable
end

View File

@@ -50,7 +50,7 @@ module Devise
def remember_me!(extend_period=false)
self.remember_token = self.class.remember_token if generate_remember_token?
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
save(:validate => false) if self.changed?
save(:validate => false)
end
# If the record is persisted, remove the remember token (but only if
@@ -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

@@ -37,7 +37,7 @@ module Devise
private
def remember_exists_and_not_expired?
return false unless respond_to?(:remember_created_at) && respond_to?(:remember_expired?)
return false unless respond_to?(:remember_created_at)
remember_created_at && !remember_expired?
end

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

@@ -1,5 +1,5 @@
module Devise
class ParameterFilter
class ParamFilter
def initialize(case_insensitive_keys, strip_whitespace_keys)
@case_insensitive_keys = case_insensitive_keys || []
@strip_whitespace_keys = strip_whitespace_keys || []

View File

@@ -1,93 +0,0 @@
module Devise
class BaseSanitizer
attr_reader :params, :resource_name, :resource_class
def initialize(resource_class, resource_name, params)
@resource_class = resource_class
@resource_name = resource_name
@params = params
@blocks = Hash.new
end
def for(kind, &block)
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)
end
end
private
def default_for(kind)
raise ArgumentError, "a block is expected in Devise base sanitizer"
end
def default_sanitize(kind)
default_params
end
def default_params
params.fetch(resource_name, {})
end
end
class ParameterSanitizer < BaseSanitizer
def initialize(*)
super
@permitted = Hash.new { |h,k| h[k] = attributes_for(k) }
end
def sign_in
default_params.permit self.for(:sign_in)
end
def sign_up
default_params.permit self.for(:sign_up)
end
def account_update
default_params.permit self.for(:account_update)
end
private
# 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)
if respond_to?(kind, true)
send(kind)
else
raise NotImplementedError, "Devise 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
end
def auth_keys
@auth_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,15 +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)}'
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

@@ -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.0".freeze
VERSION = "2.2.6".freeze
end

View File

@@ -22,7 +22,10 @@ module ActiveRecord
end
def inject_devise_content
content = model_contents
content = model_contents + <<CONTENT
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
CONTENT
class_path = if namespaced?
class_name.to_s.split("::")
@@ -50,7 +53,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 +66,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

@@ -2,43 +2,24 @@ module Devise
module Generators
module OrmHelpers
def model_contents
buffer = <<-CONTENT
<<-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
CONTENT
buffer += <<-CONTENT if needs_attr_accessible?
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
CONTENT
buffer
end
def needs_attr_accessible?
rails_3? && !strong_parameters_enabled?
end
def rails_3?
Rails::VERSION::MAJOR == 3
end
def strong_parameters_enabled?
defined?(ActionController::StrongParameters)
end
private
def model_exists?
File.exists?(File.join(destination_root, model_path))
end
def migration_exists?(table_name)
Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_to_#{table_name}.rb$/).first
end
def migration_path
@migration_path ||= File.join("db", "migrate")
end
@@ -48,4 +29,4 @@ CONTENT
end
end
end
end
end

View File

@@ -22,7 +22,7 @@ module Mongoid
## Database authenticatable
field :email, :type => String, :default => ""
field :encrypted_password, :type => String, :default => ""
## Recoverable
field :reset_password_token, :type => String
field :reset_password_sent_at, :type => Time
@@ -54,4 +54,4 @@ RUBY
end
end
end
end
end

View File

@@ -21,7 +21,7 @@ Some setup you must do manually if you haven't yet:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:
4. If you are deploying Rails 3.1+ on Heroku, you may want to set:
config.assets.initialize_on_precompile = false

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

@@ -34,20 +34,10 @@ class HelpersTest < ActionController::TestCase
end
test 'get resource params from request params using resource name as key' do
user_params = {'email' => 'shirley@templar.com'}
user_params = {'name' => 'Shirley Templar'}
@controller.stubs(:params).returns(HashWithIndifferentAccess.new({'user' => user_params}))
params = if Devise.rails4?
# Stub controller name so strong parameters can filter properly.
# DeviseController does not allow any parameters by default.
@controller.stubs(:controller_name).returns(:sessions_controller)
ActionController::Parameters.new({'user' => user_params})
else
HashWithIndifferentAccess.new({'user' => user_params})
end
@controller.stubs(:params).returns(params)
assert_equal user_params, @controller.send(:resource_params)
assert_equal user_params, @controller.resource_params
end
test 'resources methods are not controller actions' do

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

@@ -4,20 +4,6 @@ class SessionsControllerTest < ActionController::TestCase
tests Devise::SessionsController
include Devise::TestHelpers
test "#create doesn't raise unpermitted params when sign in fails" do
ActiveSupport::Notifications.subscribe /unpermitted_parameters/ do |name, start, finish, id, payload|
flunk "Unpermitted params: #{payload}"
end
request.env["devise.mapping"] = Devise.mappings[:user]
request.session["user_return_to"] = 'foo.bar'
user = create_user
post :create, :user => {
:email => "wrong@email.com",
:password => "wrongpassword"
}
assert_equal 200, @response.status
end
test "#create works even with scoped views" do
swap Devise, :scoped_views => true do
request.env["devise.mapping"] = Devise.mappings[:user]

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

@@ -10,11 +10,13 @@ if DEVISE_ORM == :active_record
test "all files are properly created with rails31 migration syntax" do
run_generator %w(monster)
assert_file "app/models/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
assert_migration "db/migrate/devise_create_monsters.rb", /def change/
end
test "all files for namespaced model are properly created" do
run_generator %w(admin/monster)
assert_file "app/models/admin/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
assert_migration "db/migrate/devise_create_admin_monsters.rb", /def change/
end
@@ -62,41 +64,11 @@ if DEVISE_ORM == :active_record
destination File.expand_path("../../tmp", __FILE__)
setup :prepare_destination
test "all files are properly created in rails 4.0" do
ActiveRecord::Generators::DeviseGenerator.any_instance.stubs(:rails_3?).returns(false)
test "all files are properly created" do
simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
run_generator ["monster"]
assert_file "app/models/rails_engine/monster.rb", /devise/
assert_file "app/models/rails_engine/monster.rb" do |content|
assert_no_match /attr_accessible :email/, content
end
end
end
test "all files are properly created in rails 3.2 when strong_parameters gem is not installed" do
ActiveRecord::Generators::DeviseGenerator.any_instance.stubs(:rails_3?).returns(true)
ActiveRecord::Generators::DeviseGenerator.any_instance.stubs(:strong_parameters_enabled?).returns(false)
simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
run_generator ["monster"]
assert_file "app/models/rails_engine/monster.rb", /devise/
assert_file "app/models/rails_engine/monster.rb" do |content|
assert_match /attr_accessible :email/, content
end
end
end
test "all files are properly created in rails 3.2 when strong_parameters gem is installed" do
ActiveRecord::Generators::DeviseGenerator.any_instance.stubs(:rails_3?).returns(true)
ActiveRecord::Generators::DeviseGenerator.any_instance.stubs(:strong_parameters_enabled?).returns(true)
simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
run_generator ["monster"]
assert_file "app/models/rails_engine/monster.rb", /devise/
assert_file "app/models/rails_engine/monster.rb" do |content|
assert_no_match /attr_accessible :email/, content
end
assert_file "app/models/rails_engine/monster.rb", /devise/,/attr_accessible (:[a-z_]+(, )?)+/
end
end
end

View File

@@ -191,7 +191,7 @@ class AuthenticationRoutesRestrictions < ActionDispatch::IntegrationTest
get dashboard_path
assert_response :success
assert_template 'home/admin_dashboard'
assert_template 'home/admin'
assert_contain 'Admin dashboard'
end
@@ -203,7 +203,7 @@ class AuthenticationRoutesRestrictions < ActionDispatch::IntegrationTest
get dashboard_path
assert_response :success
assert_template 'home/user_dashboard'
assert_template 'home/user'
assert_contain 'User dashboard'
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. Please sign in.'
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_contain 'Your account was successfully confirmed.'
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)
@@ -160,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
@@ -241,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
@@ -254,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
@@ -278,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,22 +146,21 @@ 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
assert_response :success
assert_current_url '/users/password'
assert_have_selector '#error_explanation'
assert_contain Devise.rails4? ?
"Password confirmation doesn't match Password" : "Password doesn't match confirmation"
assert_contain 'Password doesn\'t match confirmation'
assert_not user.reload.valid_password?('987654321')
end
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 +170,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 +185,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 +195,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 +209,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 +221,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 +229,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 +264,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 +325,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

@@ -17,7 +17,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
assert warden.authenticated?(:admin)
assert_current_url "/admin_area/home"
admin = Admin.order(:id).last
admin = Admin.last :order => "id"
assert_equal admin.email, 'new_user@test.com'
end
@@ -56,7 +56,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
assert_not warden.authenticated?(:user)
user = User.order(:id).last
user = User.last :order => "id"
assert_equal user.email, 'new_user@test.com'
assert_not user.confirmed?
end
@@ -100,8 +100,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
assert_template 'registrations/new'
assert_have_selector '#error_explanation'
assert_contain "Email is invalid"
assert_contain Devise.rails4? ?
"Password confirmation doesn't match Password" : "Password doesn't match confirmation"
assert_contain "Password doesn't match confirmation"
assert_contain "2 errors prohibited"
assert_nil User.first
@@ -207,8 +206,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
fill_in 'current password', :with => '12345678'
click_button 'Update'
assert_contain Devise.rails4? ?
"Password confirmation doesn't match Password" : "Password doesn't match confirmation"
assert_contain "Password doesn't match confirmation"
assert_not User.first.valid_password?('pas123')
end
@@ -253,7 +251,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<admin>)
admin = Admin.order(:id).last
admin = Admin.last :order => "id"
assert_equal admin.email, 'new_user@test.com'
end
@@ -262,7 +260,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
assert_response :success
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
user = User.order(:id).last
user = User.last :order => "id"
assert_equal user.email, 'new_user@test.com'
end

View File

@@ -48,7 +48,7 @@ class RememberMeTest < ActionDispatch::IntegrationTest
assert request.session[:_csrf_token]
post user_session_path, :authenticity_token => "oops", :user =>
{ email: "jose.valim@gmail.com", password: "123456", :remember_me => "1" }
{ :email => "jose.valim@gmail.com", :password => "123456", :remember_me => "1" }
assert_not warden.authenticated?(:user)
assert_not request.cookies['remember_user_token']
end

View File

@@ -45,16 +45,6 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
assert_not warden.authenticated?(:user)
end
test 'time out user session after deault limit time and redirect to latest get request' do
user = sign_in_as_user
visit edit_form_user_path(user)
click_button 'Update'
sign_in_as_user
assert_equal edit_form_user_url(user), current_url
end
test 'time out is not triggered on sign out' do
user = sign_in_as_user
get expire_user_path(user)

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
@@ -124,14 +114,6 @@ class ConfirmableTest < ActiveSupport::TestCase
end
end
test 'should not send confirmation when no email is provided' do
assert_email_not_sent do
user = new_user
user.email = ''
user.save(:validate => false)
end
end
test 'should find a user to send confirmation instructions' do
user = create_user
confirmation_user = User.send_confirmation_instructions(:email => user.email)
@@ -186,7 +168,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 +256,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,33 +277,14 @@ class ConfirmableTest < ActiveSupport::TestCase
end
end
test 'always generate a new token on resend' do
user = create_user
old = user.confirmation_token
user = User.find(user.id)
user.resend_confirmation_instructions
assert_not_equal user.confirmation_token, old
end
test 'should call after_confirmation if confirmed' do
user = create_user
user.define_singleton_method :after_confirmation do
self.username = self.username.to_s + 'updated'
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
old = user.username
assert user.confirm!
assert_not_equal user.username, old
end
test 'should not call after_confirmation if not confirmed' do
user = create_user
assert user.confirm!
user.define_singleton_method :after_confirmation do
self.username = self.username.to_s + 'updated'
end
old = user.username
assert_not user.confirm!
assert_equal user.username, old
end
end
@@ -348,15 +311,6 @@ class ReconfirmableTest < ActiveSupport::TestCase
assert_nil admin.confirmation_token
end
test 'should skip sending reconfirmation email when email is changed and skip_confirmation_notification! is invoked' do
admin = create_admin
admin.skip_confirmation_notification!
assert_email_not_sent do
admin.update_attributes(:email => 'new_test@example.com')
end
end
test 'should regenerate confirmation token after changing email' do
admin = create_admin
assert admin.confirm!
@@ -383,15 +337,6 @@ class ReconfirmableTest < ActiveSupport::TestCase
end
end
test 'should not send confirmation by email after changing to a blank email' do
admin = create_admin
assert admin.confirm!
assert_email_not_sent do
admin.email = ''
admin.save(:validate => false)
end
end
test 'should stay confirmed when email is changed' do
admin = create_admin
assert admin.confirm!

View File

@@ -48,19 +48,19 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
test "param filter should not convert booleans and integer to strings" do
conditions = { "login" => "foo@bar.com", "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
conditions = Devise::ParameterFilter.new([], []).filter(conditions)
conditions = Devise::ParamFilter.new([], []).filter(conditions)
assert_equal( { "login" => "foo@bar.com", "bool1" => "true", "bool2" => "false", "fixnum" => "123", "will_be_converted" => "1..10" }, conditions)
end
test 'param filter should filter case_insensitive_keys as insensitive' do
conditions = {'insensitive' => 'insensitive_VAL', 'sensitive' => 'sensitive_VAL'}
conditions = Devise::ParameterFilter.new(['insensitive'], []).filter(conditions)
conditions = Devise::ParamFilter.new(['insensitive'], []).filter(conditions)
assert_equal( {'insensitive' => 'insensitive_val', 'sensitive' => 'sensitive_VAL'}, conditions )
end
test 'param filter should filter strip_whitespace_keys stripping whitespaces' do
conditions = {'strip_whitespace' => ' strip_whitespace_val ', 'do_not_strip_whitespace' => ' do_not_strip_whitespace_val '}
conditions = Devise::ParameterFilter.new([], ['strip_whitespace']).filter(conditions)
conditions = Devise::ParamFilter.new([], ['strip_whitespace']).filter(conditions)
assert_equal( {'strip_whitespace' => 'strip_whitespace_val', 'do_not_strip_whitespace' => ' do_not_strip_whitespace_val '}, conditions )
end
@@ -123,6 +123,13 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
assert user.reload.valid_password?('pass4321')
end
test 'should update password with valid current password and :as option' do
user = create_user
assert user.update_with_password(:current_password => '12345678',
:password => 'pass4321', :password_confirmation => 'pass4321', :as => :admin)
assert user.reload.valid_password?('pass4321')
end
test 'should add an error to current password when it is invalid' do
user = create_user
assert_not user.update_with_password(:current_password => 'other',
@@ -175,6 +182,12 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
assert_equal 'new@example.com', user.email
end
test 'should update the user without password with :as option' do
user = create_user
user.update_without_password(:email => 'new@example.com', :as => :admin)
assert_equal 'new@example.com', user.email
end
test 'should not update password without password' do
user = create_user
user.update_without_password(:password => 'pass4321', :password_confirmation => 'pass4321')

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
@@ -195,30 +185,21 @@ class LockableTest < ActiveSupport::TestCase
end
test 'should require all unlock_keys' do
swap Devise, :unlock_keys => [:username, :email] do
user = create_user
unlock_user = User.send_unlock_instructions(:email => user.email)
assert_not unlock_user.persisted?
assert_equal "can't be blank", unlock_user.errors[:username].join
end
swap Devise, :unlock_keys => [:username, :email] do
user = create_user
unlock_user = User.send_unlock_instructions(:email => user.email)
assert_not unlock_user.persisted?
assert_equal "can't be blank", unlock_user.errors[:username].join
end
end
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
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.access_locked?
assert_equal 'was not locked', user.errors[:username].join
end
end
test 'should unlock account if lock has expired and increase attempts on failure' do
swap Devise, :unlock_in => 1.minute do
user = create_user

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.send :generate_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.send :generate_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.send :generate_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.send :generate_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,5 @@ class RecoverableTest < ActiveSupport::TestCase
:reset_password_sent_at,
:reset_password_token
]
end
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

@@ -43,9 +43,4 @@ class TimeoutableTest < ActiveSupport::TestCase
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Timeoutable.required_fields(User), []
end
test 'should not raise error if remember_created_at is not empty and rememberable is disabled' do
user = create_admin(remember_created_at: Time.current)
assert user.timedout?(31.minutes.ago)
end
end

View File

@@ -56,12 +56,7 @@ class ValidatableTest < ActiveSupport::TestCase
test 'should require confirmation to be set when creating a new record' do
user = new_user(:password => 'new_password', :password_confirmation => 'blabla')
assert user.invalid?
if Devise.rails4?
assert_equal 'doesn\'t match Password', user.errors[:password_confirmation].join
else
assert_equal 'doesn\'t match confirmation', user.errors[:password].join
end
assert_equal 'doesn\'t match confirmation', user.errors[:password].join
end
test 'should require password when updating/resetting password' do
@@ -78,12 +73,7 @@ class ValidatableTest < ActiveSupport::TestCase
user = create_user
user.password_confirmation = 'another_password'
assert user.invalid?
if Devise.rails4?
assert_equal 'doesn\'t match Password', user.errors[:password_confirmation].join
else
assert_equal 'doesn\'t match confirmation', user.errors[:password].join
end
assert_equal 'doesn\'t match confirmation', user.errors[:password].join
end
test 'should require a password with minimum of 6 characters' do

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

@@ -1,9 +1,6 @@
require 'test_helper'
class OmniAuthRoutesTest < ActionController::TestCase
ExpectedUrlGeneratiorError = Devise.rails4? ?
ActionController::UrlGenerationError : ActionController::RoutingError
tests ApplicationController
def assert_path(action, provider, with_param=true)
@@ -33,7 +30,7 @@ class OmniAuthRoutesTest < ActionController::TestCase
test 'should generate authorization path' do
assert_match "/users/auth/facebook", @controller.omniauth_authorize_path(:user, :facebook)
assert_raise ExpectedUrlGeneratiorError do
assert_raise ActionController::RoutingError do
@controller.omniauth_authorize_path(:user, :github)
end
end

View File

@@ -1,6 +1,5 @@
ActiveRecord::Migration.verbose = false
ActiveRecord::Base.logger = Logger.new(nil)
ActiveRecord::Base.include_root_in_json = true
ActiveRecord::Migrator.migrate(File.expand_path("../../rails_app/db/migrate/", __FILE__))

View File

@@ -1,72 +0,0 @@
require 'test_helper'
require 'devise/parameter_sanitizer'
class BaseSanitizerTest < ActiveSupport::TestCase
def sanitizer(params)
Devise::BaseSanitizer.new(User, :user, params)
end
test 'returns chosen params' do
sanitizer = sanitizer(user: { "email" => "jose" })
assert_equal({ "email" => "jose" }, sanitizer.sanitize(:sign_in))
end
end
if defined?(ActionController::StrongParameters)
require 'active_model/forbidden_attributes_protection'
class ParameterSanitizerTest < ActiveSupport::TestCase
def sanitizer(params)
params = ActionController::Parameters.new(params)
Devise::ParameterSanitizer.new(User, :user, params)
end
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))
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))
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))
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))
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))
end
test 'raises on unknown hooks' do
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
assert_raise NotImplementedError do
sanitizer.sanitize(:unknown)
end
end
end
end

View File

@@ -3,4 +3,8 @@
require File.expand_path('../config/application', __FILE__)
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
Rails.application.load_tasks

View File

@@ -8,14 +8,6 @@ class UsersController < ApplicationController
respond_with(current_user)
end
def edit_form
user_session['last_request_at'] = 31.minutes.ago.utc
end
def update_form
render :text => 'Update'
end
def accept
@current_user = current_user
end

View File

@@ -7,8 +7,9 @@ module Shim
end
module ClassMethods
def order(attribute)
asc(attribute)
def last(options = {})
options.delete(:order) if options[:order] == "id"
where(options).last
end
def find_by_email(email)

View File

@@ -1 +0,0 @@
<%= button_to 'Update', update_form_user_path(current_user), method: 'put' %>

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env ruby
require_relative '../config/boot'
require 'rake'
Rake.application.run

View File

@@ -2,6 +2,7 @@ require File.expand_path('../boot', __FILE__)
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"
Bundler.require :default, DEVISE_ORM
@@ -16,7 +17,7 @@ require "devise"
module RailsApp
class Application < Rails::Application
# Add additional load paths for your own custom dirs
config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers mailers views).include?($1) }
config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) }
config.autoload_paths += [ "#{config.root}/app/#{DEVISE_ORM}" ]
# Configure generators values. Many other options are available, be sure to check the documentation.

View File

@@ -2,7 +2,7 @@ unless defined?(DEVISE_ORM)
DEVISE_ORM = (ENV["DEVISE_ORM"] || :active_record).to_sym
end
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
require 'rubygems'
require 'bundler/setup'
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
$:.unshift File.expand_path('../../../../lib', __FILE__)

View File

@@ -1,5 +1,5 @@
# Load the rails application.
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application.
# Initialize the rails application
RailsApp::Application.initialize!

View File

@@ -1,34 +1,18 @@
RailsApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Settings specified here will take precedence over those in config/environment.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching.
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers.
config.action_dispatch.best_standards_support = :builtin
# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL).
config.active_record.auto_explain_threshold_in_seconds = 0.5
# Raise an error on page load if there are pending migrations
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
config.assets.debug = true
end

View File

@@ -1,84 +1,33 @@
RailsApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Settings specified here will take precedence over those in config/environment.rb
# Code is not reloaded between requests.
# The production environment is meant for finished, "live" apps.
# Code is not reloaded between requests
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both thread web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# See everything in the log (default is :info)
# config.log_level = :debug
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
# Use a different logger for distributed setups
# config.logger = SyslogLogger.new
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Whether to fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Set to :debug to see everything in the log.
config.log_level = :info
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
# Use a different cache store in production
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# Disable Rails's static asset server
# In production, Apache or nginx will already do this
config.serve_static_assets = false
# Enable serving of images, stylesheets, and javascripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# config.assets.precompile += %w( search.js )
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# Disable delivery errors, bad email addresses will be ignored
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL).
# config.active_record.auto_explain_threshold_in_seconds = 0.5
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Enable threaded mode
# config.threadsafe!
end

View File

@@ -1,36 +1,33 @@
RailsApp::Application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Settings specified here will take precedence over those in config/environment.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
# Show full error reports and disable caching.
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
config.action_dispatch.show_exceptions = false
config.active_support.deprecation = :stderr
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

@@ -1,8 +1,2 @@
config = Rails.application.config
if Devise.rails4?
config.secret_key_base = 'd588e99efff13a86461fd6ab82327823ad2f8feb5dc217ce652cdd9f0dfc5eb4b5a62a92d24d2574d7d51dfb1ea8dd453ea54e00cf672159a13104a135422a10'
else
config.secret_token = 'ea942c41850d502f2c8283e26bdc57829f471bb18224ddff0a192c4f32cdf6cb5aa0d82b3a7a7adbeb640c4b06f3aa1cd5f098162d8240f669b39d6b49680571'
config.session_store :cookie_store, :key => "_my_app"
end
Rails.application.config.secret_token = 'ea942c41850d502f2c8283e26bdc57829f471bb18224ddff0a192c4f32cdf6cb5aa0d82b3a7a7adbeb640c4b06f3aa1cd5f098162d8240f669b39d6b49680571'
Rails.application.config.session_store :cookie_store, :key => "_my_app"

View File

@@ -1 +0,0 @@
RailsApp::Application.config.session_store :cookie_store, key: '_rails_app_session'

View File

@@ -1,12 +1,8 @@
Rails.application.routes.draw do
# Resources for testing
resources :users, :only => [:index] do
member do
get :expire
get :accept
get :edit_form
put :update_form
end
get :expire, :on => :member
get :accept, :on => :member
authenticate do
post :exhibit, :on => :member
@@ -100,5 +96,5 @@ Rails.application.routes.draw do
get "/unauthenticated", :to => "home#unauthenticated"
get "/custom_strategy/new"
root :to => "home#index", :via => [:get, :post]
root :to => "home#index"
end

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

@@ -7,15 +7,12 @@ module SharedUser
:trackable, :validatable, :omniauthable
attr_accessor :other_key
attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :confirmation_sent_at
# They need to be included after Devise is called.
extend ExtendMethods
end
def raw_confirmation_token
@raw_confirmation_token
end
module ExtendMethods
def new_with_session(params, session)
super.tap do |user|

10
test/rails_app/script/rails Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
ENV_PATH = File.expand_path('../../config/environment', __FILE__)
BOOT_PATH = File.expand_path('../../config/boot', __FILE__)
APP_PATH = File.expand_path('../../config/application', __FILE__)
ROOT_PATH = File.expand_path('../..', __FILE__)
require BOOT_PATH
require 'rails/commands'

View File

@@ -1,7 +1,5 @@
require 'test_helper'
ExpectedRoutingError = Devise.rails4? ? MiniTest::Assertion : ActionController::RoutingError
class DefaultRoutingTest < ActionController::TestCase
test 'map new user session' do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, {:path => 'users/sign_in', :method => :get})
@@ -103,7 +101,7 @@ class DefaultRoutingTest < ActionController::TestCase
assert_recognizes({:controller => 'users/omniauth_callbacks', :action => 'google'}, {:path => 'users/auth/google/callback', :method => :post})
assert_named_route "/users/auth/google/callback", :user_omniauth_callback_path, :google
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'ysers/omniauth_callbacks', :action => 'twitter'}, {:path => 'users/auth/twitter/callback', :method => :get})
end
end
@@ -125,7 +123,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'does not map admin password' do
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/passwords', :action => 'new'}, 'admin_area/password/new')
end
end
@@ -135,7 +133,7 @@ class CustomizedRoutingTest < ActionController::TestCase
end
test 'does only map reader password' do
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, 'reader/sessions/new')
end
assert_recognizes({:controller => 'devise/passwords', :action => 'new'}, 'reader/password/new')
@@ -163,14 +161,14 @@ class CustomizedRoutingTest < ActionController::TestCase
test 'map deletes with :sign_out_via option' do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/deletes/sign_out', :method => :delete})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/deletes/sign_out', :method => :get})
end
end
test 'map posts with :sign_out_via option' do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/posts/sign_out', :method => :post})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/posts/sign_out', :method => :get})
end
end
@@ -178,56 +176,56 @@ class CustomizedRoutingTest < ActionController::TestCase
test 'map delete_or_posts with :sign_out_via option' do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/delete_or_posts/sign_out', :method => :post})
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/delete_or_posts/sign_out', :method => :delete})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => '/sign_out_via/delete_or_posts/sign_out', :method => :get})
end
end
test 'map with constraints defined in hash' do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => 'http://192.168.1.100/headquarters/sign_up', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => 'http://10.0.0.100/headquarters/sign_up', :method => :get})
end
end
test 'map with constraints defined in block' do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => 'http://192.168.1.100/homebase/sign_up', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => 'http://10.0.0.100//homebase/sign_up', :method => :get})
end
end
test 'map with format false for sessions' do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, {:path => '/htmlonly_admin/sign_in', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, {:path => '/htmlonly_admin/sign_in.xml', :method => :get})
end
end
test 'map with format false for passwords' do
assert_recognizes({:controller => 'devise/passwords', :action => 'create'}, {:path => '/htmlonly_admin/password', :method => :post})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/passwords', :action => 'create'}, {:path => '/htmlonly_admin/password.xml', :method => :post})
end
end
test 'map with format false for registrations' do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => '/htmlonly_admin/sign_up', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => '/htmlonly_admin/sign_up.xml', :method => :get})
end
end
test 'map with format false for confirmations' do
assert_recognizes({:controller => 'devise/confirmations', :action => 'show'}, {:path => '/htmlonly_users/confirmation', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/confirmations', :action => 'show'}, {:path => '/htmlonly_users/confirmation.xml', :method => :get})
end
end
test 'map with format false for unlocks' do
assert_recognizes({:controller => 'devise/unlocks', :action => 'show'}, {:path => '/htmlonly_users/unlock', :method => :get})
assert_raise ExpectedRoutingError do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/unlocks', :action => 'show'}, {:path => '/htmlonly_users/unlock.xml', :method => :get})
end
end

View File

@@ -63,8 +63,29 @@ class ActiveSupport::TestCase
def clear_cached_variables(options)
if options.key?(:case_insensitive_keys) || options.key?(:strip_whitespace_keys)
Devise.mappings.each do |_, mapping|
mapping.to.instance_variable_set(:@devise_parameter_filter, nil)
mapping.to.instance_variable_set(:@devise_param_filter, nil)
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

Some files were not shown because too many files have changed in this diff Show More