mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-11 08:37:56 -05:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
748eced9e8 | ||
|
|
a39312e26b | ||
|
|
b2c2cb272f | ||
|
|
fccde42f20 | ||
|
|
e90732c8c3 | ||
|
|
21874d8559 | ||
|
|
cfadaf80a2 | ||
|
|
df444663ac | ||
|
|
5b63605c94 | ||
|
|
3660cbac30 | ||
|
|
92cf50454b | ||
|
|
29ba790e07 | ||
|
|
4e2cd157c1 | ||
|
|
194959f312 | ||
|
|
e3b815de49 | ||
|
|
ac0105d15f | ||
|
|
7dbd2eac2a | ||
|
|
025c3875b6 | ||
|
|
f1a990c2ae | ||
|
|
1f4a31f1cf | ||
|
|
31910b85a2 | ||
|
|
5e1ef9319e | ||
|
|
70a429d9ff | ||
|
|
f16d01869a | ||
|
|
290cfd1f72 | ||
|
|
ed22295963 | ||
|
|
a2f84852af | ||
|
|
c4a4032b6b | ||
|
|
80895c3b9a | ||
|
|
84686d285c | ||
|
|
6c18c92598 | ||
|
|
0333caeb92 | ||
|
|
bece09c653 | ||
|
|
cd78a26f88 | ||
|
|
5c9fe5e769 | ||
|
|
fb0aec09f1 | ||
|
|
5f2a19d784 | ||
|
|
cc608f82dd | ||
|
|
7e784b258c | ||
|
|
870912d458 | ||
|
|
f0c0f5f11b | ||
|
|
7dc1842cc4 | ||
|
|
28b10e397f | ||
|
|
6ff77c9fdf | ||
|
|
d98882d745 | ||
|
|
80977c6dee | ||
|
|
7c82d3ee67 | ||
|
|
0150fddb4c | ||
|
|
c8ec42a41c | ||
|
|
bff64a6291 | ||
|
|
a65fd873dd | ||
|
|
592fa59e88 | ||
|
|
02c2df65cd | ||
|
|
59bee679ca | ||
|
|
21129ae38c | ||
|
|
f1bbce58f3 | ||
|
|
8e173f486c | ||
|
|
e905762611 | ||
|
|
d38421dde8 | ||
|
|
6162e1f5ff | ||
|
|
08c5179869 | ||
|
|
bb39243da2 | ||
|
|
9bdc711324 | ||
|
|
a4351b0b77 | ||
|
|
416bff3daa | ||
|
|
07204c500d | ||
|
|
f5bc66521f | ||
|
|
fb0f8fcd0d | ||
|
|
61fbec858e | ||
|
|
25302de1f8 | ||
|
|
b86c1c241b | ||
|
|
2bf9e462fa | ||
|
|
57712737b2 | ||
|
|
c582e9cb0f | ||
|
|
d750b48879 | ||
|
|
708fe78d86 | ||
|
|
41311eb38d | ||
|
|
da971e4249 | ||
|
|
eb23ca0ca7 | ||
|
|
c9fe7900c3 | ||
|
|
9d6a78f7f4 | ||
|
|
4da63c5395 | ||
|
|
b5f892bcdb | ||
|
|
3135487931 | ||
|
|
9291ab55b8 | ||
|
|
1db86a0810 | ||
|
|
fb832e6ffe | ||
|
|
ca6248cfd3 | ||
|
|
b9c0676a01 | ||
|
|
731f156f50 | ||
|
|
b2a50db1df | ||
|
|
6bd0c7fc2b | ||
|
|
4e674ab9a0 | ||
|
|
cbfeb59fb3 | ||
|
|
8db559148c | ||
|
|
7403c9f80e | ||
|
|
f3d654a733 | ||
|
|
bafc859f75 | ||
|
|
bf63824aae | ||
|
|
32d37cebed | ||
|
|
d2ebaa43ec | ||
|
|
045af3a614 | ||
|
|
a96fdcf0bd | ||
|
|
fd934f1434 | ||
|
|
b2fe7e49fd | ||
|
|
22392f23f2 | ||
|
|
3ce98d4163 | ||
|
|
c07b5ae858 | ||
|
|
dbe116c255 | ||
|
|
9d1a52978c | ||
|
|
0d3c6b9d99 | ||
|
|
71f74a10f7 | ||
|
|
0bd75469ba | ||
|
|
1591294b7a | ||
|
|
f9cbd3c457 | ||
|
|
66ca9f5ce0 |
@@ -1,2 +0,0 @@
|
||||
---
|
||||
BUNDLE_WITHOUT: ""
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
*~
|
||||
coverage/*
|
||||
*.sqlite3
|
||||
.bundle
|
||||
rdoc/*
|
||||
pkg
|
||||
log
|
||||
|
||||
@@ -1,34 +1,77 @@
|
||||
== 1.1.pre
|
||||
== 1.1.rc2
|
||||
|
||||
* enhancements
|
||||
* Rails 3 compatibility.
|
||||
* All controllers and views are namespaced, for example: Devise::SessionsController and "devise/sessions".
|
||||
* Devise.orm is deprecated. This reduces the required API to hook your ORM with devise.
|
||||
* Use metal for failure app.
|
||||
* HTML e-mails now have proper formatting.
|
||||
* Do not remove options from Datamapper and MongoMapper in find.
|
||||
* Allow to give :skip and :controllers in routes.
|
||||
* Move trackable logic to the model.
|
||||
* E-mails now use any template available in the filesystem. Easy to create multipart e-mails.
|
||||
* E-mails asks headers_for in the model to set the proper headers.
|
||||
* Allow to specify haml in devise_views.
|
||||
* Compatibility with Datamapper and Mongoid.
|
||||
* Make config.devise available on config/application.rb.
|
||||
* TokenAuthenticatable now works with HTTP Basic Auth.
|
||||
* Allow :unlock_strategy to be :none and add :lock_strategy which can be :failed_attempts or none. Setting those values to :none means that you want to handle lock and unlocking by yourself.
|
||||
* No need to append ?unauthenticated=true in URLs anymore since Flash was moved to a middleware in Rails 3.
|
||||
* All messages under devise.sessions, except :signed_in and :signed_out, should be moved to devise.failure.
|
||||
* Allow to set cookie domain for the remember token. (by github.com/mantas)
|
||||
* Added navigational formats to specify when it should return a 302 and when a 401.
|
||||
* Added authenticate(scope) support in routes (by github.com/wildchild)
|
||||
* Added after_update_path_for to registrations controller (by github.com/thedelchop)
|
||||
* Allow the mailer object to be replaced through config.mailer = "MyOwnMailer"
|
||||
|
||||
* bug fix
|
||||
* Fix a bug where session was timing out on sign out
|
||||
|
||||
* deprecations
|
||||
* bcrypt is now the default encryptor
|
||||
* devise.mailer.confirmations_instructions now should be devise.mailer.confirmations_instructions.subject
|
||||
* devise.mailer.user.confirmations_instructions now should be devise.mailer.confirmations_instructions.user_subject
|
||||
* Generators now use Rails 3 syntax (devise:install) instead of devise_install
|
||||
|
||||
== 1.1.rc
|
||||
|
||||
* enhancements
|
||||
* Rails 3 compatibility
|
||||
* All controllers and views are namespaced, for example: Devise::SessionsController and "devise/sessions"
|
||||
* Devise.orm is deprecated. This reduces the required API to hook your ORM with devise
|
||||
* Use metal for failure app
|
||||
* HTML e-mails now have proper formatting
|
||||
* Allow to give :skip and :controllers in routes
|
||||
* Move trackable logic to the model
|
||||
* E-mails now use any template available in the filesystem. Easy to create multipart e-mails
|
||||
* E-mails asks headers_for in the model to set the proper headers
|
||||
* Allow to specify haml in devise_views
|
||||
* Compatibility with Datamapper and Mongoid
|
||||
* Make config.devise available on config/application.rb
|
||||
* TokenAuthenticatable now works with HTTP Basic Auth
|
||||
* Allow :unlock_strategy to be :none and add :lock_strategy which can be :failed_attempts or none. Setting those values to :none means that you want to handle lock and unlocking by yourself
|
||||
* No need to append ?unauthenticated=true in URLs anymore since Flash was moved to a middleware in Rails 3
|
||||
* :activatable is included by default in your models
|
||||
|
||||
* bug fix
|
||||
* Fix a bug with STI
|
||||
|
||||
* deprecations
|
||||
* Rails 3 compatible only
|
||||
* Removed support for MongoMapper
|
||||
* Scoped views are no longer "sessions/users/new". Now use "users/sessions/new"
|
||||
* Devise.orm is deprecated, just require "devise/orm/YOUR_ORM" instead
|
||||
* Devise.default_url_options is deprecated, just modify ApplicationController.default_url_options
|
||||
* All messages under devise.sessions, except :signed_in and :signed_out, should be moved to devise.failure
|
||||
* :as and :scope in routes is deprecated. Use :path and :singular instead
|
||||
|
||||
== 1.0.8
|
||||
|
||||
* enhancements
|
||||
* Support for latest MongoMapper
|
||||
* Added anybody_signed_in? helper (by github.com/SSDany)
|
||||
|
||||
* bug fix
|
||||
* confirmation_required? is properly honored on active? calls. (by github.com/paulrosania)
|
||||
|
||||
== 1.0.7
|
||||
|
||||
* bug fix
|
||||
* Ensure password confirmation is always required
|
||||
|
||||
* deprecations
|
||||
* authenticatable was deprecated and renamed to database_authenticatable
|
||||
* confirmable is not included by default on generation
|
||||
|
||||
== 1.0.6
|
||||
|
||||
* bug fix
|
||||
* Do not allow unlockable strategies based on time to access a controller.
|
||||
* Do not send unlockable email several times.
|
||||
|
||||
* deprecations
|
||||
* Rails 3 compatible only.
|
||||
* Scoped views are no longer "sessions/users/new". Now use "users/sessions/new".
|
||||
* Devise.orm is deprecated, just require "devise/orm/YOUR_ORM" instead.
|
||||
* Devise.default_url_options is deprecated, just modify ApplicationController.default_url_options.
|
||||
* All messages under devise.sessions, except :signed_in and :signed_out, should be moved to devise.failure.
|
||||
* Allow controller to upstram custom! failures to Warden.
|
||||
|
||||
== 1.0.5
|
||||
|
||||
|
||||
28
Gemfile
28
Gemfile
@@ -1,10 +1,10 @@
|
||||
source "http://gemcutter.org"
|
||||
source "http://rubygems.org"
|
||||
|
||||
# Need to install Rails from source
|
||||
gem "rails", "3.0.0.beta2"
|
||||
gem "warden", "0.10.3"
|
||||
gem "sqlite3-ruby", :require => "sqlite3"
|
||||
gem "webrat", "0.7"
|
||||
gem "rails", "3.0.0.beta4"
|
||||
gem "warden", "0.10.7"
|
||||
gem "sqlite3-ruby"
|
||||
gem "webrat", "0.7.0"
|
||||
gem "mocha", :require => false
|
||||
gem "bcrypt-ruby", :require => "bcrypt"
|
||||
|
||||
@@ -13,15 +13,17 @@ if RUBY_VERSION < '1.9'
|
||||
end
|
||||
|
||||
group :mongoid do
|
||||
gem "mongo", ">= 0.18.3"
|
||||
gem "mongo_ext", ">= 0.18.3", :require => false
|
||||
gem "mongo"
|
||||
gem "mongoid", :git => "git://github.com/durran/mongoid.git"
|
||||
gem "bson_ext"
|
||||
end
|
||||
|
||||
group :data_mapper do
|
||||
gem "do_sqlite3", '>= 0.10.1'
|
||||
gem "dm-core", :git => "git://github.com/datamapper/dm-core.git"
|
||||
gem "dm-validations", :git => "git://github.com/datamapper/dm-more.git"
|
||||
gem "dm-timestamps", :git => "git://github.com/datamapper/dm-more.git"
|
||||
gem "dm-rails", :git => "git://github.com/datamapper/dm-rails.git"
|
||||
end
|
||||
gem 'dm-core', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-core'
|
||||
gem 'dm-migrations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-migrations'
|
||||
gem 'dm-sqlite-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-sqlite-adapter'
|
||||
gem 'dm-validations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-validations'
|
||||
gem 'dm-serializer', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-serializer'
|
||||
gem 'dm-timestamps', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-timestamps'
|
||||
gem 'dm-rails', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-rails'
|
||||
end
|
||||
|
||||
157
README.rdoc
157
README.rdoc
@@ -13,63 +13,87 @@ Right now it's composed of 11 modules:
|
||||
* Token Authenticatable: signs in an 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.
|
||||
* Confirmable: sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
|
||||
* Recoverable: resets the user password and sends reset instructions.
|
||||
* Registerable: handles signing up users through a registration process.
|
||||
* Registerable: handles signing up users through a registration process, also allowing them to edit and destroy their account.
|
||||
* Rememberable: manages generating and clearing a token for remembering the user from a saved cookie.
|
||||
* Trackable: tracks sign in count, timestamps and IP address.
|
||||
* Timeoutable: expires sessions that have no activity in a specified period of time.
|
||||
* Validatable: provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
|
||||
* Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
|
||||
* Activatable: use this module if you need to activate accounts by means other than confirmation.
|
||||
|
||||
== Examples
|
||||
|
||||
* Example application using Devise at http://github.com/plataformatec/devise_example
|
||||
* Example Rails 2.3 web app combining subdomains with Devise at http://github.com/fortuity/subdomain-authentication
|
||||
|
||||
== Dependencies
|
||||
|
||||
Devise is based on Warden (http://github.com/hassox/warden), a Rack Authentication Framework. You need to install Warden as a gem. Please ensure you have it installed in order to use Devise (see installation below).
|
||||
|
||||
== Installation
|
||||
|
||||
Devise master branch now supports Rails 3 and is NOT backward compatible. If you are using Rails 3.0.0 beta gem, you need to install devise as a gem:
|
||||
=== Rails 3 beta 4
|
||||
|
||||
sudo gem install devise --version=1.1.pre4
|
||||
To use Devise with Rails 3 beta 4, please use it straight from the git repository, by adding it to your Gemfile:
|
||||
|
||||
However, if you are using Rails edge, from the git repository, you also need to use Devise from the git repository. After you install Devise and add it to your gemfile, you need to run the generator:
|
||||
gem "devise", :git => "git://github.com/plataformatec/devise.git"
|
||||
|
||||
rails generate devise_install
|
||||
Then follow the same steps as below.
|
||||
|
||||
And you're ready to go. The generator will install an initializer which describes ALL Devise's configuration options, so be sure to take a look at it and at the documentation as well:
|
||||
=== Rails 3 beta 3
|
||||
|
||||
http://rdoc.info/projects/plataformatec/devise
|
||||
Devise master branch now supports Rails 3 and is NOT backward compatible. You can use the latest Rails 3 beta gem with Devise latest gem:
|
||||
|
||||
== Rails 2.3
|
||||
gem install devise --version=1.1.rc1
|
||||
|
||||
After you install Devise and add it to your Gemfile, you need to run the generator:
|
||||
|
||||
rails generate devise:install
|
||||
|
||||
The generator will install an initializer which describes ALL Devise's configuration options and you MUST take a look at it. When you are done, you are ready to add Devise to any of your models using the generator:
|
||||
|
||||
rails generate devise MODEL
|
||||
|
||||
Replace MODEL by the class name you want to add devise, like User, Admin, etc. This will create a model (if one does not exist) and configure it with default Devise modules. The generator will also create a migration file (if your ORM support them) and configure your routes. Continue reading this file to understand exactly what the generator produces and how to use it.
|
||||
|
||||
=== Rails 2.3
|
||||
|
||||
If you want to use the Rails 2.3.x version, you should do:
|
||||
|
||||
sudo gem install devise --version=1.0.4
|
||||
gem install devise --version=1.0.7
|
||||
|
||||
Or checkout from the v1.0 branch:
|
||||
And please check the README at the v1.0 branch since this one is based on Rails 3:
|
||||
|
||||
http://github.com/plataformatec/devise/tree/v1.0
|
||||
|
||||
== Ecosystem
|
||||
|
||||
Devise ecosystem is growing solid day after day. If you just need a walkthrough about setting up Devise, this README will work great. But if you need more documentation and resources, please check both the wiki and rdoc:
|
||||
|
||||
* http://rdoc.info/projects/plataformatec/devise
|
||||
* http://wiki.github.com/plataformatec/devise
|
||||
|
||||
Both links above are for Devise with Rails 3. 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.
|
||||
|
||||
Another great way to learn Devise are Ryan Bates' screencasts:
|
||||
|
||||
* http://railscasts.com/episodes/209-introducing-devise
|
||||
* http://railscasts.com/episodes/210-customizing-devise
|
||||
|
||||
And a few example applications:
|
||||
|
||||
* Rails 2.3 app using Devise at http://github.com/plataformatec/devise_example
|
||||
* Rails 2.3 app using Devise with subdomains at http://github.com/fortuity/subdomain-authentication
|
||||
* Rails 3.0 app with Mongoid at http://github.com/fortuity/rails3-mongoid-devise
|
||||
|
||||
Finally, Devise also has several extensions built by the community. Don't forget to check them at the end of this README. If you want to write an extension on your own, you should also check Warden (http://github.com/hassox/warden), a Rack Authentication Framework which Devise depends on.
|
||||
|
||||
== Basic Usage
|
||||
|
||||
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration. You MUST also check out the *Generators* section below to help you start.
|
||||
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration.
|
||||
|
||||
Devise must be set up within the model (or models) you want to use. Devise routes must be created inside your config/routes.rb file.
|
||||
|
||||
We're assuming here you want a User model with some Devise modules, as outlined below:
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
end
|
||||
|
||||
After you choose which modules to use, you need to set up your migrations. Luckily, Devise has some helpers to save you from this boring work:
|
||||
|
||||
create_table :users do |t|
|
||||
t.authenticatable
|
||||
t.database_authenticatable
|
||||
t.confirmable
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
@@ -85,13 +109,13 @@ Configure your routes after setting up your model. Open your config/routes.rb fi
|
||||
|
||||
This will use your User model to create a set of needed routes (you can see them by running `rake routes`).
|
||||
|
||||
Options for configuring your routes include :class_name (to set the class for that route), :path_prefix, :as and :path_names, where the last two have the same meaning as in common routes. The available :path_names are:
|
||||
Options for configuring your routes include :class_name (to set the class for that route), :path_prefix, :path and :path_names, where the last two have the same meaning as in common routes. The available :path_names are:
|
||||
|
||||
devise_for :users, :as => "usuarios", :path_names => { :sign_in => 'login', :sign_out => 'logout', :sign_up => 'register', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock' }
|
||||
devise_for :users, :path => "usuarios", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
|
||||
|
||||
Be sure to check devise_for documentation for details.
|
||||
|
||||
After creating your models and routes, run your migrations, and you are ready to go! But don't stop reading here, we still have a lot to tell you:
|
||||
This exactly what the devise generator produces for you: model, routes and migrations. Don't forget to run rake db:migrate and you are ready to go! But don't stop reading here, we still have a lot to tell you.
|
||||
|
||||
== Controller filters and helpers
|
||||
|
||||
@@ -127,16 +151,17 @@ Devise allows you to set up as many roles as you want. For example, you may have
|
||||
|
||||
# Create a migration with the required fields
|
||||
create_table :admins do |t|
|
||||
t.authenticatable
|
||||
t.database_authenticatable
|
||||
t.lockable
|
||||
t.trackable
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
# Inside your Admin model
|
||||
devise :authenticatable, :trackable, :timeoutable, :lockable
|
||||
devise :database_authenticatable, :trackable, :timeoutable, :lockable
|
||||
|
||||
# Inside your routes
|
||||
devise_for :admin
|
||||
devise_for :admins
|
||||
|
||||
# Inside your protected controller
|
||||
before_filter :authenticate_admin!
|
||||
@@ -146,52 +171,40 @@ Devise allows you to set up as many roles as you want. For example, you may have
|
||||
current_admin
|
||||
admin_session
|
||||
|
||||
== Generators
|
||||
|
||||
Devise has generators to help you get started:
|
||||
|
||||
rails generate devise_install
|
||||
|
||||
This will generate an initializer, with a description of all configuration values.
|
||||
|
||||
You can also generate models:
|
||||
|
||||
rails generate devise Model
|
||||
|
||||
This will create a model named "Model" configured with default Devise modules and attr_accessible set for default fields. The generator will also create the migration and configure your routes for Devise.
|
||||
|
||||
== Model configuration
|
||||
|
||||
The devise method in your models also accepts some options to configure its modules. For example, you can choose which encryptor to use in authenticatable:
|
||||
The devise method in your models also accepts some options to configure its modules. For example, you can choose which encryptor to use in database_authenticatable:
|
||||
|
||||
devise :authenticatable, :confirmable, :recoverable, :encryptor => :bcrypt
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :encryptor => :bcrypt
|
||||
|
||||
Besides :encryptor, you can define :pepper, :stretches, :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.
|
||||
Besides :encryptor, you can define :pepper, :stretches, :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.
|
||||
|
||||
== Configuring controllers and views
|
||||
== Configuring views
|
||||
|
||||
We built Devise to help you quickly develop an application that uses authentication. We don't want to be in your way when you need to customize it.
|
||||
We built Devise to help you quickly develop an application that uses authentication. However, we don't want to be in your way when you need to customize it.
|
||||
|
||||
Since Devise is an engine, all its default views are packaged inside the gem. The default views will get you started but you may want to customize them. Devise has a generator to copy the default views to your application. After they've been copied to your application, you can make changes as required:
|
||||
Since Devise is an engine, all its views are packaged inside the gem. These views will help you get started, but after sometime you may want to change them. If this is the case, you just need to invoke the following generator, and it will copy all views to your application:
|
||||
|
||||
rails generate devise_views
|
||||
rails generate devise:views
|
||||
|
||||
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. You may need different views for each role. Devise offers an easy way to customize views for each role. Just set config.scoped_views to "true" inside "config/initializers/devise.rb".
|
||||
However, 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 scope 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".
|
||||
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".
|
||||
|
||||
Finally, if the customization at the views level is not enough, you can customize each controller by following these steps:
|
||||
== Configuring controllers
|
||||
|
||||
1) Create your custom controller, for example a Admins::SessionsController:
|
||||
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:
|
||||
|
||||
class Admins::SessionsController < Devise::SessionsController
|
||||
end
|
||||
|
||||
2) Tell the router to use this controller:
|
||||
2) Tell the router to use this controller:
|
||||
|
||||
devise_for :admins, :controllers => { :sessions = "admin/sessions" }
|
||||
devise_for :admins, :controllers => { :sessions => "admin/sessions" }
|
||||
|
||||
3) And finally, 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.
|
||||
|
||||
@@ -252,6 +265,20 @@ Devise implements encryption strategies for Clearance, Authlogic and Restful-Aut
|
||||
|
||||
Devise supports ActiveRecord (by default) and Mongoid. We offer experimental Datamapper support (with the limitation that the Devise test suite does not run completely with Datamapper). To choose other ORM, you just need to configure it in the initializer file.
|
||||
|
||||
== Extensions
|
||||
|
||||
Devise also has extensions created by the community:
|
||||
|
||||
* http://github.com/scambra/devise_invitable adds support to Devise for sending invitations by email.
|
||||
|
||||
* http://github.com/grimen/devise_facebook_connectable adds support for Facebook Connect authentication, and optionally fetching user info from Facebook in the same step.
|
||||
|
||||
* http://github.com/joshk/devise_imapable adds support for imap based authentication, excellent for internal apps when an LDAP server isn't available.
|
||||
|
||||
* http://github.com/cschiewek/devise_ldap_authenticatable adds support for LDAP authentication via simple bind.
|
||||
|
||||
Please consult their respective documentation for more information and requirements.
|
||||
|
||||
== TODO
|
||||
|
||||
Please refer to TODO file.
|
||||
@@ -263,15 +290,9 @@ Please refer to TODO file.
|
||||
|
||||
== Contributors
|
||||
|
||||
We have a long list of valued contributors. See the CHANGELOG or do `git shortlog -s -n` in the cloned repository.
|
||||
We have a long list of valued contributors. Check them all at:
|
||||
|
||||
== Devise extensions
|
||||
|
||||
* http://github.com/scambra/devise_invitable adds support to Devise for sending invitations by email.
|
||||
|
||||
* http://github.com/grimen/devise_facebook_connectable adds support for Facebook Connect authentication, and optionally fetching user info from Facebook in the same step.
|
||||
|
||||
* http://github.com/joshk/devise_imapable adds support for imap based authentication, excellent for internal apps when an LDAP server isn't available.
|
||||
http://github.com/plataformatec/devise/contributors
|
||||
|
||||
== Bugs and Feedback
|
||||
|
||||
@@ -283,10 +304,6 @@ For support, send an e-mail to the mailing list.
|
||||
|
||||
http://groups.google.com/group/plataformatec-devise
|
||||
|
||||
See the wiki for additional documentation and support.
|
||||
|
||||
http://wiki.github.com/plataformatec/devise/
|
||||
|
||||
== License
|
||||
|
||||
MIT License. Copyright 2009 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
MIT License. Copyright 2010 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
|
||||
5
Rakefile
5
Rakefile
@@ -45,10 +45,11 @@ begin
|
||||
s.authors = ['José Valim', 'Carlos Antônio']
|
||||
s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"]
|
||||
s.extra_rdoc_files = FileList["[A-Z]*"] - %w(Gemfile Rakefile)
|
||||
s.add_dependency("warden", "~> 0.10.3")
|
||||
s.add_dependency("warden", "~> 0.10.7")
|
||||
s.add_dependency("bcrypt-ruby", "~> 2.1.2")
|
||||
end
|
||||
|
||||
Jeweler::GemcutterTasks.new
|
||||
rescue LoadError
|
||||
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
||||
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
||||
end
|
||||
|
||||
2
TODO
2
TODO
@@ -1,3 +1,3 @@
|
||||
* Extract Activatable tests from Confirmable
|
||||
* Move integration tests to Capybara
|
||||
* Better ORM integration
|
||||
* Extract activatable models tests from confirmable
|
||||
|
||||
@@ -31,7 +31,7 @@ class Devise::RegistrationsController < ApplicationController
|
||||
def update
|
||||
if resource.update_with_password(params[resource_name])
|
||||
set_flash_message :notice, :updated
|
||||
redirect_to after_sign_in_path_for(self.resource)
|
||||
redirect_to after_update_path_for(resource)
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
render_with_scope :edit
|
||||
|
||||
17
app/helpers/devise_helper.rb
Normal file
17
app/helpers/devise_helper.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module DeviseHelper
|
||||
def devise_error_messages!
|
||||
return "" if resource.errors.empty?
|
||||
|
||||
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
|
||||
sentence = "#{pluralize(resource.errors.count, "error")} prohibited this #{resource_name} from being saved:"
|
||||
|
||||
html = <<-HTML
|
||||
<div id="error_explanation">
|
||||
<h2>#{sentence}</h2>
|
||||
<ul>#{messages}</ul>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
68
app/mailers/devise/mailer.rb
Normal file
68
app/mailers/devise/mailer.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
attr_reader :devise_mapping, :resource
|
||||
|
||||
def confirmation_instructions(record)
|
||||
setup_mail(record, :confirmation_instructions)
|
||||
end
|
||||
|
||||
def reset_password_instructions(record)
|
||||
setup_mail(record, :reset_password_instructions)
|
||||
end
|
||||
|
||||
def unlock_instructions(record)
|
||||
setup_mail(record, :unlock_instructions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Configure default email options
|
||||
def setup_mail(record, action)
|
||||
@scope_name = Devise::Mapping.find_scope!(record)
|
||||
@devise_mapping = Devise.mappings[@scope_name]
|
||||
@resource = instance_variable_set("@#{@devise_mapping.name}", record)
|
||||
|
||||
template_path = ["devise/mailer"]
|
||||
template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
|
||||
|
||||
headers = {
|
||||
:subject => translate(@devise_mapping, action),
|
||||
:from => mailer_sender(@devise_mapping),
|
||||
:to => record.email,
|
||||
:template_path => template_path
|
||||
}
|
||||
|
||||
headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
|
||||
mail(headers)
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
|
||||
# based on the current mapping:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# user_subject: '...'
|
||||
#
|
||||
# If one does not exist, it fallbacks to ActionMailer default:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# subject: '...'
|
||||
#
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
|
||||
:default => [:subject, key.to_s.humanize])
|
||||
end
|
||||
end
|
||||
@@ -1,61 +0,0 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
|
||||
attr_reader :devise_mapping, :resource
|
||||
|
||||
def confirmation_instructions(record)
|
||||
setup_mail(record, :confirmation_instructions)
|
||||
end
|
||||
|
||||
def reset_password_instructions(record)
|
||||
setup_mail(record, :reset_password_instructions)
|
||||
end
|
||||
|
||||
def unlock_instructions(record)
|
||||
setup_mail(record, :unlock_instructions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Configure default email options
|
||||
def setup_mail(record, action)
|
||||
@scope_name = Devise::Mapping.find_scope!(record)
|
||||
@devise_mapping = Devise.mappings[@scope_name]
|
||||
@resource = instance_variable_set("@#{@devise_mapping.name}", record)
|
||||
|
||||
template_path = ["devise/mailer"]
|
||||
template_path.unshift "#{@devise_mapping.as}/mailer" if self.class.scoped_views?
|
||||
|
||||
headers = {
|
||||
:subject => translate(@devise_mapping, action),
|
||||
:from => mailer_sender(@devise_mapping),
|
||||
:to => record.email,
|
||||
:template_path => template_path
|
||||
}
|
||||
|
||||
headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
|
||||
mail(headers)
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
# Setup subject namespaced by model. It means you're able to setup your
|
||||
# messages using specific resource scope, or provide a default one.
|
||||
# Example (i18n locale file):
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions: '...'
|
||||
# user:
|
||||
# confirmation_instructions: '...'
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}.#{key}", :scope => [:devise, :mailer], :default => key)
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => confirmation_path(resource_name)) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.submit "Resend confirmation instructions" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.submit "Change my password" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => password_path(resource_name)) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.submit "Send me reset password instructions" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i></p>
|
||||
<p><%= f.password_field :current_password %></p>
|
||||
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password %></p>
|
||||
|
||||
<p><%= f.submit "Update" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<h2>Sign up</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.submit "Sign up" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<h2>Sign in</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %>
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p>
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && controller_name != 'unlocks' %>
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource_name, resource, :url => unlock_path(resource_name)) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.submit "Resend unlock instructions" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -24,13 +24,16 @@ en:
|
||||
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
|
||||
confirmed: 'Your account was successfully confirmed. You are now signed in.'
|
||||
registrations:
|
||||
signed_up: 'You have signed up successfully.'
|
||||
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
|
||||
updated: 'You updated your account successfully.'
|
||||
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
|
||||
unlocks:
|
||||
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
|
||||
unlocked: 'Your account was successfully unlocked. You are now signed in.'
|
||||
mailer:
|
||||
confirmation_instructions: 'Confirmation instructions'
|
||||
reset_password_instructions: 'Reset password instructions'
|
||||
unlock_instructions: 'Unlock Instructions'
|
||||
confirmation_instructions:
|
||||
subject: 'Confirmation instructions'
|
||||
reset_password_instructions:
|
||||
subject: 'Reset password instructions'
|
||||
unlock_instructions:
|
||||
subject: 'Unlock Instructions'
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{devise}
|
||||
s.version = "1.1.rc0"
|
||||
s.version = "1.1.rc2"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Jos\303\251 Valim", "Carlos Ant\303\264nio"]
|
||||
s.date = %q{2010-04-03}
|
||||
s.date = %q{2010-06-23}
|
||||
s.description = %q{Flexible authentication solution for Rails with Warden}
|
||||
s.email = %q{contact@plataformatec.com.br}
|
||||
s.extra_rdoc_files = [
|
||||
@@ -30,7 +30,8 @@ Gem::Specification.new do |s|
|
||||
"app/controllers/devise/registrations_controller.rb",
|
||||
"app/controllers/devise/sessions_controller.rb",
|
||||
"app/controllers/devise/unlocks_controller.rb",
|
||||
"app/models/devise/mailer.rb",
|
||||
"app/helpers/devise_helper.rb",
|
||||
"app/mailers/devise/mailer.rb",
|
||||
"app/views/devise/confirmations/new.html.erb",
|
||||
"app/views/devise/mailer/confirmation_instructions.html.erb",
|
||||
"app/views/devise/mailer/reset_password_instructions.html.erb",
|
||||
@@ -57,12 +58,12 @@ Gem::Specification.new do |s|
|
||||
"lib/devise/encryptors/sha512.rb",
|
||||
"lib/devise/failure_app.rb",
|
||||
"lib/devise/hooks/activatable.rb",
|
||||
"lib/devise/hooks/forgetable.rb",
|
||||
"lib/devise/hooks/rememberable.rb",
|
||||
"lib/devise/hooks/timeoutable.rb",
|
||||
"lib/devise/hooks/trackable.rb",
|
||||
"lib/devise/mapping.rb",
|
||||
"lib/devise/models.rb",
|
||||
"lib/devise/models/activatable.rb",
|
||||
"lib/devise/models/authenticatable.rb",
|
||||
"lib/devise/models/confirmable.rb",
|
||||
"lib/devise/models/database_authenticatable.rb",
|
||||
@@ -78,6 +79,7 @@ Gem::Specification.new do |s|
|
||||
"lib/devise/orm/active_record.rb",
|
||||
"lib/devise/orm/data_mapper.rb",
|
||||
"lib/devise/orm/mongoid.rb",
|
||||
"lib/devise/path_checker.rb",
|
||||
"lib/devise/rails.rb",
|
||||
"lib/devise/rails/routes.rb",
|
||||
"lib/devise/rails/warden_compat.rb",
|
||||
@@ -89,17 +91,20 @@ Gem::Specification.new do |s|
|
||||
"lib/devise/strategies/token_authenticatable.rb",
|
||||
"lib/devise/test_helpers.rb",
|
||||
"lib/devise/version.rb",
|
||||
"lib/generators/devise/devise_generator.rb",
|
||||
"lib/generators/devise/templates/migration.rb",
|
||||
"lib/generators/devise_install/devise_install_generator.rb",
|
||||
"lib/generators/devise_install/templates/README",
|
||||
"lib/generators/devise_install/templates/devise.rb",
|
||||
"lib/generators/devise_views/devise_views_generator.rb"
|
||||
"lib/generators/devise/devise/devise_generator.rb",
|
||||
"lib/generators/devise/devise/templates/migration.rb",
|
||||
"lib/generators/devise/install/install_generator.rb",
|
||||
"lib/generators/devise/install/templates/README",
|
||||
"lib/generators/devise/install/templates/devise.rb",
|
||||
"lib/generators/devise/views/views_generator.rb",
|
||||
"lib/generators/devise_generator.rb",
|
||||
"lib/generators/devise_install_generator.rb",
|
||||
"lib/generators/devise_views_generator.rb"
|
||||
]
|
||||
s.homepage = %q{http://github.com/plataformatec/devise}
|
||||
s.rdoc_options = ["--charset=UTF-8"]
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = %q{1.3.6}
|
||||
s.rubygems_version = %q{1.3.7}
|
||||
s.summary = %q{Flexible authentication solution for Rails with Warden}
|
||||
s.test_files = [
|
||||
"test/controllers/helpers_test.rb",
|
||||
@@ -108,6 +113,7 @@ Gem::Specification.new do |s|
|
||||
"test/devise_test.rb",
|
||||
"test/encryptors_test.rb",
|
||||
"test/failure_app_test.rb",
|
||||
"test/integration/authenticatable_test.rb",
|
||||
"test/integration/confirmable_test.rb",
|
||||
"test/integration/database_authenticatable_test.rb",
|
||||
"test/integration/http_authenticatable_test.rb",
|
||||
@@ -136,6 +142,7 @@ Gem::Specification.new do |s|
|
||||
"test/orm/data_mapper.rb",
|
||||
"test/orm/mongoid.rb",
|
||||
"test/rails_app/app/active_record/admin.rb",
|
||||
"test/rails_app/app/active_record/shim.rb",
|
||||
"test/rails_app/app/active_record/user.rb",
|
||||
"test/rails_app/app/controllers/admins_controller.rb",
|
||||
"test/rails_app/app/controllers/application_controller.rb",
|
||||
@@ -143,9 +150,11 @@ Gem::Specification.new do |s|
|
||||
"test/rails_app/app/controllers/sessions_controller.rb",
|
||||
"test/rails_app/app/controllers/users_controller.rb",
|
||||
"test/rails_app/app/data_mapper/admin.rb",
|
||||
"test/rails_app/app/data_mapper/shim.rb",
|
||||
"test/rails_app/app/data_mapper/user.rb",
|
||||
"test/rails_app/app/helpers/application_helper.rb",
|
||||
"test/rails_app/app/mongoid/admin.rb",
|
||||
"test/rails_app/app/mongoid/shim.rb",
|
||||
"test/rails_app/app/mongoid/user.rb",
|
||||
"test/rails_app/config/application.rb",
|
||||
"test/rails_app/config/boot.rb",
|
||||
@@ -156,6 +165,7 @@ Gem::Specification.new do |s|
|
||||
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
||||
"test/rails_app/config/initializers/devise.rb",
|
||||
"test/rails_app/config/initializers/inflections.rb",
|
||||
"test/rails_app/config/initializers/secret_token.rb",
|
||||
"test/rails_app/config/routes.rb",
|
||||
"test/rails_app/db/migrate/20100401102949_create_tables.rb",
|
||||
"test/rails_app/db/schema.rb",
|
||||
@@ -173,13 +183,16 @@ Gem::Specification.new do |s|
|
||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||
s.specification_version = 3
|
||||
|
||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_runtime_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require 'active_support/core_ext/numeric/time'
|
||||
require 'active_support/dependencies'
|
||||
|
||||
module Devise
|
||||
autoload :FailureApp, 'devise/failure_app'
|
||||
autoload :PathChecker, 'devise/path_checker'
|
||||
autoload :Schema, 'devise/schema'
|
||||
autoload :TestHelpers, 'devise/test_helpers'
|
||||
|
||||
@@ -47,6 +49,10 @@ module Devise
|
||||
:bcrypt => 60
|
||||
}
|
||||
|
||||
# Custom domain for cookies. Not set by default
|
||||
mattr_accessor :cookie_domain
|
||||
@@cookie_domain = false
|
||||
|
||||
# Used to encrypt password. Please generate one with rake secret.
|
||||
mattr_accessor :pepper
|
||||
@@pepper = nil
|
||||
@@ -93,7 +99,7 @@ module Devise
|
||||
|
||||
# Used to define the password encryption algorithm.
|
||||
mattr_accessor :encryptor
|
||||
@@encryptor = :sha1
|
||||
@@encryptor = nil
|
||||
|
||||
# Store scopes mappings.
|
||||
mattr_accessor :mappings
|
||||
@@ -143,6 +149,9 @@ module Devise
|
||||
mattr_accessor :token_authentication_key
|
||||
@@token_authentication_key = :auth_token
|
||||
|
||||
mattr_accessor :navigational_formats
|
||||
@@navigational_formats = [:html]
|
||||
|
||||
# Private methods to interface with Warden.
|
||||
mattr_accessor :warden_config
|
||||
@@warden_config = nil
|
||||
@@ -154,16 +163,24 @@ module Devise
|
||||
yield self
|
||||
end
|
||||
|
||||
# Get the mailer class from the mailer reference object.
|
||||
def self.mailer
|
||||
@@mailer_ref.get
|
||||
end
|
||||
|
||||
# Set the mailer reference object to access the mailer.
|
||||
def self.mailer=(class_name)
|
||||
@@mailer_ref = ActiveSupport::Dependencies.ref(class_name)
|
||||
end
|
||||
self.mailer = "Devise::Mailer"
|
||||
|
||||
# Register a model in Devise. You can call this manually if you don't want
|
||||
# to use devise routes. Check devise_for in routes to know which options
|
||||
# are available.
|
||||
def self.register(resource, options)
|
||||
def self.add_model(resource, options)
|
||||
mapping = Devise::Mapping.new(resource, options)
|
||||
self.mappings[mapping.name] = mapping
|
||||
self.default_scope ||= mapping.name
|
||||
|
||||
warden_config.default_scope ||= mapping.name
|
||||
warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
|
||||
mapping
|
||||
end
|
||||
|
||||
@@ -233,7 +250,17 @@ module Devise
|
||||
# A method used internally to setup warden manager from the Rails initialize
|
||||
# block.
|
||||
def self.configure_warden! #:nodoc:
|
||||
@@warden_config_block.try :call, Devise.warden_config
|
||||
@@warden_configured ||= begin
|
||||
warden_config.failure_app = Devise::FailureApp
|
||||
warden_config.default_scope = Devise.default_scope
|
||||
|
||||
Devise.mappings.each_value do |mapping|
|
||||
warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
|
||||
end
|
||||
|
||||
@@warden_config_block.try :call, Devise.warden_config
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Generate a friendly string randomically to be used as token.
|
||||
|
||||
@@ -5,8 +5,8 @@ module Devise
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
helper_method :warden, :signed_in?, :devise_controller?,
|
||||
*Devise.mappings.keys.map { |m| [:"current_#{m}", :"#{m}_signed_in?"] }.flatten
|
||||
helper_method :warden, :signed_in?, :devise_controller?, :anybody_signed_in?,
|
||||
*Devise.mappings.keys.map { |m| [:"current_#{m}", :"#{m}_signed_in?", :"#{m}_session"] }.flatten
|
||||
end
|
||||
|
||||
# The main accessor for the warden proxy instance
|
||||
@@ -29,6 +29,12 @@ module Devise
|
||||
warden.authenticate?(:scope => scope)
|
||||
end
|
||||
|
||||
# Check if the any scope is signed in session, without running
|
||||
# authentication hooks.
|
||||
def anybody_signed_in?
|
||||
Devise.mappings.keys.any? { |scope| signed_in?(scope) }
|
||||
end
|
||||
|
||||
# Sign in an user that already was authenticated. This helper is useful for logging
|
||||
# users in after sign up.
|
||||
#
|
||||
@@ -102,6 +108,36 @@ module Devise
|
||||
respond_to?(home_path, true) ? send(home_path) : root_path
|
||||
end
|
||||
|
||||
# The default url to be used after updating a resource. This is used by all Devise
|
||||
# controllers and you can overwrite it in your ApplicationController to
|
||||
# provide a custom hook for a custom resource.
|
||||
#
|
||||
# By default, it first tries to find a resource_root_path, otherwise it
|
||||
# uses the root path. For a user scope, you can define the default url in
|
||||
# the following way:
|
||||
#
|
||||
# map.user_root '/users', :controller => 'users' # creates user_root_path
|
||||
#
|
||||
# map.resources :users do |users|
|
||||
# users.root # creates user_root_path
|
||||
# end
|
||||
#
|
||||
#
|
||||
# If none of these are defined, root_path is used. However, if this default
|
||||
# is not enough, you can customize it, for example:
|
||||
#
|
||||
# def after_update_path_for(resource)
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
# publisher_url
|
||||
# else
|
||||
# super
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def after_update_path_for(resource_or_scope)
|
||||
after_sign_in_path_for(resource_or_scope)
|
||||
end
|
||||
|
||||
# Method used by sessions controller to sign out an user. You can overwrite
|
||||
# it in your ApplicationController to provide a custom hook for a custom
|
||||
# scope. Notice that differently from +after_sign_in_path_for+ this method
|
||||
|
||||
@@ -9,6 +9,7 @@ module Devise
|
||||
|
||||
included do
|
||||
unloadable
|
||||
helper DeviseHelper
|
||||
|
||||
helpers = %w(resource scope_name resource_name
|
||||
resource_class devise_mapping devise_controller?)
|
||||
|
||||
@@ -22,7 +22,7 @@ module Devise
|
||||
|
||||
if self.class.scoped_views?
|
||||
begin
|
||||
render :template => "#{devise_mapping.as}/#{controller_name}/#{action}"
|
||||
render :template => "#{devise_mapping.plural}/#{controller_name}/#{action}"
|
||||
rescue ActionView::MissingTemplate
|
||||
render :template => "#{controller_path}/#{action}"
|
||||
end
|
||||
|
||||
@@ -7,7 +7,6 @@ module Devise
|
||||
# Warning: it uses Devise's stretches configuration to port Authlogic's one. Should be set to 20 in the initializer to silumate
|
||||
# the default behavior.
|
||||
class AuthlogicSha512 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -15,7 +14,6 @@ module Devise
|
||||
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Devise
|
||||
# = BCrypt
|
||||
# Uses the BCrypt hash algorithm to encrypt passwords.
|
||||
class Bcrypt < Base
|
||||
|
||||
# Gererates a default password digest based on stretches, salt, pepper and the
|
||||
# incoming password. We don't strech it ourselves since BCrypt does so internally.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -15,7 +14,6 @@ module Devise
|
||||
def self.salt
|
||||
::BCrypt::Engine.generate_salt
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,13 +7,11 @@ module Devise
|
||||
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
||||
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
|
||||
class ClearanceSha1 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Devise
|
||||
# = Sha1
|
||||
# Uses the Sha1 hash algorithm to encrypt passwords.
|
||||
class Sha1 < Base
|
||||
|
||||
# Gererates a default password digest based on stretches, salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -14,14 +13,13 @@ module Devise
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Devise
|
||||
# = Sha512
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -14,14 +13,13 @@ module Devise
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,7 @@ module Devise
|
||||
include ActionController::RackDelegation
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirecting
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
delegate :flash, :to => :request
|
||||
|
||||
@@ -63,7 +64,7 @@ module Devise
|
||||
end
|
||||
|
||||
def http_auth?
|
||||
request.authorization
|
||||
!Devise.navigational_formats.include?(request.format.to_sym) || request.xhr?
|
||||
end
|
||||
|
||||
def http_auth_body
|
||||
@@ -96,7 +97,7 @@ module Devise
|
||||
# yet, but we still need to store the uri based on scope, so different scopes
|
||||
# would never use the same uri to redirect.
|
||||
def store_location!
|
||||
session[:"#{scope}_return_to"] = attempted_path if request && request.get?
|
||||
session[:"#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
# Deny user access whenever his account is not active yet.
|
||||
# Deny user access whenever his account is not active yet. All strategies that inherits from
|
||||
# Devise::Strategies::Authenticatable and uses the validate already check if the user is active?
|
||||
# before actively signing him in. However, we need this as hook to validate the user activity
|
||||
# in each request and in case the user is using other strategies beside Devise ones.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record && record.respond_to?(:active?) && !record.active?
|
||||
scope = options[:scope]
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => record.inactive_message
|
||||
end
|
||||
end
|
||||
|
||||
module Devise
|
||||
module Hooks
|
||||
# Overwrite Devise base strategy to only authenticate an user if it's active.
|
||||
# If you have an strategy that does not use Devise::Strategy::Base, don't worry
|
||||
# because the hook above will still avoid it to authenticate.
|
||||
module Activatable
|
||||
def success!(resource)
|
||||
if resource.respond_to?(:active?) && !resource.active?
|
||||
fail!(resource.inactive_message)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Devise::Strategies::Base.send :include, Devise::Hooks::Activatable
|
||||
end
|
||||
11
lib/devise/hooks/forgetable.rb
Normal file
11
lib/devise/hooks/forgetable.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, options|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
|
||||
warden.cookies.delete("remember_#{options[:scope]}_token", options)
|
||||
end
|
||||
end
|
||||
@@ -1,19 +1,9 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, scope|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
warden.cookies.delete "remember_#{scope}_token"
|
||||
end
|
||||
end
|
||||
|
||||
module Devise
|
||||
module Hooks
|
||||
# Overwrite success! in authentication strategies allowing users to be remembered.
|
||||
# We choose to implement this as an strategy hook instead of a Devise hook to avoid users
|
||||
# giving a remember_me access in strategies that should not create remember me tokens.
|
||||
# We choose to implement this as an strategy hook instead of a warden hook to allow a specific
|
||||
# strategy (like token authenticatable or facebook authenticatable) to turn off remember_me?
|
||||
# cookies.
|
||||
module Rememberable #:nodoc:
|
||||
def success!(resource)
|
||||
super
|
||||
@@ -21,15 +11,18 @@ module Devise
|
||||
if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
|
||||
resource.remember_me!
|
||||
|
||||
cookies.signed["remember_#{scope}_token"] = {
|
||||
configuration = {
|
||||
:value => resource.class.serialize_into_cookie(resource),
|
||||
:expires => resource.remember_expires_at,
|
||||
:path => "/"
|
||||
}
|
||||
|
||||
configuration[:domain] = resource.cookie_domain if resource.cookie_domain?
|
||||
cookies.signed["remember_#{scope}_token"] = configuration
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
def remember_me?
|
||||
valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
|
||||
@@ -38,4 +31,5 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
||||
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@
|
||||
# verify timeout in the following request.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
|
||||
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope)
|
||||
last_request_at = warden.session(scope)['last_request_at']
|
||||
|
||||
if record.timedout?(last_request_at)
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
path_checker = Devise::PathChecker.new(warden.env, scope)
|
||||
unless path_checker.signing_out?
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
end
|
||||
end
|
||||
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
|
||||
@@ -22,14 +22,15 @@ module Devise
|
||||
# # is the modules included in the class
|
||||
#
|
||||
class Mapping #:nodoc:
|
||||
attr_reader :name, :as, :controllers, :path_names, :path_prefix
|
||||
attr_reader :singular, :plural, :path, :controllers, :path_names, :path_prefix, :class_name
|
||||
alias :name :singular
|
||||
|
||||
# Loop through all mappings looking for a map that matches with the requested
|
||||
# path (ie /users/sign_in). If a path prefix is given, it's taken into account.
|
||||
def self.find_by_path(path)
|
||||
Devise.mappings.each_value do |mapping|
|
||||
route = path.split("/")[mapping.as_position]
|
||||
return mapping if route && mapping.as == route.to_sym
|
||||
route = path.split("/")[mapping.segment_position]
|
||||
return mapping if route && mapping.path == route.to_sym
|
||||
end
|
||||
nil
|
||||
end
|
||||
@@ -50,9 +51,22 @@ module Devise
|
||||
end
|
||||
|
||||
def initialize(name, options) #:nodoc:
|
||||
@as = (options.delete(:as) || name).to_sym
|
||||
@klass = (options.delete(:class_name) || name.to_s.classify).to_s
|
||||
@name = (options.delete(:scope) || name.to_s.singularize).to_sym
|
||||
if as = options.delete(:as)
|
||||
ActiveSupport::Deprecation.warn ":as is deprecated, please use :path instead."
|
||||
options[:path] ||= as
|
||||
end
|
||||
|
||||
if scope = options.delete(:scope)
|
||||
ActiveSupport::Deprecation.warn ":scope is deprecated, please use :singular instead."
|
||||
options[:singular] ||= scope
|
||||
end
|
||||
|
||||
@plural = name.to_sym
|
||||
@path = (options.delete(:path) || name).to_sym
|
||||
@singular = (options.delete(:singular) || name.to_s.singularize).to_sym
|
||||
|
||||
@class_name = (options.delete(:class_name) || name.to_s.classify).to_s
|
||||
@ref = ActiveSupport::Dependencies.ref(@class_name)
|
||||
|
||||
@path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
|
||||
|
||||
@@ -60,21 +74,18 @@ module Devise
|
||||
@controllers.merge!(options.delete(:controllers) || {})
|
||||
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names.merge!(:registration => "")
|
||||
@path_names.merge!(options.delete(:path_names) || {})
|
||||
end
|
||||
|
||||
# Return modules for the mapping.
|
||||
def modules
|
||||
@modules ||= to.devise_modules
|
||||
@modules ||= to.respond_to?(:devise_modules) ? to.devise_modules : []
|
||||
end
|
||||
|
||||
# Gives the class the mapping points to.
|
||||
# Reload mapped class each time when cache_classes is false.
|
||||
def to
|
||||
return @to if @to
|
||||
klass = @klass.constantize
|
||||
@to = klass if Rails.configuration.cache_classes
|
||||
klass
|
||||
@ref.get
|
||||
end
|
||||
|
||||
def strategies
|
||||
@@ -96,13 +107,13 @@ module Devise
|
||||
end
|
||||
|
||||
# Return in which position in the path prefix devise should find the as mapping.
|
||||
def as_position
|
||||
def segment_position
|
||||
self.path_prefix.count("/")
|
||||
end
|
||||
|
||||
# Returns the raw path using path_prefix and as.
|
||||
def path
|
||||
path_prefix + as.to_s
|
||||
def full_path
|
||||
path_prefix + path.to_s
|
||||
end
|
||||
|
||||
def authenticatable?
|
||||
|
||||
@@ -45,7 +45,7 @@ module Devise
|
||||
# for a complete description on those values.
|
||||
#
|
||||
def devise(*modules)
|
||||
raise "You need to give at least one Devise module" if modules.empty?
|
||||
include Devise::Models::Authenticatable
|
||||
options = modules.extract_options!
|
||||
|
||||
if modules.delete(:authenticatable)
|
||||
@@ -53,50 +53,28 @@ module Devise
|
||||
modules << :database_authenticatable
|
||||
end
|
||||
|
||||
if modules.delete(:activatable)
|
||||
ActiveSupport::Deprecation.warn ":activatable as module is deprecated. It's included in your model by default.", caller
|
||||
end
|
||||
|
||||
if modules.delete(:http_authenticatable)
|
||||
ActiveSupport::Deprecation.warn ":http_authenticatable as module is deprecated and is on by default. Revert by setting :http_authenticatable => false.", caller
|
||||
end
|
||||
|
||||
@devise_modules = Devise::ALL & modules.map(&:to_sym).uniq
|
||||
self.devise_modules += Devise::ALL & modules.map(&:to_sym).uniq
|
||||
|
||||
devise_modules_hook! do
|
||||
@devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
||||
devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
||||
options.each { |key, value| send(:"#{key}=", value) }
|
||||
end
|
||||
end
|
||||
|
||||
# Stores all modules included inside the model, so we are able to verify
|
||||
# which routes are needed.
|
||||
def devise_modules
|
||||
@devise_modules ||= []
|
||||
end
|
||||
|
||||
# The hook which is called inside devise. So your ORM can include devise
|
||||
# compatibility stuff.
|
||||
def devise_modules_hook!
|
||||
yield
|
||||
end
|
||||
|
||||
# Find an initialize a record setting an error if it can't be found.
|
||||
def find_or_initialize_with_error_by(attribute, value, error=:invalid)
|
||||
if value.present?
|
||||
conditions = { attribute => value }
|
||||
record = find(:first, :conditions => conditions)
|
||||
end
|
||||
|
||||
unless record
|
||||
record = new
|
||||
|
||||
if value.present?
|
||||
record.send(:"#{attribute}=", value)
|
||||
else
|
||||
error = :blank
|
||||
end
|
||||
|
||||
record.errors.add(attribute, error)
|
||||
end
|
||||
|
||||
record
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'devise/models/authenticatable'
|
||||
@@ -1,16 +0,0 @@
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# This module implements the default API required in activatable hook.
|
||||
module Activatable
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,10 @@
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Authenticable module. Holds common settings for authentication.
|
||||
#
|
||||
# Configuration:
|
||||
# == Configuration:
|
||||
#
|
||||
# You can overwrite configuration values by setting in globally in Devise,
|
||||
# using devise method or overwriting the respective instance method.
|
||||
@@ -15,13 +17,53 @@ module Devise
|
||||
# params_authenticatable: if this model allows authentication through request params. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow params authentication.
|
||||
#
|
||||
# == Active?
|
||||
#
|
||||
# Before authenticating an user and in each request, Devise checks if your model is active by
|
||||
# calling model.active?. This method is overwriten by other devise modules. For instance,
|
||||
# :confirmable overwrites .active? to only return true if your model was confirmed.
|
||||
#
|
||||
# You overwrite this method yourself, but if you do, don't forget to call super:
|
||||
#
|
||||
# def active?
|
||||
# super && special_condition_is_valid?
|
||||
# end
|
||||
#
|
||||
# Whenever active? returns false, Devise asks the reason why your model is inactive using
|
||||
# the inactive_message method. You can overwrite it as well:
|
||||
#
|
||||
# def inactive_message
|
||||
# special_condition_is_valid? ? super : :special_condition_is_not_valid
|
||||
# end
|
||||
#
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Yields the given block. This method is overwritten by other modules to provide
|
||||
# hooks around authentication.
|
||||
included do
|
||||
class_attribute :devise_modules, :instance_writer => false
|
||||
self.devise_modules ||= []
|
||||
end
|
||||
|
||||
# Check if the current object is valid for authentication. This method and
|
||||
# find_for_authentication are the methods used in a Warden::Strategy to check
|
||||
# if a model should be signed in or not.
|
||||
#
|
||||
# However, you should not overwrite this method, you should overwrite active? and
|
||||
# inactive_message instead.
|
||||
def valid_for_authentication?
|
||||
yield
|
||||
if active?
|
||||
block_given? ? yield : true
|
||||
else
|
||||
inactive_message
|
||||
end
|
||||
end
|
||||
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
@@ -50,6 +92,26 @@ module Devise
|
||||
def find_for_authentication(conditions)
|
||||
find(:first, :conditions => conditions)
|
||||
end
|
||||
|
||||
# Find an initialize a record setting an error if it can't be found.
|
||||
def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
|
||||
if value.present?
|
||||
conditions = { attribute => value }
|
||||
record = find(:first, :conditions => conditions)
|
||||
end
|
||||
|
||||
unless record
|
||||
record = new
|
||||
if value.present?
|
||||
record.send(:"#{attribute}=", value)
|
||||
else
|
||||
error = :blank
|
||||
end
|
||||
record.errors.add(attribute, error)
|
||||
end
|
||||
|
||||
record
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Confirmable is responsible to verify if an account is already confirmed to
|
||||
# sign in, and to send emails with confirmation instructions.
|
||||
# Confirmation instructions are sent to the user email after creating a
|
||||
@@ -30,7 +27,6 @@ module Devise
|
||||
# User.find(1).resend_confirmation! # generates a new token and resent it
|
||||
module Confirmable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
|
||||
included do
|
||||
before_create :generate_confirmation_token, :if => :confirmation_required?
|
||||
@@ -54,7 +50,8 @@ module Devise
|
||||
|
||||
# Send confirmation instructions by email
|
||||
def send_confirmation_instructions
|
||||
::Devise::Mailer.confirmation_instructions(self).deliver
|
||||
generate_confirmation_token if self.confirmation_token.nil?
|
||||
::Devise.mailer.confirmation_instructions(self).deliver
|
||||
end
|
||||
|
||||
# Resend confirmation token. This method does not need to generate a new token.
|
||||
@@ -67,7 +64,7 @@ module Devise
|
||||
# is already confirmed, it should never be blocked. Otherwise we need to
|
||||
# calculate if the confirm time has not expired for this user.
|
||||
def active?
|
||||
super && (confirmed? || confirmation_period_valid?)
|
||||
super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
|
||||
end
|
||||
|
||||
# The message to be shown if the account is inactive.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
require 'devise/models/authenticatable'
|
||||
require 'devise/strategies/database_authenticatable'
|
||||
|
||||
module Devise
|
||||
@@ -25,8 +24,7 @@ module Devise
|
||||
# User.find(1).valid_password?('password123') # returns true/false
|
||||
#
|
||||
module DatabaseAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
attr_reader :password, :current_password
|
||||
@@ -60,8 +58,10 @@ module Devise
|
||||
def update_with_password(params={})
|
||||
current_password = params.delete(:current_password)
|
||||
|
||||
params.delete(:password) if params[:password].blank?
|
||||
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
||||
if params[:password].blank?
|
||||
params.delete(:password)
|
||||
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
||||
end
|
||||
|
||||
result = if valid_password?(current_password)
|
||||
update_attributes(params)
|
||||
@@ -75,6 +75,9 @@ module Devise
|
||||
result
|
||||
end
|
||||
|
||||
def after_database_authentication
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Digests the password using the configured encryptor.
|
||||
@@ -90,8 +93,8 @@ module Devise
|
||||
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
||||
end
|
||||
|
||||
def find_for_database_authentication(*args)
|
||||
find_for_authentication(*args)
|
||||
def find_for_database_authentication(conditions)
|
||||
find_for_authentication(conditions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Handles blocking a user access after a certain number of attempts.
|
||||
# Lockable accepts two different strategies to unlock a user after it's
|
||||
# blocked: email and time. The former will send an email to the user when
|
||||
@@ -20,7 +17,6 @@ module Devise
|
||||
#
|
||||
module Lockable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
|
||||
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
||||
|
||||
@@ -53,7 +49,7 @@ module Devise
|
||||
|
||||
# Send unlock instructions by email
|
||||
def send_unlock_instructions
|
||||
::Devise::Mailer.unlock_instructions(self).deliver
|
||||
::Devise.mailer.unlock_instructions(self).deliver
|
||||
end
|
||||
|
||||
# Resend the unlock instructions if the user is locked.
|
||||
@@ -77,15 +73,15 @@ module Devise
|
||||
# for verifying whether an user is allowed to sign in or not. If the user
|
||||
# is locked, it should never be allowed.
|
||||
def valid_for_authentication?
|
||||
return :locked if access_locked?
|
||||
return super unless persisted?
|
||||
return super unless lock_strategy_enabled?(:failed_attempts)
|
||||
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
||||
|
||||
if result = super
|
||||
case (result = super)
|
||||
when Symbol
|
||||
return result
|
||||
when TrueClass
|
||||
self.failed_attempts = 0
|
||||
else
|
||||
when FalseClass
|
||||
self.failed_attempts += 1
|
||||
|
||||
if attempts_exceeded?
|
||||
lock_access!
|
||||
return :locked
|
||||
|
||||
@@ -28,7 +28,7 @@ module Devise
|
||||
# Resets reset password token and send reset password instructions by email
|
||||
def send_reset_password_instructions
|
||||
generate_reset_password_token!
|
||||
::Devise::Mailer.reset_password_instructions(self).deliver
|
||||
::Devise.mailer.reset_password_instructions(self).deliver
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'devise/strategies/rememberable'
|
||||
require 'devise/hooks/rememberable'
|
||||
require 'devise/hooks/forgetable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
@@ -64,6 +65,14 @@ module Devise
|
||||
remember_created_at + self.class.remember_for
|
||||
end
|
||||
|
||||
def cookie_domain
|
||||
self.class.cookie_domain
|
||||
end
|
||||
|
||||
def cookie_domain?
|
||||
self.class.cookie_domain != false
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Create the cookie key using the record id and remember_token
|
||||
def serialize_into_cookie(record)
|
||||
@@ -77,7 +86,7 @@ module Devise
|
||||
record if record && !record.remember_expired?
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :remember_for)
|
||||
Devise::Models.config(self, :remember_for, :cookie_domain)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,8 +2,11 @@ require 'devise/strategies/token_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Token Authenticatable Module, responsible for generate authentication token and validating
|
||||
# authenticity of a user while signing in using an authentication token (say follows an URL).
|
||||
# The TokenAuthenticatable module is responsible for generating an authentication token and
|
||||
# validating the authenticity of the same while signing in.
|
||||
#
|
||||
# This module only provides a few helpers to help you manage the token. Creating and resetting
|
||||
# the token is your responsibility.
|
||||
#
|
||||
# == Configuration:
|
||||
#
|
||||
@@ -12,18 +15,8 @@ module Devise
|
||||
#
|
||||
# +token_authentication_key+ - Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
||||
#
|
||||
# == Examples:
|
||||
#
|
||||
# User.authenticate_with_token(:auth_token => '123456789') # returns authenticated user or nil
|
||||
# User.find(1).valid_authentication_token?('rI1t6PKQ8yP7VetgwdybB') # returns true/false
|
||||
#
|
||||
module TokenAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Authenticatable
|
||||
|
||||
included do
|
||||
before_save :ensure_authentication_token
|
||||
end
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Generate new authentication token (a.k.a. "single access token").
|
||||
def reset_authentication_token
|
||||
@@ -33,7 +26,7 @@ module Devise
|
||||
# Generate new authentication token and save the record.
|
||||
def reset_authentication_token!
|
||||
reset_authentication_token
|
||||
self.save
|
||||
self.save(:validate => false)
|
||||
end
|
||||
|
||||
# Generate authentication token unless already exists.
|
||||
@@ -46,35 +39,21 @@ module Devise
|
||||
self.reset_authentication_token! if self.authentication_token.blank?
|
||||
end
|
||||
|
||||
# Hook called after token authentication.
|
||||
def after_token_authentication
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
::Devise::Models.config(self, :token_authentication_key)
|
||||
|
||||
# Authenticate a user based on authentication token.
|
||||
def authenticate_with_token(attributes)
|
||||
token = attributes[self.token_authentication_key]
|
||||
self.find_for_token_authentication(token)
|
||||
def find_for_token_authentication(conditions)
|
||||
conditions[:authentication_token] ||= conditions.delete(token_authentication_key)
|
||||
find_for_authentication(conditions)
|
||||
end
|
||||
|
||||
def authentication_token
|
||||
::Devise.friendly_token
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Find first record based on conditions given (ie by the sign in form).
|
||||
# Overwrite to add customized conditions, create a join, or maybe use a
|
||||
# namedscope to filter records while authenticating.
|
||||
#
|
||||
# == Example:
|
||||
#
|
||||
# def self.find_for_token_authentication(token, conditions = {})
|
||||
# conditions = {:active => true}
|
||||
# super
|
||||
# end
|
||||
#
|
||||
def find_for_token_authentication(token)
|
||||
self.find(:first, :conditions => { :authentication_token => token})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,7 +14,6 @@ Devise.with_options :model => true do |d|
|
||||
d.add_module :validatable
|
||||
|
||||
# The ones which can sign out after
|
||||
d.add_module :activatable
|
||||
d.add_module :confirmable, :controller => :confirmations, :route => :confirmation
|
||||
d.add_module :lockable, :controller => :unlocks, :route => :unlock
|
||||
d.add_module :timeoutable
|
||||
|
||||
@@ -23,7 +23,7 @@ module Devise
|
||||
include Devise::Schema
|
||||
|
||||
# Tell how to apply schema methods.
|
||||
def apply_schema(name, type, options={})
|
||||
def apply_devise_schema(name, type, options={})
|
||||
column name, type.to_s.downcase.to_sym, options
|
||||
end
|
||||
end
|
||||
@@ -31,8 +31,6 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord)
|
||||
ActiveRecord::Base.extend Devise::Models
|
||||
ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord::Schema
|
||||
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord::Schema
|
||||
end
|
||||
ActiveRecord::Base.extend Devise::Models
|
||||
ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord::Schema
|
||||
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord::Schema
|
||||
@@ -21,7 +21,7 @@ module Devise
|
||||
|
||||
# Tell how to apply schema methods. This automatically maps :limit to
|
||||
# :length and :null to :required.
|
||||
def apply_schema(name, type, options={})
|
||||
def apply_devise_schema(name, type, options={})
|
||||
SCHEMA_OPTIONS.each do |old_key, new_key|
|
||||
next unless options.key?(old_key)
|
||||
options[new_key] = options.delete(old_key)
|
||||
@@ -72,7 +72,7 @@ module Devise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def changed?
|
||||
dirty?
|
||||
end
|
||||
@@ -84,7 +84,7 @@ module Devise
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def update_attributes(*args)
|
||||
update(*args)
|
||||
end
|
||||
@@ -93,7 +93,5 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
DataMapper::Model.class_eval do
|
||||
include Devise::Models
|
||||
include Devise::Orm::DataMapper::Hook
|
||||
end
|
||||
DataMapper::Model.append_extensions(Devise::Models)
|
||||
DataMapper::Model.append_extensions(Devise::Orm::DataMapper::Hook)
|
||||
|
||||
@@ -4,32 +4,21 @@ module Devise
|
||||
module Hook
|
||||
def devise_modules_hook!
|
||||
extend Schema
|
||||
include ::Mongoid::Timestamps
|
||||
include Compatibility
|
||||
yield
|
||||
return unless Devise.apply_schema
|
||||
devise_modules.each { |m| send(m) if respond_to?(m, true) }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module Schema
|
||||
include Devise::Schema
|
||||
|
||||
# Tell how to apply schema methods
|
||||
def apply_schema(name, type, options={})
|
||||
def apply_devise_schema(name, type, options={})
|
||||
type = Time if type == DateTime
|
||||
field name, { :type => type }.merge(options)
|
||||
end
|
||||
end
|
||||
|
||||
module Compatibility
|
||||
def save(validate = true)
|
||||
if validate.is_a?(Hash) && validate.has_key?(:validate)
|
||||
validate = validate[:validate]
|
||||
end
|
||||
super(validate)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
13
lib/devise/path_checker.rb
Normal file
13
lib/devise/path_checker.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module Devise
|
||||
class PathChecker
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def initialize(env, scope)
|
||||
@env, @scope = env, scope
|
||||
end
|
||||
|
||||
def signing_out?
|
||||
@env["PATH_INFO"] == send("destroy_#{@scope}_session_path")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,33 +1,62 @@
|
||||
require 'devise/rails/routes'
|
||||
require 'devise/rails/warden_compat'
|
||||
|
||||
# Include UrlHelpers in ActionController and ActionView as soon as they are loaded.
|
||||
ActiveSupport.on_load(:action_controller) { include Devise::Controllers::UrlHelpers }
|
||||
ActiveSupport.on_load(:action_view) { include Devise::Controllers::UrlHelpers }
|
||||
|
||||
module Devise
|
||||
class Engine < ::Rails::Engine
|
||||
config.devise = Devise
|
||||
|
||||
initializer "devise.add_middleware" do |app|
|
||||
app.config.middleware.use Warden::Manager do |config|
|
||||
Devise.warden_config = config
|
||||
config.failure_app = Devise::FailureApp
|
||||
config.default_scope = Devise.default_scope
|
||||
config.app_middleware.use Warden::Manager do |config|
|
||||
Devise.warden_config = config
|
||||
end
|
||||
|
||||
# Force routes to be loaded if we are doing any eager load.
|
||||
config.before_eager_load { |app| app.reload_routes! }
|
||||
|
||||
config.after_initialize do
|
||||
Devise.encryptor ||= begin
|
||||
warn "[WARNING] config.encryptor is not set in your config/initializers/devise.rb. " \
|
||||
"Devise will then set it to :bcrypt. If you were using the previous default " \
|
||||
"encryptor, please add config.encryptor = :sha1 to your configuration file."
|
||||
:bcrypt
|
||||
end
|
||||
end
|
||||
|
||||
initializer "devise.add_url_helpers" do |app|
|
||||
Devise::FailureApp.send :include, app.routes.url_helpers
|
||||
end
|
||||
unless Rails.env.production?
|
||||
config.after_initialize do
|
||||
actions = [:confirmation_instructions, :reset_password_instructions, :unlock_instructions]
|
||||
|
||||
config.after_initialize do
|
||||
I18n.available_locales
|
||||
flash = [:unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked]
|
||||
translations = begin
|
||||
I18n.t("devise.mailer", :raise => true).map { |k, v| k if v.is_a?(String) }.compact
|
||||
rescue Exception => e # Do not care if something fails
|
||||
[]
|
||||
end
|
||||
|
||||
I18n.backend.send(:translations).each do |locale, translations|
|
||||
keys = flash & (translations[:devise][:sessions].keys) rescue []
|
||||
keys = actions & translations
|
||||
|
||||
keys.each do |key|
|
||||
ActiveSupport::Deprecation.warn "The I18n message 'devise.mailer.#{key}' is deprecated. " \
|
||||
"Please use 'devise.mailer.#{key}.subject' instead."
|
||||
end
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
flash = [:unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked]
|
||||
|
||||
translations = begin
|
||||
I18n.t("devise.sessions", :raise => true).keys
|
||||
rescue Exception => e # Do not care if something fails
|
||||
[]
|
||||
end
|
||||
|
||||
keys = flash & translations
|
||||
|
||||
if keys.any?
|
||||
ActiveSupport::Deprecation.warn "The following I18n messages in 'devise.sessions' " <<
|
||||
"for locale '#{locale}' are deprecated: #{keys.to_sentence}. Please move them to " <<
|
||||
"'devise.failure' instead."
|
||||
ActiveSupport::Deprecation.warn "The following I18n messages in 'devise.sessions' " \
|
||||
"are deprecated: #{keys.to_sentence}. Please move them to 'devise.failure' instead."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,8 +6,6 @@ module ActionDispatch::Routing
|
||||
finalize_without_devise!
|
||||
Devise.configure_warden!
|
||||
ActionController::Base.send :include, Devise::Controllers::Helpers
|
||||
ActionController::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
ActionView::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
end
|
||||
alias_method_chain :finalize!, :devise
|
||||
end
|
||||
@@ -16,13 +14,14 @@ module ActionDispatch::Routing
|
||||
# Includes devise_for method for routes. This method is responsible to
|
||||
# generate all needed routes for devise, based on what modules you have
|
||||
# defined in your model.
|
||||
#
|
||||
# Examples: Let's say you have an User model configured to use
|
||||
# authenticatable, confirmable and recoverable modules. After creating this
|
||||
# inside your routes:
|
||||
#
|
||||
# devise_for :users
|
||||
#
|
||||
# this method is going to look inside your User model and create the
|
||||
# This method is going to look inside your User model and create the
|
||||
# needed routes:
|
||||
#
|
||||
# # Session routes for Authenticatable (default)
|
||||
@@ -46,56 +45,57 @@ module ActionDispatch::Routing
|
||||
# * :class_name => setup a different class to be looked up by devise,
|
||||
# if it cannot be correctly find by the route name.
|
||||
#
|
||||
# devise_for :users, :class_name => 'Account'
|
||||
# devise_for :users, :class_name => 'Account'
|
||||
#
|
||||
# * :as => allows you to setup path name that will be used, as rails routes does.
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
# * :path => allows you to setup path name that will be used, as rails routes does.
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
#
|
||||
# devise_for :users, :as => 'accounts'
|
||||
# devise_for :users, :path => 'accounts'
|
||||
#
|
||||
# * :scope => setup the scope name. This is used as the instance variable name in controller,
|
||||
# as the name in routes and the scope given to warden. Defaults to the singular of the given name:
|
||||
# * :singular => setup the singular name for the given resource. This is used as the instance variable name in
|
||||
# controller, as the name in routes and the scope given to warden.
|
||||
#
|
||||
# devise_for :users, :scope => :account
|
||||
# devise_for :users, :singular => :user
|
||||
#
|
||||
# * :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' }
|
||||
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
|
||||
#
|
||||
# * :path_prefix => the path prefix to be used in all routes.
|
||||
#
|
||||
# devise_for :users, :path_prefix => "/:locale"
|
||||
# devise_for :users, :path_prefix => "/:locale"
|
||||
#
|
||||
# If you are using a dynamic prefix, like :locale above, you need to configure default_url_options in your ApplicationController
|
||||
# class level, so Devise can pick it:
|
||||
#
|
||||
# class ApplicationController < ActionController::Base
|
||||
# def self.default_url_options
|
||||
# { :locale => I18n.locale }
|
||||
# class ApplicationController < ActionController::Base
|
||||
# def self.default_url_options
|
||||
# { :locale => I18n.locale }
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# * :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:
|
||||
#
|
||||
# devise_for :users, :controllers => { :sessions => "users/sessions" }
|
||||
# devise_for :users, :controllers => { :sessions => "users/sessions" }
|
||||
#
|
||||
# * :skip => tell which controller you want to skip routes from being created:
|
||||
#
|
||||
# devise_for :users, :skip => :sessions
|
||||
# devise_for :users, :skip => :sessions
|
||||
#
|
||||
def devise_for(*resources)
|
||||
options = resources.extract_options!
|
||||
resources.map!(&:to_sym)
|
||||
|
||||
resources.each do |resource|
|
||||
mapping = Devise.register(resource, options)
|
||||
mapping = Devise.add_model(resource, options)
|
||||
|
||||
unless mapping.to.respond_to?(:devise)
|
||||
raise "#{mapping.to.name} 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' " <<
|
||||
"inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
|
||||
begin
|
||||
raise_no_devise_method_error!(mapping.class_name) unless mapping.to.respond_to?(:devise)
|
||||
rescue NoMethodError => e
|
||||
raise unless e.message.include?("undefined method `devise'")
|
||||
raise_no_devise_method_error!(mapping.class_name)
|
||||
end
|
||||
|
||||
routes = mapping.routes
|
||||
@@ -107,10 +107,20 @@ module ActionDispatch::Routing
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate(scope)
|
||||
constraint = lambda do |request|
|
||||
request.env["warden"].authenticate!(:scope => scope)
|
||||
end
|
||||
|
||||
constraints(constraint) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def devise_session(mapping, controllers)
|
||||
scope mapping.path do
|
||||
scope mapping.full_path do
|
||||
get mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#new", :as => :"new_#{mapping.name}_session"
|
||||
post mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#create", :as => :"#{mapping.name}_session"
|
||||
get mapping.path_names[:sign_out], :to => "#{controllers[:sessions]}#destroy", :as => :"destroy_#{mapping.name}_session"
|
||||
@@ -118,28 +128,34 @@ module ActionDispatch::Routing
|
||||
end
|
||||
|
||||
def devise_password(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :password, :only => [:new, :create, :edit, :update], :as => mapping.path_names[:password], :controller => controllers[:passwords]
|
||||
scope mapping.full_path, :name_prefix => mapping.name do
|
||||
resource :password, :only => [:new, :create, :edit, :update], :path => mapping.path_names[:password], :controller => controllers[:passwords]
|
||||
end
|
||||
end
|
||||
|
||||
def devise_confirmation(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :confirmation, :only => [:new, :create, :show], :as => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
|
||||
scope mapping.full_path, :name_prefix => mapping.name do
|
||||
resource :confirmation, :only => [:new, :create, :show], :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
|
||||
end
|
||||
end
|
||||
|
||||
def devise_unlock(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :unlock, :only => [:new, :create, :show], :as => mapping.path_names[:unlock], :controller => controllers[:unlocks]
|
||||
scope mapping.full_path, :name_prefix => mapping.name do
|
||||
resource :unlock, :only => [:new, :create, :show], :path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
|
||||
end
|
||||
end
|
||||
|
||||
def devise_registration(mapping, controllers)
|
||||
scope mapping.path[1..-1], :name_prefix => "#{mapping.name}_registration" do
|
||||
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :as => "",
|
||||
scope mapping.full_path[1..-1], :name_prefix => mapping.name do
|
||||
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => mapping.path_names[:registration],
|
||||
:path_names => { :new => mapping.path_names[:sign_up] }, :controller => controllers[:registrations]
|
||||
end
|
||||
end
|
||||
|
||||
def raise_no_devise_method_error!(klass)
|
||||
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' " <<
|
||||
"inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,6 +13,10 @@ module Devise
|
||||
# == Options
|
||||
# * :null - When true, allow columns to be null.
|
||||
# * :default - Should be set to "" when :null is false.
|
||||
#
|
||||
# == Notes
|
||||
# For Datamapper compatibility, we explicitly hardcode the limit for the
|
||||
# encrypter password field in 128 characters.
|
||||
def database_authenticatable(options={})
|
||||
null = options[:null] || false
|
||||
default = options[:default] || ""
|
||||
@@ -21,42 +25,42 @@ module Devise
|
||||
ActiveSupport::Deprecation.warn ":encryptor as option is deprecated, simply remove it."
|
||||
end
|
||||
|
||||
apply_schema :email, String, :null => null, :default => default
|
||||
apply_schema :encrypted_password, String, :null => null, :default => default, :limit => 128
|
||||
apply_schema :password_salt, String, :null => null, :default => default
|
||||
apply_devise_schema :email, String, :null => null, :default => default
|
||||
apply_devise_schema :encrypted_password, String, :null => null, :default => default, :limit => 128
|
||||
apply_devise_schema :password_salt, String, :null => null, :default => default
|
||||
end
|
||||
|
||||
# Creates authentication_token.
|
||||
def token_authenticatable(options={})
|
||||
apply_schema :authentication_token, String
|
||||
apply_devise_schema :authentication_token, String
|
||||
end
|
||||
|
||||
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
|
||||
def confirmable
|
||||
apply_schema :confirmation_token, String
|
||||
apply_schema :confirmed_at, DateTime
|
||||
apply_schema :confirmation_sent_at, DateTime
|
||||
apply_devise_schema :confirmation_token, String
|
||||
apply_devise_schema :confirmed_at, DateTime
|
||||
apply_devise_schema :confirmation_sent_at, DateTime
|
||||
end
|
||||
|
||||
# Creates reset_password_token.
|
||||
def recoverable
|
||||
apply_schema :reset_password_token, String
|
||||
apply_devise_schema :reset_password_token, String
|
||||
end
|
||||
|
||||
# Creates remember_token and remember_created_at.
|
||||
def rememberable
|
||||
apply_schema :remember_token, String
|
||||
apply_schema :remember_created_at, DateTime
|
||||
apply_devise_schema :remember_token, String
|
||||
apply_devise_schema :remember_created_at, DateTime
|
||||
end
|
||||
|
||||
# Creates sign_in_count, current_sign_in_at, last_sign_in_at,
|
||||
# current_sign_in_ip, last_sign_in_ip.
|
||||
def trackable
|
||||
apply_schema :sign_in_count, Integer, :default => 0
|
||||
apply_schema :current_sign_in_at, DateTime
|
||||
apply_schema :last_sign_in_at, DateTime
|
||||
apply_schema :current_sign_in_ip, String
|
||||
apply_schema :last_sign_in_ip, String
|
||||
apply_devise_schema :sign_in_count, Integer, :default => 0
|
||||
apply_devise_schema :current_sign_in_at, DateTime
|
||||
apply_devise_schema :last_sign_in_at, DateTime
|
||||
apply_devise_schema :current_sign_in_ip, String
|
||||
apply_devise_schema :last_sign_in_ip, String
|
||||
end
|
||||
|
||||
# Creates failed_attempts, unlock_token and locked_at depending on the options given.
|
||||
@@ -75,18 +79,18 @@ module Devise
|
||||
lock_strategy ||= :failed_attempts
|
||||
|
||||
if lock_strategy == :failed_attempts
|
||||
apply_schema :failed_attempts, Integer, :default => 0
|
||||
apply_devise_schema :failed_attempts, Integer, :default => 0
|
||||
end
|
||||
|
||||
if [:both, :email].include?(unlock_strategy)
|
||||
apply_schema :unlock_token, String
|
||||
apply_devise_schema :unlock_token, String
|
||||
end
|
||||
|
||||
apply_schema :locked_at, DateTime
|
||||
apply_devise_schema :locked_at, DateTime
|
||||
end
|
||||
|
||||
# Overwrite with specific modification to create your own schema.
|
||||
def apply_schema(name, type, options={})
|
||||
def apply_devise_schema(name, type, options={})
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,24 +14,23 @@ module Devise
|
||||
|
||||
private
|
||||
|
||||
# Simply invokes valid_for_authentication? with the given block and deal with the result.
|
||||
def validate(resource, &block)
|
||||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
case result
|
||||
when Symbol, String
|
||||
fail!(result)
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
# Check if this is strategy is valid for http authentication.
|
||||
# Check if this is strategy is valid for http authentication by:
|
||||
#
|
||||
# * Validating if the model allows params authentication;
|
||||
# * If any of the authorization headers were sent;
|
||||
# * If all authentication keys are present;
|
||||
#
|
||||
def valid_for_http_auth?
|
||||
http_authenticatable? && request.authorization && with_authentication_hash(http_auth_hash)
|
||||
end
|
||||
|
||||
# Check if this is strategy is valid for params authentication.
|
||||
# Check if this is strategy is valid for params authentication by:
|
||||
#
|
||||
# * Validating if the model allows params authentication;
|
||||
# * If the request hits the sessions controller through POST;
|
||||
# * If the params[scope] returns a hash with credentials;
|
||||
# * If all authentication keys are present;
|
||||
#
|
||||
def valid_for_params_auth?
|
||||
params_authenticatable? && valid_request? &&
|
||||
valid_params? && with_authentication_hash(params_auth_hash)
|
||||
@@ -63,12 +62,12 @@ module Devise
|
||||
valid_controller? && valid_verb?
|
||||
end
|
||||
|
||||
# Check if the controller is valid for params authentication.
|
||||
# Check if the controller is the one registered for authentication.
|
||||
def valid_controller?
|
||||
mapping.controllers[:sessions] == params[:controller]
|
||||
end
|
||||
|
||||
# Check if the params_auth_hash is valid for params authentication.
|
||||
# Check if it was a POST request.
|
||||
def valid_verb?
|
||||
request.post?
|
||||
end
|
||||
@@ -78,6 +77,11 @@ module Devise
|
||||
params_auth_hash.is_a?(Hash)
|
||||
end
|
||||
|
||||
# Check if password is present and is not equal to "X" (default value for token).
|
||||
def valid_password?
|
||||
password.present? && password != "X"
|
||||
end
|
||||
|
||||
# Helper to decode credentials from HTTP.
|
||||
def decode_credentials
|
||||
username_and_password = request.authorization.split(' ', 2).last || ''
|
||||
|
||||
@@ -11,9 +11,23 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def succeeded?
|
||||
@result == :success
|
||||
end
|
||||
|
||||
# Simply invokes valid_for_authentication? with the given block and deal with the result.
|
||||
def validate(resource, &block)
|
||||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
case result
|
||||
when Symbol, String
|
||||
fail!(result)
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,9 +5,10 @@ module Devise
|
||||
# Default strategy for signing in a user, based on his email and password in the database.
|
||||
class DatabaseAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
resource = mapping.to.find_for_database_authentication(authentication_hash)
|
||||
resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
|
||||
|
||||
if validate(resource){ resource.valid_password?(password) }
|
||||
resource.after_database_authentication
|
||||
success!(resource)
|
||||
else
|
||||
fail(:invalid)
|
||||
|
||||
@@ -16,7 +16,9 @@ module Devise
|
||||
# the record in the database. If the attempt fails, we pass to another
|
||||
# strategy handle the authentication.
|
||||
def authenticate!
|
||||
if resource = mapping.to.serialize_from_cookie(*remember_cookie)
|
||||
resource = mapping.to.serialize_from_cookie(*remember_cookie)
|
||||
|
||||
if validate(resource)
|
||||
success!(resource)
|
||||
else
|
||||
cookies.delete(remember_key)
|
||||
|
||||
@@ -7,11 +7,14 @@ module Devise
|
||||
#
|
||||
# http://myapp.example.com/?user_token=SECRET
|
||||
#
|
||||
# For HTTP, you can pass the token as username. Since some clients may require a password,
|
||||
# you can pass anything and it will simply be ignored.
|
||||
# For HTTP, you can pass the token as username and blank password. Since some clients may require
|
||||
# a password, you can pass "X" as password and it will simply be ignored.
|
||||
class TokenAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
if resource = mapping.to.authenticate_with_token(authentication_hash)
|
||||
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
||||
|
||||
if validate(resource)
|
||||
resource.after_token_authentication
|
||||
success!(resource)
|
||||
else
|
||||
fail(:invalid_token)
|
||||
|
||||
@@ -40,7 +40,8 @@ module Devise
|
||||
Warden::Manager._before_failure.each{ |hook| hook.call(env, result) }
|
||||
|
||||
status, headers, body = Devise::FailureApp.call(env).to_a
|
||||
@controller.send :redirect_to, headers["Location"]
|
||||
@controller.send :render, :status => status, :text => body,
|
||||
:content_type => headers["Content-Type"], :location => headers["Location"]
|
||||
else
|
||||
result
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Devise
|
||||
VERSION = "1.1.rc0".freeze
|
||||
VERSION = "1.1.rc2".freeze
|
||||
end
|
||||
|
||||
86
lib/generators/devise/devise/devise_generator.rb
Normal file
86
lib/generators/devise/devise/devise_generator.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
require 'rails/generators/migration'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
class DeviseGenerator < Rails::Generators::NamedBase
|
||||
include Rails::Generators::Migration
|
||||
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
namespace "devise"
|
||||
|
||||
desc "Generates a model with the given NAME (if one does not exist) with devise " <<
|
||||
"configuration plus a migration file and devise routes."
|
||||
|
||||
def self.orm_has_migration?
|
||||
Rails::Generators.options[:rails][:orm] == :active_record
|
||||
end
|
||||
|
||||
def self.next_migration_number(path)
|
||||
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
||||
end
|
||||
|
||||
class_option :orm
|
||||
class_option :migration, :type => :boolean, :default => orm_has_migration?
|
||||
|
||||
def invoke_orm_model
|
||||
return unless behavior == :invoke
|
||||
|
||||
if model_exists?
|
||||
say "* Model already exists. Adding Devise behavior."
|
||||
elsif options[:orm].present?
|
||||
invoke "model", [name], :migration => false, :orm => options[:orm]
|
||||
|
||||
unless model_exists?
|
||||
abort "Tried to invoke the model generator for '#{options[:orm]}' but could not find it.\n" <<
|
||||
"Please create your model by hand before calling `rails g devise #{name}`."
|
||||
end
|
||||
else
|
||||
abort "Cannot create a devise model because config.generators.orm is blank.\n" <<
|
||||
"Please create your model by hand or configure your generators orm before calling `rails g devise #{name}`."
|
||||
end
|
||||
end
|
||||
|
||||
def inject_devise_config_into_model
|
||||
devise_class_setup = <<-CONTENT
|
||||
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :confirmable, :lockable and :timeoutable
|
||||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
CONTENT
|
||||
|
||||
case options[:orm].to_s
|
||||
when "mongoid"
|
||||
inject_into_file model_path, devise_class_setup, :after => "include Mongoid::Document\n"
|
||||
when "data_mapper"
|
||||
inject_into_file model_path, devise_class_setup, :after => "include DataMapper::Resource\n"
|
||||
when "active_record"
|
||||
inject_into_class model_path, class_name, devise_class_setup + <<-CONTENT
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
attr_accessible :email, :password, :password_confirmation
|
||||
CONTENT
|
||||
end
|
||||
end
|
||||
|
||||
def copy_migration_template
|
||||
return unless options.migration?
|
||||
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
|
||||
end
|
||||
|
||||
def add_devise_routes
|
||||
route "devise_for :#{table_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_exists?
|
||||
File.exists?(File.join(destination_root, model_path))
|
||||
end
|
||||
|
||||
def model_path
|
||||
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,18 +2,20 @@ class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table(:<%= table_name %>) do |t|
|
||||
t.database_authenticatable :null => false
|
||||
t.confirmable
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
t.trackable
|
||||
|
||||
# t.confirmable
|
||||
# t.lockable :lock_strategy => :<%= Devise.lock_strategy %>, :unlock_strategy => :<%= Devise.unlock_strategy %>
|
||||
# t.token_authenticatable
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :<%= table_name %>, :email, :unique => true
|
||||
add_index :<%= table_name %>, :confirmation_token, :unique => true
|
||||
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
|
||||
end
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
require 'rails/generators/migration'
|
||||
|
||||
class DeviseGenerator < Rails::Generators::NamedBase
|
||||
include Rails::Generators::Migration
|
||||
|
||||
desc "Generates a model with the given NAME (if one does not exist) with devise " <<
|
||||
"configuration plus a migration file and devise routes."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../templates", __FILE__)
|
||||
end
|
||||
|
||||
def self.orm_has_migration?
|
||||
Rails::Generators.options[:rails][:orm] == :active_record
|
||||
end
|
||||
|
||||
def self.next_migration_number(path)
|
||||
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
||||
end
|
||||
|
||||
class_option :orm
|
||||
class_option :migration, :type => :boolean, :default => orm_has_migration?
|
||||
|
||||
def invoke_orm_model
|
||||
if model_exists?
|
||||
say "* Model already exists. Adding Devise behavior."
|
||||
else
|
||||
invoke "model", [name], :migration => false, :orm => options[:orm]
|
||||
|
||||
unless model_exists?
|
||||
abort "Tried to invoke the model generator for '#{options[:orm]}' but could not find it.\n" <<
|
||||
"Please create your model by hand before calling `rails g devise #{name}`."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def inject_devise_config_into_model
|
||||
inject_into_class model_path, class_name, <<-CONTENT
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :lockable, :timeoutable and :activatable
|
||||
devise :database_authenticatable, :registerable, :confirmable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
attr_accessible :email, :password, :password_confirmation
|
||||
CONTENT
|
||||
end
|
||||
|
||||
def copy_migration_template
|
||||
return unless options.migration?
|
||||
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
|
||||
end
|
||||
|
||||
def add_devise_routes
|
||||
route "devise_for :#{table_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_exists?
|
||||
File.exists?(File.join(destination_root, model_path))
|
||||
end
|
||||
|
||||
def model_path
|
||||
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
||||
end
|
||||
end
|
||||
24
lib/generators/devise/install/install_generator.rb
Normal file
24
lib/generators/devise/install/install_generator.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
require 'active_support/secure_random'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
class InstallGenerator < Rails::Generators::Base
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
|
||||
desc "Creates a Devise initializer and copy locale files to your application."
|
||||
class_option :orm
|
||||
|
||||
def copy_initializer
|
||||
template "devise.rb", "config/initializers/devise.rb"
|
||||
end
|
||||
|
||||
def copy_locale
|
||||
copy_file "../../../../../config/locales/en.yml", "config/locales/devise.en.yml"
|
||||
end
|
||||
|
||||
def show_readme
|
||||
readme "README"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,7 @@ Some setup you must do manually if you haven't yet:
|
||||
|
||||
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
|
||||
|
||||
This is a required Rails configuration. In production is must be the
|
||||
This is a required Rails configuration. In production it must be the
|
||||
actual host of your application
|
||||
|
||||
2. Ensure you have defined root_url to *something* in your config/routes.rb.
|
||||
@@ -16,4 +16,10 @@ Some setup you must do manually if you haven't yet:
|
||||
|
||||
root :to => "home#index"
|
||||
|
||||
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
|
||||
For example:
|
||||
|
||||
<p class="notice"><%= notice %></p>
|
||||
<p class="alert"><%= alert %></p>
|
||||
|
||||
===============================================================================
|
||||
@@ -1,9 +1,18 @@
|
||||
# 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|
|
||||
# ==> Mailer Configuration
|
||||
# Configure the e-mail address which will be shown in DeviseMailer.
|
||||
config.mailer_sender = "please-change-me@config-initializers-devise.com"
|
||||
|
||||
# Configure the class responsible to send e-mails.
|
||||
# config.mailer = "Devise::Mailer"
|
||||
|
||||
# ==> ORM configuration
|
||||
# Load and configure the ORM. Supports :active_record (default), :mongoid
|
||||
# (bson_ext recommended) and :data_mapper (experimental).
|
||||
require 'devise/orm/<%= options[:orm] %>'
|
||||
|
||||
# ==> Configuration for any authentication mechanism
|
||||
# Configure which keys are used when authenticating an user. By default is
|
||||
# just :email. You can configure it to use [:username, :subdomain], so for
|
||||
@@ -22,23 +31,26 @@ Devise.setup do |config|
|
||||
# config.http_authentication_realm = "Application"
|
||||
|
||||
# ==> Configuration for :database_authenticatable
|
||||
# Invoke `rake secret` and use the printed value to setup a pepper to generate
|
||||
# the encrypted password. By default no pepper is used.
|
||||
# config.pepper = "rake secret output"
|
||||
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
|
||||
# using other encryptors, it sets how many times you want the password re-encrypted.
|
||||
config.stretches = 10
|
||||
|
||||
# Configure how many times you want the password is reencrypted. Default is 10.
|
||||
# config.stretches = 10
|
||||
|
||||
# Define which will be the encryption algorithm. Supported algorithms are :sha1
|
||||
# (default), :sha512 and :bcrypt. Devise also supports encryptors from others
|
||||
# authentication tools as :clearance_sha1, :authlogic_sha512 (then you should set
|
||||
# stretches above to 20 for default behavior) and :restful_authentication_sha1
|
||||
# Define which will be the encryption algorithm. Devise also supports encryptors
|
||||
# from others authentication tools as :clearance_sha1, :authlogic_sha512 (then
|
||||
# you should set stretches above to 20 for default behavior) and :restful_authentication_sha1
|
||||
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
|
||||
# config.encryptor = :sha1
|
||||
config.encryptor = :bcrypt
|
||||
|
||||
# Setup a pepper to generate the encrypted password.
|
||||
config.pepper = <%= ActiveSupport::SecureRandom.hex(64).inspect %>
|
||||
|
||||
# ==> Configuration for :confirmable
|
||||
# The time you want give to your user to confirm his account. During this time
|
||||
# The time you want to give your user to confirm his account. During this time
|
||||
# he will be able to access your application without confirming. Default is nil.
|
||||
# When confirm_within is zero, the user won't be able to sign in without confirming.
|
||||
# You can use this to let your user access some features of your application
|
||||
# without confirming the account, but blocking it after a certain period
|
||||
# (ie 2 days).
|
||||
# config.confirm_within = 2.days
|
||||
|
||||
# ==> Configuration for :rememberable
|
||||
@@ -65,7 +77,7 @@ Devise.setup do |config|
|
||||
|
||||
# Defines which strategy will be used to unlock an account.
|
||||
# :email = Sends an unlock link to the user email
|
||||
# :time = Reanables login after a certain ammount of time (see :unlock_in below)
|
||||
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
|
||||
# :both = Enables both strategies
|
||||
# :none = No unlock strategy. You should handle unlocking by yourself.
|
||||
# config.unlock_strategy = :both
|
||||
@@ -81,11 +93,7 @@ Devise.setup do |config|
|
||||
# Defines name of the authentication token params key
|
||||
# config.token_authentication_key = :auth_token
|
||||
|
||||
# ==> General configuration
|
||||
# Load and configure the ORM. Supports :active_record (default), :mongoid
|
||||
# (requires mongo_ext installed) and :data_mapper (experimental).
|
||||
require 'devise/orm/active_record'
|
||||
|
||||
# ==> Scopes configuration
|
||||
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
||||
# "sessions/users/new". It's turned off by default because it's slower if you
|
||||
# are using only default views.
|
||||
@@ -95,12 +103,23 @@ Devise.setup do |config|
|
||||
# accessing "/users/sign_in", it knows you are accessing an User. This makes
|
||||
# routes as "/sign_in" not possible, unless you tell Devise to use the default
|
||||
# scope, setting true below.
|
||||
# Note that devise does not generate default routes. You also have to
|
||||
# specify them in config/routes.rb
|
||||
# config.use_default_scope = true
|
||||
|
||||
# Configure the default scope used by Devise. By default it's the first devise
|
||||
# role declared in your routes.
|
||||
# config.default_scope = :user
|
||||
|
||||
# ==> Navigation configuration
|
||||
# Lists the formats that should be treated as navigational. Formats like
|
||||
# :html, should redirect to the sign in page when the user does not have
|
||||
# access, but formats like :xml or :json, should return 401.
|
||||
# If you have any extra navigational formats, like :iphone or :mobile, you
|
||||
# should add them to the navigational formats lists. Default is [:html]
|
||||
# config.navigational_formats = [:html, :iphone]
|
||||
|
||||
# ==> Warden configuration
|
||||
# If you want to use other strategies, that are not (yet) supported by Devise,
|
||||
# you can configure them inside the config.warden block. The example below
|
||||
# allows you to setup OAuth, using http://github.com/roman/warden_oauth
|
||||
63
lib/generators/devise/views/views_generator.rb
Normal file
63
lib/generators/devise/views/views_generator.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
module Devise
|
||||
module Generators
|
||||
class ViewsGenerator < Rails::Generators::Base
|
||||
source_root File.expand_path("../../../../../app/views", __FILE__)
|
||||
desc "Copies all Devise views to your application."
|
||||
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
class_option :template_engine, :type => :string, :aliases => "-t", :default => "erb",
|
||||
:desc => "Template engine for the views. Available options are 'erb' and 'haml'."
|
||||
|
||||
def copy_views
|
||||
case options[:template_engine]
|
||||
when "haml"
|
||||
verify_haml_existence
|
||||
verify_haml_version
|
||||
create_and_copy_haml_views
|
||||
else
|
||||
directory "devise", "app/views/#{scope || :devise}"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def verify_haml_existence
|
||||
begin
|
||||
require 'haml'
|
||||
rescue LoadError
|
||||
say "HAML is not installed, or it is not specified in your Gemfile."
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def verify_haml_version
|
||||
unless Haml.version[:major] == 2 and Haml.version[:minor] >= 3 or Haml.version[:major] >= 3
|
||||
say "To generate HAML templates, you need to install HAML 2.3 or above."
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def create_and_copy_haml_views
|
||||
require 'tmpdir'
|
||||
html_root = "#{self.class.source_root}/devise"
|
||||
|
||||
Dir.mktmpdir("devise-haml.") do |haml_root|
|
||||
Dir["#{html_root}/**/*"].each do |path|
|
||||
relative_path = path.sub(html_root, "")
|
||||
source_path = (haml_root + relative_path).sub(/erb$/, "haml")
|
||||
|
||||
if File.directory?(path)
|
||||
FileUtils.mkdir_p(source_path)
|
||||
else
|
||||
`html2haml -r #{path} #{source_path}`
|
||||
end
|
||||
end
|
||||
|
||||
directory haml_root, "app/views/#{scope || :devise}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
2
lib/generators/devise_generator.rb
Normal file
2
lib/generators/devise_generator.rb
Normal file
@@ -0,0 +1,2 @@
|
||||
# Remove this file on next rails release
|
||||
require "generators/devise/devise/devise_generator"
|
||||
@@ -1,25 +0,0 @@
|
||||
class DeviseInstallGenerator < Rails::Generators::Base
|
||||
desc "Creates a Devise initializer and copy locale files to your application."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../templates", __FILE__)
|
||||
end
|
||||
|
||||
def copy_initializer
|
||||
template "devise.rb", "config/initializers/devise.rb"
|
||||
end
|
||||
|
||||
def copy_locale
|
||||
copy_file "../../../../config/locales/en.yml", "config/locales/devise.en.yml"
|
||||
end
|
||||
|
||||
def show_readme
|
||||
readme "README"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def readme(path)
|
||||
say File.read(File.expand_path(path, self.class.source_root))
|
||||
end
|
||||
end
|
||||
4
lib/generators/devise_install_generator.rb
Normal file
4
lib/generators/devise_install_generator.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
# Remove this file after deprecation
|
||||
if caller.none? { |l| l =~ %r{lib/rails/generators\.rb:(\d+):in `lookup!'$} }
|
||||
warn "[WARNING] `rails g devise_install` is deprecated, please use `rails g devise:install` instead."
|
||||
end
|
||||
@@ -1,62 +0,0 @@
|
||||
class DeviseViewsGenerator < Rails::Generators::Base
|
||||
desc "Copies all Devise views to your application."
|
||||
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
class_option :template_engine, :type => :string, :aliases => "-t", :default => "erb",
|
||||
:desc => "Template engine for the views. Available options are 'erb' and 'haml'."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../../../../app/views", __FILE__)
|
||||
end
|
||||
|
||||
def copy_views
|
||||
case options[:template_engine]
|
||||
when "haml"
|
||||
verify_haml_existence
|
||||
verify_haml_version
|
||||
create_and_copy_haml_views
|
||||
else
|
||||
directory "devise", "app/views/devise/#{scope}"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def verify_haml_existence
|
||||
begin
|
||||
require 'haml'
|
||||
rescue LoadError
|
||||
say "HAML is not installed, or it is not specified in your Gemfile."
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def verify_haml_version
|
||||
unless Haml.version[:major] == 2 and Haml.version[:minor] >= 3 or Haml.version[:major] >= 3
|
||||
say "To generate HAML templates, you need to install HAML 2.3 or above."
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def create_and_copy_haml_views
|
||||
require 'tmpdir'
|
||||
html_root = "#{self.class.source_root}/devise"
|
||||
|
||||
Dir.mktmpdir("devise-haml.") do |haml_root|
|
||||
Dir["#{html_root}/**/*"].each do |path|
|
||||
relative_path = path.sub(html_root, "")
|
||||
source_path = (haml_root + relative_path).sub(/erb$/, "haml")
|
||||
|
||||
if File.directory?(path)
|
||||
FileUtils.mkdir_p(source_path)
|
||||
else
|
||||
`html2haml -r #{path} #{source_path}`
|
||||
end
|
||||
end
|
||||
|
||||
directory haml_root, "app/views/devise/#{scope}"
|
||||
end
|
||||
end
|
||||
end
|
||||
4
lib/generators/devise_views_generator.rb
Normal file
4
lib/generators/devise_views_generator.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
# Remove this file after deprecation
|
||||
if caller.none? { |l| l =~ %r{lib/rails/generators\.rb:(\d+):in `lookup!'$} }
|
||||
warn "[WARNING] `rails g devise_views` is deprecated, please use `rails g devise:views` instead."
|
||||
end
|
||||
@@ -53,6 +53,13 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.signed_in?(:my_scope)
|
||||
end
|
||||
|
||||
test 'proxy anybody_signed_in? to signed_in?' do
|
||||
Devise.mappings.keys.each { |scope| # :user, :admin, :manager
|
||||
@controller.expects(:signed_in?).with(scope)
|
||||
}
|
||||
@controller.anybody_signed_in?
|
||||
end
|
||||
|
||||
test 'proxy current_admin to authenticate with admin scope' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :admin)
|
||||
@controller.current_admin
|
||||
@@ -145,6 +152,14 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
assert_equal admin_root_path, @controller.after_sign_in_path_for(:admin)
|
||||
end
|
||||
|
||||
test 'after update path defaults to root path if none by was specified for the given scope' do
|
||||
assert_equal root_path, @controller.after_update_path_for(:user)
|
||||
end
|
||||
|
||||
test 'after update path defaults to the scoped root path' do
|
||||
assert_equal admin_root_path, @controller.after_update_path_for(:admin)
|
||||
end
|
||||
|
||||
test 'after sign out path defaults to the root path' do
|
||||
assert_equal root_path, @controller.after_sign_out_path_for(:admin)
|
||||
assert_equal root_path, @controller.after_sign_out_path_for(:user)
|
||||
|
||||
@@ -2,6 +2,7 @@ require 'test_helper'
|
||||
|
||||
module Devise
|
||||
def self.yield_and_restore
|
||||
@@warden_configured = nil
|
||||
c, b = @@warden_config, @@warden_config_block
|
||||
yield
|
||||
ensure
|
||||
|
||||
@@ -8,11 +8,12 @@ class FailureTest < ActiveSupport::TestCase
|
||||
|
||||
def call_failure(env_params={})
|
||||
env = {
|
||||
'warden.options' => { :scope => :user },
|
||||
'REQUEST_URI' => 'http://test.host/',
|
||||
'HTTP_HOST' => 'test.host',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'warden.options' => { :scope => :user },
|
||||
'rack.session' => {},
|
||||
'action_dispatch.request.formats' => Array(env_params.delete('formats') || :html),
|
||||
'rack.input' => "",
|
||||
'warden' => OpenStruct.new(:message => nil)
|
||||
}.merge!(env_params)
|
||||
@@ -21,11 +22,6 @@ class FailureTest < ActiveSupport::TestCase
|
||||
@request = ActionDispatch::Request.new(env)
|
||||
end
|
||||
|
||||
def call_failure_with_http(env_params={})
|
||||
env = { "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("foo:bar")}" }
|
||||
call_failure(env_params.merge!(env))
|
||||
end
|
||||
|
||||
context 'When redirecting' do
|
||||
test 'return 302 status' do
|
||||
call_failure
|
||||
@@ -61,22 +57,41 @@ class FailureTest < ActiveSupport::TestCase
|
||||
assert_match /redirected/, @response.last.body
|
||||
assert_match /users\/sign_in/, @response.last.body
|
||||
end
|
||||
|
||||
test 'works for any navigational format' do
|
||||
swap Devise, :navigational_formats => [:xml] do
|
||||
call_failure('formats' => :xml)
|
||||
assert_equal 302, @response.first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'For HTTP request' do
|
||||
test 'return 401 status' do
|
||||
call_failure_with_http
|
||||
call_failure('formats' => :xml)
|
||||
assert_equal 401, @response.first
|
||||
end
|
||||
|
||||
test 'return WWW-authenticate headers' do
|
||||
call_failure_with_http
|
||||
call_failure('formats' => :xml)
|
||||
assert_equal 'Basic realm="Application"', @response.second["WWW-Authenticate"]
|
||||
end
|
||||
|
||||
test 'uses the proxy failure message as response body' do
|
||||
call_failure_with_http('warden' => OpenStruct.new(:message => :invalid))
|
||||
assert_equal 'Invalid email or password.', @response.third.body
|
||||
call_failure('formats' => :xml, 'warden' => OpenStruct.new(:message => :invalid))
|
||||
assert_match '<error>Invalid email or password.</error>', @response.third.body
|
||||
end
|
||||
|
||||
test 'works for any non navigational format' do
|
||||
swap Devise, :navigational_formats => [] do
|
||||
call_failure('formats' => :html)
|
||||
assert_equal 401, @response.first
|
||||
end
|
||||
end
|
||||
|
||||
test 'works for xml http requests' do
|
||||
call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
|
||||
assert_equal 401, @response.first
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
279
test/integration/authenticatable_test.rb
Normal file
279
test/integration/authenticatable_test.rb
Normal file
@@ -0,0 +1,279 @@
|
||||
require 'test_helper'
|
||||
|
||||
class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
test 'home should be accessible without sign in' do
|
||||
visit '/'
|
||||
assert_response :success
|
||||
assert_template 'home/index'
|
||||
end
|
||||
|
||||
test 'sign in as user should not authenticate admin scope' do
|
||||
sign_in_as_user
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign in as admin should not authenticate user scope' do
|
||||
sign_in_as_admin
|
||||
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'sign in as both user and admin at same time' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as user should not touch admin authentication' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_user_session_path
|
||||
assert_not warden.authenticated?(:user)
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as admin should not touch user authentication' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'not signed in as admin should not be able to access admins actions' do
|
||||
get admins_path
|
||||
|
||||
assert_redirected_to new_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'not signed in as admin should not be able to access private route restricted to admins' do
|
||||
get private_path
|
||||
|
||||
assert_redirected_to new_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'signed in as user should not be able to access private route restricted to admins' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
|
||||
get private_path
|
||||
assert_redirected_to new_admin_session_path
|
||||
end
|
||||
|
||||
test 'signed in as admin should be able to access private route restricted to admins' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
get private_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'home/private'
|
||||
assert_contain 'Private!'
|
||||
end
|
||||
|
||||
test 'signed in as user should not be able to access admins actions' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
|
||||
get admins_path
|
||||
assert_redirected_to new_admin_session_path
|
||||
end
|
||||
|
||||
test 'signed in as admin should be able to access admin actions' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
get admins_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'admins/index'
|
||||
assert_contain 'Welcome Admin'
|
||||
end
|
||||
|
||||
test 'authenticated admin should not be able to sign as admin again' do
|
||||
sign_in_as_admin
|
||||
get new_admin_session_path
|
||||
|
||||
assert_response :redirect
|
||||
assert_redirected_to admin_root_path
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'authenticated admin should be able to sign out' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
|
||||
get destroy_admin_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
get root_path
|
||||
assert_contain 'Signed out successfully'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'unauthenticated admin does not set message on sign out' do
|
||||
get destroy_admin_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
get root_path
|
||||
assert_not_contain 'Signed out successfully'
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationRedirectTest < ActionController::IntegrationTest
|
||||
test 'redirect from warden shows sign in or sign up message' do
|
||||
get admins_path
|
||||
|
||||
warden_path = new_admin_session_path
|
||||
assert_redirected_to warden_path
|
||||
|
||||
get warden_path
|
||||
assert_contain 'You need to sign in or sign up before continuing.'
|
||||
end
|
||||
|
||||
test 'redirect to default url if no other was configured' do
|
||||
sign_in_as_user
|
||||
assert_template 'home/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to requested url after sign in' do
|
||||
get users_path
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal users_path, session[:"user_return_to"]
|
||||
|
||||
follow_redirect!
|
||||
sign_in_as_user :visit => false
|
||||
|
||||
assert_template 'users/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to last requested url overwriting the stored return_to option' do
|
||||
get expire_user_path(create_user)
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal expire_user_path(create_user), session[:"user_return_to"]
|
||||
|
||||
get users_path
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal users_path, session[:"user_return_to"]
|
||||
|
||||
follow_redirect!
|
||||
sign_in_as_user :visit => false
|
||||
|
||||
assert_template 'users/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'xml http requests does not store urls for redirect' do
|
||||
get users_path, {}, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
|
||||
assert_equal 401, response.status
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to configured home path for a given scope after sign in' do
|
||||
sign_in_as_admin
|
||||
assert_equal "/admin_area/home", @request.path
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationSessionTest < ActionController::IntegrationTest
|
||||
test 'destroyed account is signed out' do
|
||||
sign_in_as_user
|
||||
get '/users'
|
||||
|
||||
User.destroy_all
|
||||
get '/users'
|
||||
assert_redirected_to new_user_session_path
|
||||
end
|
||||
|
||||
test 'allows session to be set by a given scope' do
|
||||
sign_in_as_user
|
||||
get '/users'
|
||||
assert_equal "Cart", @controller.user_session[:cart]
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationWithScopesTest < ActionController::IntegrationTest
|
||||
test 'renders the scoped view if turned on and view is available' do
|
||||
swap Devise, :scoped_views => true do
|
||||
assert_raise Webrat::NotFoundError do
|
||||
sign_in_as_user
|
||||
end
|
||||
assert_match /Special user view/, response.body
|
||||
end
|
||||
end
|
||||
|
||||
test 'renders the scoped view if turned on in an specific controller' do
|
||||
begin
|
||||
Devise::SessionsController.scoped_views = true
|
||||
assert_raise Webrat::NotFoundError do
|
||||
sign_in_as_user
|
||||
end
|
||||
|
||||
assert_match /Special user view/, response.body
|
||||
assert !Devise::PasswordsController.scoped_views?
|
||||
ensure
|
||||
Devise::SessionsController.send :remove_instance_variable, :@scoped_views
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not render the scoped view if turned off' do
|
||||
swap Devise, :scoped_views => false do
|
||||
assert_nothing_raised do
|
||||
sign_in_as_user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not render the scoped view if not available' do
|
||||
swap Devise, :scoped_views => true do
|
||||
assert_nothing_raised do
|
||||
sign_in_as_admin
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'uses the mapping from the default scope if specified' do
|
||||
swap Devise, :use_default_scope => true do
|
||||
get '/sign_in'
|
||||
assert_response :ok
|
||||
assert_contain 'Sign in'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationOthersTest < ActionController::IntegrationTest
|
||||
test 'uses the custom controller with the custom controller view' do
|
||||
get '/admin_area/sign_in'
|
||||
assert_contain 'Sign in'
|
||||
assert_contain 'Welcome to "sessions" controller!'
|
||||
assert_contain 'Welcome to "sessions/new" view!'
|
||||
end
|
||||
|
||||
test 'render 404 on roles without routes' do
|
||||
get '/admin_area/password/new'
|
||||
assert_equal 404, response.status
|
||||
end
|
||||
|
||||
test 'render 404 on roles without mapping' do
|
||||
assert_raise AbstractController::ActionNotFound do
|
||||
get '/sign_in'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -26,7 +26,7 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'confirmations/new'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Confirmation token(.*)invalid/
|
||||
end
|
||||
|
||||
@@ -49,7 +49,7 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
assert_template 'confirmations/new'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain 'already confirmed'
|
||||
end
|
||||
|
||||
|
||||
@@ -1,113 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class DatabaseAuthenticationSanityTest < ActionController::IntegrationTest
|
||||
test 'home should be accessible without sign in' do
|
||||
visit '/'
|
||||
assert_response :success
|
||||
assert_template 'home/index'
|
||||
end
|
||||
|
||||
test 'sign in as user should not authenticate admin scope' do
|
||||
sign_in_as_user
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign in as admin should not authenticate user scope' do
|
||||
sign_in_as_admin
|
||||
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'sign in as both user and admin at same time' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as user should not touch admin authentication' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_user_session_path
|
||||
assert_not warden.authenticated?(:user)
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as admin should not touch user authentication' do
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'not signed in as admin should not be able to access admins actions' do
|
||||
get admins_path
|
||||
|
||||
assert_redirected_to new_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'signed in as user should not be able to access admins actions' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
|
||||
get admins_path
|
||||
assert_redirected_to new_admin_session_path
|
||||
end
|
||||
|
||||
test 'signed in as admin should be able to access admin actions' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
get admins_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'admins/index'
|
||||
assert_contain 'Welcome Admin'
|
||||
end
|
||||
|
||||
test 'authenticated admin should not be able to sign as admin again' do
|
||||
sign_in_as_admin
|
||||
get new_admin_session_path
|
||||
|
||||
assert_response :redirect
|
||||
assert_redirected_to admin_root_path
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'authenticated admin should be able to sign out' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
|
||||
get destroy_admin_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
get root_path
|
||||
assert_contain 'Signed out successfully'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'unauthenticated admin does not set message on sign out' do
|
||||
get destroy_admin_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
get root_path
|
||||
assert_not_contain 'Signed out successfully'
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationTest < ActionController::IntegrationTest
|
||||
class DatabaseAuthenticationTest < ActionController::IntegrationTest
|
||||
test 'sign in should not authenticate if not using proper authentication keys' do
|
||||
swap Devise, :authentication_keys => [:username] do
|
||||
sign_in_as_user
|
||||
@@ -142,157 +35,4 @@ class AuthenticationTest < ActionController::IntegrationTest
|
||||
assert_contain 'Invalid credentials'
|
||||
end
|
||||
end
|
||||
|
||||
test 'redirect from warden shows sign in or sign up message' do
|
||||
get admins_path
|
||||
|
||||
warden_path = new_admin_session_path
|
||||
assert_redirected_to warden_path
|
||||
|
||||
get warden_path
|
||||
assert_contain 'You need to sign in or sign up before continuing.'
|
||||
end
|
||||
|
||||
test 'redirect to default url if no other was configured' do
|
||||
sign_in_as_user
|
||||
|
||||
assert_template 'home/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to requested url after sign in' do
|
||||
get users_path
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal users_path, session[:"user_return_to"]
|
||||
|
||||
follow_redirect!
|
||||
sign_in_as_user :visit => false
|
||||
|
||||
assert_template 'users/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to last requested url overwriting the stored return_to option' do
|
||||
get expire_user_path(create_user)
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal expire_user_path(create_user), session[:"user_return_to"]
|
||||
|
||||
get users_path
|
||||
assert_redirected_to new_user_session_path
|
||||
assert_equal users_path, session[:"user_return_to"]
|
||||
|
||||
follow_redirect!
|
||||
sign_in_as_user :visit => false
|
||||
|
||||
assert_template 'users/index'
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'redirect to configured home path for a given scope after sign in' do
|
||||
sign_in_as_admin
|
||||
assert_equal "/admin_area/home", @request.path
|
||||
end
|
||||
|
||||
test 'destroyed account is signed out' do
|
||||
sign_in_as_user
|
||||
get '/users'
|
||||
|
||||
User.destroy_all
|
||||
get '/users'
|
||||
assert_redirected_to new_user_session_path
|
||||
end
|
||||
|
||||
test 'allows session to be set by a given scope' do
|
||||
sign_in_as_user
|
||||
get '/users'
|
||||
assert_equal "Cart", @controller.user_session[:cart]
|
||||
end
|
||||
|
||||
# Scoped views
|
||||
test 'renders the scoped view if turned on and view is available' do
|
||||
swap Devise, :scoped_views => true do
|
||||
assert_raise Webrat::NotFoundError do
|
||||
sign_in_as_user
|
||||
end
|
||||
assert_match /Special user view/, response.body
|
||||
end
|
||||
end
|
||||
|
||||
test 'renders the scoped view if turned on in an specific controller' do
|
||||
begin
|
||||
Devise::SessionsController.scoped_views = true
|
||||
assert_raise Webrat::NotFoundError do
|
||||
sign_in_as_user
|
||||
end
|
||||
|
||||
assert_match /Special user view/, response.body
|
||||
assert !Devise::PasswordsController.scoped_views?
|
||||
ensure
|
||||
Devise::SessionsController.send :remove_instance_variable, :@scoped_views
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not render the scoped view if turned off' do
|
||||
swap Devise, :scoped_views => false do
|
||||
assert_nothing_raised do
|
||||
sign_in_as_user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not render the scoped view if not available' do
|
||||
swap Devise, :scoped_views => true do
|
||||
assert_nothing_raised do
|
||||
sign_in_as_admin
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Default scope
|
||||
test 'uses the mapping from the default scope if specified' do
|
||||
swap Devise, :use_default_scope => true do
|
||||
get '/sign_in'
|
||||
assert_response :ok
|
||||
assert_contain 'Sign in'
|
||||
end
|
||||
end
|
||||
|
||||
# Custom controller
|
||||
test 'uses the custom controller with the custom controller view' do
|
||||
get '/admin_area/sign_in'
|
||||
assert_contain 'Sign in'
|
||||
assert_contain 'Welcome to "sessions" controller!'
|
||||
assert_contain 'Welcome to "sessions/new" view!'
|
||||
end
|
||||
|
||||
# Custom strategy invoking custom!
|
||||
test 'custom strategy invoking custom on sign up bevahes as expected' do
|
||||
Warden::Strategies.add(:custom) do
|
||||
def authenticate!
|
||||
custom!([401, {"Content-Type" => "text/html"}, ["Custom strategy"]])
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
Devise.warden_config.default_strategies(:scope => :user).unshift(:custom)
|
||||
sign_in_as_user
|
||||
assert_equal 401, status
|
||||
assert_contain 'Custom strategy'
|
||||
ensure
|
||||
Devise.warden_config.default_strategies(:scope => :user).shift
|
||||
end
|
||||
end
|
||||
|
||||
# Access
|
||||
test 'render 404 on roles without permission' do
|
||||
get '/admin_area/password/new', {}, "action_dispatch.show_exceptions" => true
|
||||
assert_response :not_found
|
||||
assert_not_contain 'Send me reset password instructions'
|
||||
end
|
||||
|
||||
test 'render 404 on roles without mapping' do
|
||||
get '/sign_in', {}, "action_dispatch.show_exceptions" => true
|
||||
assert_response :not_found
|
||||
assert_not_contain 'Sign in'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,8 +5,7 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
test 'sign in should authenticate with http' do
|
||||
sign_in_as_new_user_with_http
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
@@ -17,10 +16,10 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
test 'uses the request format as response content type' do
|
||||
sign_in_as_new_user_with_http("unknown", "123456", :xml)
|
||||
sign_in_as_new_user_with_http("unknown")
|
||||
assert_equal 401, status
|
||||
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
|
||||
assert response.body.include?("<error>Invalid email or password.</error>")
|
||||
assert_match "<error>Invalid email or password.</error>", response.body
|
||||
end
|
||||
|
||||
test 'returns a custom response with www-authenticate and chosen realm' do
|
||||
@@ -33,19 +32,18 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
|
||||
test 'sign in should authenticate with http even with specific authentication keys' do
|
||||
swap Devise, :authentication_keys => [:username] do
|
||||
sign_in_as_new_user_with_http "usertest"
|
||||
sign_in_as_new_user_with_http("usertest")
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sign_in_as_new_user_with_http(username="user@test.com", password="123456", format=:html)
|
||||
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
|
||||
user = create_user
|
||||
get users_path(:format => format), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
|
||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
|
||||
user
|
||||
end
|
||||
end
|
||||
@@ -37,8 +37,16 @@ class LockTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
test 'unlocked pages should not be available if email strategy is disabled' do
|
||||
visit new_user_unlock_path
|
||||
visit "/users/sign_in"
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
|
||||
swap Devise, :unlock_strategy => :time do
|
||||
visit "/users/sign_in"
|
||||
|
||||
assert_raise Webrat::NotFoundError do
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
end
|
||||
|
||||
assert_raise AbstractController::ActionNotFound do
|
||||
visit new_user_unlock_path
|
||||
end
|
||||
@@ -50,7 +58,7 @@ class LockTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'unlocks/new'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Unlock token(.*)invalid/
|
||||
end
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'passwords/edit'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Reset password token(.*)invalid/
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
end
|
||||
@@ -91,7 +91,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'passwords/edit'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain 'Password doesn\'t match confirmation'
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
end
|
||||
@@ -113,7 +113,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
fill_in 'Password confirmation', :with => 'other_password'
|
||||
end
|
||||
assert_response :success
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
|
||||
reset_password :reset_password_token => user.reload.reset_password_token, :visit => false
|
||||
|
||||
@@ -48,7 +48,7 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_template 'registrations/new'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain "Email is invalid"
|
||||
assert_contain "Password doesn't match confirmation"
|
||||
assert_nil User.first
|
||||
@@ -113,7 +113,6 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
assert_equal "user@test.com", User.first.email
|
||||
end
|
||||
|
||||
|
||||
test 'a signed in user should be able to edit his password' do
|
||||
sign_in_as_user
|
||||
get edit_user_registration_path
|
||||
@@ -129,6 +128,19 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
assert User.first.valid_password?('pas123')
|
||||
end
|
||||
|
||||
test 'a signed in user should not be able to edit his password with invalid confirmation' do
|
||||
sign_in_as_user
|
||||
get edit_user_registration_path
|
||||
|
||||
fill_in 'password', :with => 'pas123'
|
||||
fill_in 'password confirmation', :with => ''
|
||||
fill_in 'current password', :with => '123456'
|
||||
click_button 'Update'
|
||||
|
||||
assert_contain "Password doesn't match confirmation"
|
||||
assert_not User.first.valid_password?('pas123')
|
||||
end
|
||||
|
||||
test 'a signed in user should be able to cancel his account' do
|
||||
sign_in_as_user
|
||||
get edit_user_registration_path
|
||||
@@ -138,4 +150,4 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
|
||||
assert User.all.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,19 +12,31 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
def generate_signed_cookie(raw_cookie)
|
||||
request = ActionDispatch::Request.new({})
|
||||
request = ActionDispatch::TestRequest.new
|
||||
request.cookie_jar.signed['raw_cookie'] = raw_cookie
|
||||
request.cookie_jar['raw_cookie']
|
||||
end
|
||||
|
||||
test 'do not remember the user if he has not checked remember me option' do
|
||||
user = sign_in_as_user
|
||||
assert_nil request.cookies["remember_user_cookie"]
|
||||
assert_nil user.reload.remember_token
|
||||
end
|
||||
|
||||
test 'generate remember token after sign in' do
|
||||
user = sign_in_as_user :remember_me => true
|
||||
assert_not_nil user.reload.remember_token
|
||||
assert request.cookies["remember_user_token"]
|
||||
assert user.reload.remember_token
|
||||
end
|
||||
|
||||
test 'generate remember token after sign in setting cookie domain' do
|
||||
# We test this by asserting the cookie is not sent after the redirect
|
||||
# since we changed the domain. This is the only difference with the
|
||||
# previous test.
|
||||
swap User, :cookie_domain => "omg.somewhere.com" do
|
||||
user = sign_in_as_user :remember_me => true
|
||||
assert_nil request.cookies["remember_user_token"]
|
||||
end
|
||||
end
|
||||
|
||||
test 'remember the user before sign in' do
|
||||
@@ -35,7 +47,7 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
assert warden.user(:user) == user
|
||||
end
|
||||
|
||||
test 'does not remember other scopes' do
|
||||
test 'do not remember other scopes' do
|
||||
user = create_user_and_remember
|
||||
get root_path
|
||||
assert_response :success
|
||||
@@ -50,7 +62,7 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
assert_redirected_to new_user_session_path
|
||||
end
|
||||
|
||||
test 'do not remember with token expired' do
|
||||
test 'do not remember with expired token' do
|
||||
user = create_user_and_remember
|
||||
swap Devise, :remember_for => 0 do
|
||||
get users_path
|
||||
|
||||
@@ -36,6 +36,18 @@ class SessionTimeoutTest < ActionController::IntegrationTest
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'time out is not triggered on sign out' do
|
||||
user = sign_in_as_user
|
||||
get expire_user_path(user)
|
||||
|
||||
get destroy_user_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
follow_redirect!
|
||||
assert_contain 'Signed out successfully'
|
||||
end
|
||||
|
||||
test 'user configured timeout limit' do
|
||||
swap Devise, :timeout_in => 8.minutes do
|
||||
user = sign_in_as_user
|
||||
|
||||
@@ -18,8 +18,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
sign_in_as_new_user_with_token(:http_auth => true)
|
||||
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
@@ -78,7 +77,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
|
||||
if options[:http_auth]
|
||||
header = "Basic #{ActiveSupport::Base64.encode64("#{VALID_AUTHENTICATION_TOKEN}:X")}"
|
||||
get users_path, {}, "HTTP_AUTHORIZATION" => header
|
||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => header
|
||||
else
|
||||
visit users_path(options[:auth_token_key].to_sym => options[:auth_token])
|
||||
end
|
||||
|
||||
@@ -36,13 +36,13 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => 'Account Confirmation' } } do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => { :subject => 'Account Confirmation' } } } do
|
||||
assert_equal 'Account Confirmation', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :confirmation_instructions => 'User Account Confirmation' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => { :user_subject => 'User Account Confirmation' } } } do
|
||||
assert_equal 'User Account Confirmation', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,13 +39,13 @@ class ResetPasswordInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => 'Reset instructions' } } do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => { :subject => 'Reset instructions' } } } do
|
||||
assert_equal 'Reset instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :reset_password_instructions => 'User Reset Instructions' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => { :user_subject => 'User Reset Instructions' } } } do
|
||||
assert_equal 'User Reset Instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,13 +39,13 @@ class UnlockInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => 'Unlock instructions' } } do
|
||||
assert_equal 'Unlock instructions', mail.subject
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => { :subject => 'Yo unlock instructions' } } } do
|
||||
assert_equal 'Yo unlock instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :unlock_instructions => 'User Unlock Instructions' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => { :user_subject => 'User Unlock Instructions' } } } do
|
||||
assert_equal 'User Unlock Instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,15 +6,17 @@ class MappingTest < ActiveSupport::TestCase
|
||||
mapping = Devise.mappings[:user]
|
||||
assert_equal User, mapping.to
|
||||
assert_equal User.devise_modules, mapping.modules
|
||||
assert_equal :users, mapping.as
|
||||
assert_equal :users, mapping.plural
|
||||
assert_equal :user, mapping.singular
|
||||
assert_equal :users, mapping.path
|
||||
end
|
||||
|
||||
test 'allows as to be given' do
|
||||
assert_equal :admin_area, Devise.mappings[:admin].as
|
||||
test 'allows path to be given' do
|
||||
assert_equal :admin_area, Devise.mappings[:admin].path
|
||||
end
|
||||
|
||||
test 'allows custom scope to be given' do
|
||||
assert_equal :accounts, Devise.mappings[:manager].as
|
||||
test 'allows custom singular to be given' do
|
||||
assert_equal :accounts, Devise.mappings[:manager].path
|
||||
end
|
||||
|
||||
test 'allows a controller depending on the mapping' do
|
||||
@@ -91,13 +93,13 @@ class MappingTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'retrieve as from the proper position' do
|
||||
assert_equal 1, Devise.mappings[:user].as_position
|
||||
assert_equal 2, Devise.mappings[:manager].as_position
|
||||
assert_equal 1, Devise.mappings[:user].segment_position
|
||||
assert_equal 2, Devise.mappings[:manager].segment_position
|
||||
end
|
||||
|
||||
test 'path is returned with path prefix and as' do
|
||||
assert_equal '/users', Devise.mappings[:user].path
|
||||
assert_equal '/:locale/accounts', Devise.mappings[:manager].path
|
||||
assert_equal '/users', Devise.mappings[:user].full_path
|
||||
assert_equal '/:locale/accounts', Devise.mappings[:manager].full_path
|
||||
end
|
||||
|
||||
test 'magic predicates' do
|
||||
|
||||
@@ -127,6 +127,14 @@ class ConfirmableTest < ActiveSupport::TestCase
|
||||
User.send_confirmation_instructions(:email => user.email)
|
||||
end
|
||||
end
|
||||
|
||||
test 'should always have confirmation token when email is sent' do
|
||||
user = new_user
|
||||
user.instance_eval { def confirmation_required?; false end }
|
||||
user.save
|
||||
user.send_confirmation_instructions
|
||||
assert_not_nil user.confirmation_token
|
||||
end
|
||||
|
||||
test 'should not resend email instructions if the user change his email' do
|
||||
user = create_user
|
||||
@@ -202,4 +210,12 @@ class ConfirmableTest < ActiveSupport::TestCase
|
||||
user.save
|
||||
assert_not user.reload.active?
|
||||
end
|
||||
|
||||
test 'should be active without confirmation when confirmation is not required' do
|
||||
user = create_user
|
||||
user.instance_eval { def confirmation_required?; false end }
|
||||
user.confirmation_sent_at = nil
|
||||
user.save
|
||||
assert user.reload.active?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,22 @@ require 'digest/sha1'
|
||||
|
||||
class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
|
||||
def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encryptor=::Devise::Encryptors::Sha1)
|
||||
def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encryptor=User.encryptor_class)
|
||||
encryptor.digest('123456', stretches, user.password_salt, pepper)
|
||||
end
|
||||
|
||||
def swap_with_encryptor(klass, encryptor, options={})
|
||||
klass.instance_variable_set(:@encryptor_class, nil)
|
||||
|
||||
swap klass, options.merge(:encryptor => encryptor) do
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
klass.instance_variable_set(:@encryptor_class, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'should respond to password and password confirmation' do
|
||||
user = new_user
|
||||
assert user.respond_to?(:password)
|
||||
@@ -28,8 +40,10 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'should generate a base64 hash using SecureRandom for password salt' do
|
||||
ActiveSupport::SecureRandom.expects(:base64).with(15).returns('friendly_token')
|
||||
assert_equal 'friendly_token', new_user.password_salt
|
||||
swap_with_encryptor User, :sha1 do
|
||||
ActiveSupport::SecureRandom.expects(:base64).with(15).returns('friendly_token')
|
||||
assert_equal 'friendly_token', new_user.password_salt
|
||||
end
|
||||
end
|
||||
|
||||
test 'should not generate salt if password is blank' do
|
||||
@@ -71,24 +85,10 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test 'should fallback to devise stretches default configuration' do
|
||||
swap Devise, :stretches => 1 do
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user, nil, 1), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, nil, 2), user.encrypted_password
|
||||
end
|
||||
end
|
||||
|
||||
test 'should respect encryptor configuration' do
|
||||
User.instance_variable_set(:@encryptor_class, nil)
|
||||
|
||||
swap Devise, :encryptor => :sha512 do
|
||||
begin
|
||||
user = create_user
|
||||
assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512)
|
||||
ensure
|
||||
User.instance_variable_set(:@encryptor_class, nil)
|
||||
end
|
||||
swap_with_encryptor User, :sha512 do
|
||||
user = create_user
|
||||
assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should respect maximum attempts configuration" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
swap Devise, :maximum_attempts => 2 do
|
||||
3.times { user.valid_for_authentication?{ false } }
|
||||
assert user.reload.access_locked?
|
||||
@@ -15,6 +16,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should clear failed_attempts on successfull validation" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
user.valid_for_authentication?{ false }
|
||||
assert_equal 1, user.reload.failed_attempts
|
||||
user.valid_for_authentication?{ true }
|
||||
@@ -23,6 +25,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should not touch failed_attempts if lock_strategy is none" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
swap Devise, :lock_strategy => :none, :maximum_attempts => 2 do
|
||||
3.times { user.valid_for_authentication?{ false } }
|
||||
assert !user.access_locked?
|
||||
@@ -61,7 +64,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
user.unlock_access!
|
||||
assert_nil user.reload.locked_at
|
||||
assert_nil user.reload.unlock_token
|
||||
assert 0, user.reload.failed_attempts
|
||||
assert_equal 0, user.reload.failed_attempts
|
||||
end
|
||||
|
||||
test 'should not unlock an unlocked user' do
|
||||
|
||||
@@ -18,19 +18,19 @@ class RememberableTest < ActiveSupport::TestCase
|
||||
test 'forget_me should clear remember token and save the record without validating' do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
assert user.remember_token?
|
||||
assert_not user.remember_token.nil?
|
||||
user.expects(:valid?).never
|
||||
user.forget_me!
|
||||
assert_not user.remember_token?
|
||||
assert user.remember_token.nil?
|
||||
assert_not user.changed?
|
||||
end
|
||||
|
||||
test 'forget_me should clear remember_created_at' do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
assert user.remember_created_at?
|
||||
assert_not user.remember_created_at.nil?
|
||||
user.forget_me!
|
||||
assert_not user.remember_created_at?
|
||||
assert user.remember_created_at.nil?
|
||||
end
|
||||
|
||||
test 'forget should do nothing if no remember token exists' do
|
||||
|
||||
@@ -2,13 +2,6 @@ require 'test_helper'
|
||||
|
||||
class TokenAuthenticatableTest < ActiveSupport::TestCase
|
||||
|
||||
test 'should generate friendly authentication token on create' do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
assert_present user.authentication_token
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
end
|
||||
|
||||
test 'should reset authentication token' do
|
||||
user = new_user
|
||||
user.reset_authentication_token
|
||||
@@ -26,18 +19,18 @@ class TokenAuthenticatableTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'should authenticate a valid user with authentication token and return it' do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
user.ensure_authentication_token!
|
||||
user.confirm!
|
||||
authenticated_user = User.authenticate_with_token(:auth_token => user.authentication_token)
|
||||
authenticated_user = User.find_for_token_authentication(:auth_token => user.authentication_token)
|
||||
assert_equal authenticated_user, user
|
||||
end
|
||||
|
||||
test 'should return nil when authenticating an invalid user by authentication token' do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
user.ensure_authentication_token!
|
||||
user.confirm!
|
||||
authenticated_user = User.authenticate_with_token(:auth_token => user.authentication_token.reverse)
|
||||
authenticated_user = User.find_for_token_authentication(:auth_token => user.authentication_token.reverse)
|
||||
assert_nil authenticated_user
|
||||
end
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Configurable < User
|
||||
devise :authenticatable, :confirmable, :rememberable, :timeoutable, :lockable,
|
||||
devise :database_authenticatable, :confirmable, :rememberable, :timeoutable, :lockable,
|
||||
:stretches => 15, :pepper => 'abcdef', :confirm_within => 5.days,
|
||||
:remember_for => 7.days, :timeout_in => 15.minutes, :unlock_in => 10.days
|
||||
end
|
||||
|
||||
class Inheritable < Admin
|
||||
end
|
||||
|
||||
class ActiveRecordTest < ActiveSupport::TestCase
|
||||
def include_module?(klass, mod)
|
||||
klass.devise_modules.include?(mod) &&
|
||||
@@ -22,10 +25,14 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test 'add modules cherry pick' do
|
||||
test 'can cherry pick modules' do
|
||||
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
end
|
||||
|
||||
test 'chosen modules are inheritable' do
|
||||
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
end
|
||||
|
||||
test 'order of module inclusion' do
|
||||
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :timeoutable]
|
||||
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable]
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
require 'rails/test_help'
|
||||
|
||||
DataMapper.auto_migrate!
|
||||
|
||||
class ActiveSupport::TestCase
|
||||
setup do
|
||||
User.all.destroy!
|
||||
Admin.all.destroy!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Admin < ActiveRecord::Base
|
||||
devise :authenticatable, :registerable, :timeoutable, :recoverable
|
||||
devise :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
end
|
||||
|
||||
2
test/rails_app/app/active_record/shim.rb
Normal file
2
test/rails_app/app/active_record/shim.rb
Normal file
@@ -0,0 +1,2 @@
|
||||
module Shim
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
class User < ActiveRecord::Base
|
||||
devise :authenticatable, :http_authenticatable, :confirmable, :lockable, :recoverable,
|
||||
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
|
||||
:registerable, :rememberable, :timeoutable, :token_authenticatable,
|
||||
:trackable, :validatable
|
||||
|
||||
|
||||
@@ -5,4 +5,5 @@ class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
before_filter :current_user
|
||||
before_filter :authenticate_user!, :if => :devise_controller?
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user