Compare commits

...

116 Commits

Author SHA1 Message Date
José Valim
748eced9e8 Release RC2 (for Rails 3.0.0.beta4) 2010-06-23 12:39:04 +02:00
José Valim
a39312e26b Ensure flash messages work with Devise::TestHelper, closes #327 2010-06-23 12:39:04 +02:00
José Valim
b2c2cb272f Revert "Track Deprecation of :name_prefix in Rails 3 RC"
Let's wait until a new Rails 3 release is out before applying this to maintain compatibility with Rails 3 beta 4.

This reverts commit 21874d8559.
2010-06-23 12:39:04 +02:00
José Valim
fccde42f20 Do not show model exist message on revoke behavior, closes #334 2010-06-23 12:39:04 +02:00
Jared Morgan
e90732c8c3 Remove #save! method from test DM User model
DM has a #save! method, so it's no longer needed. Having it call #save
caused #valid? to be called where tests were expecting validations to be
skipped.
2010-06-23 18:38:39 +08:00
bodhi
21874d8559 Track Deprecation of :name_prefix in Rails 3 RC 2010-06-23 14:56:01 +08:00
José Valim
cfadaf80a2 Merge with jm81 and snusnu datamapper forks. 2010-06-22 21:01:37 +02:00
José Valim
df444663ac Bring datamapper Gemfile back. 2010-06-22 21:00:46 +02:00
Jared Morgan
5b63605c94 Add dm-serializer to Gemfile so DM models respond to #to_xml
Fixes 3 Missing template errors
2010-06-22 11:00:36 -05:00
José Valim
3660cbac30 Do not execute after initializers if production. 2010-06-21 14:07:58 +02:00
José Valim
92cf50454b Add Rails 3 + Mongoid example to the README. 2010-06-20 01:29:53 -07:00
Postmodern
29ba790e07 Do not use ActiveRecord only methods in tests. 2010-06-19 17:30:10 -07:00
snusnu
4e2cd157c1 Specs surely don't pass, but they run at least! 2010-06-19 17:30:10 -07:00
snusnu
194959f312 Updated Gemfile to include DataMapper-1.0.0 (from git for now) 2010-06-19 17:30:10 -07:00
José Valim
e3b815de49 Bring encrypted password limit back. 2010-06-18 22:00:31 +02:00
José Valim
ac0105d15f No need to limit password. 2010-06-17 00:36:09 -07:00
Carlos Antonio da Silva
7dbd2eac2a Confirmable is not default anymore, so remove it from generated migration. 2010-06-17 01:57:42 -03:00
José Valim
025c3875b6 Update gemspec, closes #316. 2010-06-13 21:48:43 +02:00
José Valim
f1a990c2ae Do not show messages if eager loading to call help. 2010-06-13 13:34:49 +02:00
José Valim
1f4a31f1cf Update generators to use Rails 3 syntax, i.e devise:install instead of devise_install. 2010-06-13 13:10:33 +02:00
José Valim
31910b85a2 Regenerate .gemspec 2010-06-13 12:40:40 +02:00
José Valim
5e1ef9319e Check if the user is already signing out before timing out his connection, closes #273. 2010-06-13 12:40:13 +02:00
José Valim
70a429d9ff Split tests files a bit. 2010-06-13 12:11:15 +02:00
José Valim
f16d01869a Rename apply_schema to apply_devise_schema and refactor Mongoid part a bit. 2010-06-13 11:48:45 +02:00
José Valim
290cfd1f72 Be more generic on TestHelpers. 2010-06-13 11:09:59 +02:00
José Valim
ed22295963 Fix a couple things based on community feedback (love ya!) 2010-06-13 10:51:46 +02:00
José Valim
a2f84852af Allow the mailer class to be configured. 2010-06-12 20:56:55 +02:00
José Valim
c4a4032b6b Use ActiveSupport::Dependencies.ref to abstract constant lookup logic. 2010-06-12 20:48:37 +02:00
José Valim
80895c3b9a Make I18n key for mailer compatible with lookup shortcuts, closes #245 2010-06-12 20:29:43 +02:00
José Valim
84686d285c Be more clear that Rails 2.3 users should use the v1.0 branch README. 2010-06-12 06:56:15 -07:00
José Valim
6c18c92598 Update gemspec. 2010-06-12 15:30:43 +02:00
José Valim
0333caeb92 Make bcrypt the default encryptor and automatically add a pepper on generation. 2010-06-12 14:46:55 +02:00
José Valim
bece09c653 Comment out datamapper scenario because it simply does not work currently. 2010-06-12 13:30:55 +02:00
SSDany
cd78a26f88 add #anybody_signed_in? to helpers 2010-06-12 05:11:04 +08:00
SSDany
5c9fe5e769 anybody_signed_in? helper 2010-06-12 05:11:03 +08:00
José Valim
fb0aec09f1 Talk about beta 4 in the README. 2010-06-11 09:10:36 -07:00
José Valim
5f2a19d784 Also need a klass reader. 2010-06-09 02:50:45 -07:00
José Valim
cc608f82dd Properly check if devise method is present. 2010-06-09 02:50:28 -07:00
José Valim
7e784b258c Update Devise generator error message. 2010-06-09 02:41:30 -07:00
José Valim
870912d458 beta 4 works, yay. 2010-06-09 01:27:38 +02:00
Lloyd Pick
f0c0f5f11b fixed a few spelling/grammar mistakes 2010-05-28 20:24:39 +08:00
Antonio Tapiador del Dujo
7dc1842cc4 Add note about default routes in devise configuration 2010-05-25 18:58:20 +08:00
José Valim
28b10e397f Update CHANGELOG 2010-05-25 00:03:03 +02:00
Alexander Uvarov
6ff77c9fdf Add merb-auth like router helper 2010-05-25 05:51:32 +08:00
José Valim
d98882d745 Tidy up previous commit. 2010-05-24 22:50:25 +02:00
Joseph DelCioppio
80977c6dee Added after_update_path to registrations controller. Users can now specify the path that their app should return to after updated a resource. If not specified it will return to the root, or the resource's root if specified. 2010-05-25 04:25:32 +08:00
José Valim
7c82d3ee67 Move the generator bit to the top. 2010-05-21 07:42:34 -07:00
José Valim
0150fddb4c Depends on warden 0.10.5. 2010-05-20 01:24:11 +02:00
bodhi
c8ec42a41c Update documentation to track deprecation of :as in #devise_for 2010-05-19 15:50:48 +08:00
José Valim
bff64a6291 Added navigational formats to specify when it should return a 302 and when a 401, closes #234 and #249. 2010-05-16 19:13:38 +02:00
José Valim
a65fd873dd Update CHANGELOG 2010-05-16 14:55:35 +02:00
Paul Rosania
592fa59e88 Automatically create the confirmation_token when email is sent for optionally confirmable models
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 14:54:05 +02:00
Paul Rosania
02c2df65cd Mark confirmable roles as active when confirmation_required? is false
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 14:53:08 +02:00
José Valim
59bee679ca Add tests to cookie domain, closes #254. 2010-05-16 14:13:56 +02:00
Mantas Masalskis
21129ae38c custom domain cookie support
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 12:30:00 +02:00
José Valim
f1bbce58f3 Add tests to previous commit. 2010-05-16 12:14:02 +02:00
Davide Marquês
8e173f486c Enable :registration in the :path_names configuration option.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 12:00:43 +02:00
José Valim
e905762611 Clean up the whole loading mess and closes #247. This commit depends on latest Rails. 2010-05-16 00:38:40 +02:00
José Valim
d38421dde8 Green tests on Rails master, closes #261 2010-05-15 10:39:11 +02:00
José Valim
6162e1f5ff Devise install now accepts --orm option. 2010-05-15 10:28:29 +02:00
José Valim
08c5179869 Update registerable on readme. 2010-05-11 02:37:46 -07:00
José Valim
bb39243da2 data_mapper uses underscore (ht: Yehuda Katz) 2010-05-05 02:28:40 -07:00
José Valim
9bdc711324 Update README. 2010-05-03 14:00:32 +02:00
José Valim
a4351b0b77 Update master CHANGELOG. 2010-05-03 13:57:57 +02:00
José Valim
416bff3daa Merge branch 'master' of github.com:plataformatec/devise 2010-05-03 00:12:58 +02:00
José Valim
07204c500d Confirmable is not default anymore. This provides a better bootstrap experience. 2010-05-03 00:08:48 +02:00
gitman
f5bc66521f patch-244 for improving commented help for :confirmable configuration
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-03 00:06:16 +02:00
Britto
fb0f8fcd0d typo 2010-04-29 05:45:44 +08:00
José Valim
61fbec858e Add a missing TODO 2010-04-26 07:34:06 -07:00
José Valim
25302de1f8 Add a link to the second screencast to the README. 2010-04-25 10:02:51 +02:00
José Valim
b86c1c241b Use markup in views as Ryan Bates does in the screencast. 2010-04-25 10:02:11 +02:00
José Valim
2bf9e462fa Update CHANGELOG. 2010-04-25 09:59:10 +02:00
Jacques Crocker
57712737b2 Fixing up devise generator for mongoid and datamapper. Will insert devise configuration after the module include so that it works, closes #226.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-25 09:47:14 +02:00
Ryan Booker
c582e9cb0f Fix grammar in notice, closes #229
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-25 09:44:04 +02:00
José Valim
d750b48879 Include model_session helpers in view, closes #227 2010-04-25 09:40:07 +02:00
José Valim
708fe78d86 Ensure password confirmation is always required, closes #228 2010-04-25 09:38:56 +02:00
José Valim
41311eb38d Move mailer configuration to the app. 2010-04-25 09:26:51 +02:00
José Valim
da971e4249 .bundle directory should NOT be ignored. 2010-04-23 13:51:10 +02:00
hpoydar
eb23ca0ca7 Include bson_ext in Gemfile
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-23 13:50:49 +02:00
hpoydar
c9fe7900c3 Removed references to mongo_ext, since mongoid now uses bson_ext
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-23 13:50:41 +02:00
José Valim
9d6a78f7f4 Add ldap_authenticatable to README. 2010-04-22 20:55:27 +02:00
José Valim
4da63c5395 Ensure routes are loaded before application classes are eager loaded, closes #212. 2010-04-22 19:59:52 +02:00
José Valim
b5f892bcdb No need to check if AR is defined. 2010-04-20 17:22:16 +02:00
José Valim
3135487931 More more logic to Authenticatable. 2010-04-16 22:00:06 +02:00
José Valim
9291ab55b8 Fix compatibility with Mongoid and Datamapper, closes #206. 2010-04-15 21:39:56 +02:00
José Valim
1db86a0810 More information about ecosystem in the README. 2010-04-15 21:20:00 +02:00
José Valim
fb832e6ffe Replace devise_for :admin by devise_for :admins. 2010-04-15 11:31:13 -07:00
José Valim
ca6248cfd3 Release devise 1.1.rc1. 2010-04-15 08:45:33 +02:00
José Valim
b9c0676a01 Get rid of deprecation warnings. 2010-04-15 08:43:39 +02:00
José Valim
731f156f50 Do not show unlock link unless strategy is e-mail. Closes #204. 2010-04-15 08:40:15 +02:00
José Valim
b2a50db1df Fix a bug with STI. Closes #195. 2010-04-15 08:34:57 +02:00
José Valim
6bd0c7fc2b :as and :scope in routes is deprecated. Use :path and :singular instead. Closes #199. 2010-04-15 08:21:13 +02:00
José Valim
4e674ab9a0 No need to wait for routes finalization to include UrlHelpers, closes #200. 2010-04-14 08:59:09 +02:00
José Valim
cbfeb59fb3 Regerate gemspec. 2010-04-13 23:44:25 +02:00
José Valim
8db559148c All tests green on latest Rails beta. 2010-04-13 23:28:13 +02:00
José Valim
7403c9f80e Fix a mailer bug in Rails 3. 2010-04-13 23:11:12 +02:00
José Valim
f3d654a733 :activatable is added by default. 2010-04-13 13:35:34 -07:00
José Valim
bafc859f75 Fix small typo in the README. 2010-04-12 10:31:22 -07:00
José Valim
bf63824aae Improve wording in the README. 2010-04-12 04:48:22 -07:00
José Valim
32d37cebed Properly use scope in views generator. 2010-04-12 04:39:16 -07:00
José Valim
d2ebaa43ec Be more helpful in the sign up message for new comers. 2010-04-09 23:13:34 +02:00
José Valim
045af3a614 Change README shown in devise_install. 2010-04-09 09:50:45 -07:00
José Valim
a96fdcf0bd Change authenticatable to database_authenticatable in README. 2010-04-07 22:24:00 -07:00
José Valim
fd934f1434 Revert "Only triggers http in failure app if devise.authentication_method is :http."
It has not fixed the problem it was supposed to fix.
This reverts commit 9d1a52978c.
2010-04-06 22:36:41 +02:00
José Valim
b2fe7e49fd Kill .bundle dir 2010-04-06 17:56:41 +02:00
José Valim
22392f23f2 Authenticatable shuold be loaded at the end. 2010-04-06 17:27:49 +02:00
José Valim
3ce98d4163 Regenerate gemspec. 2010-04-06 16:56:14 +02:00
José Valim
c07b5ae858 :activatable is included by default in your models. If you are building a strategy for devise, you now need to call validate(resource), since Devise has now a default API to validate resources before and after signing them in. You can still use other Warden::Strategies with Devise, but they won't work with a few modules like unlockable (they never did, but now we have a single point to make it work). 2010-04-06 16:34:22 +02:00
José Valim
dbe116c255 Add more info to README. 2010-04-06 13:43:38 +02:00
José Valim
9d1a52978c Only triggers http in failure app if devise.authentication_method is :http. 2010-04-06 13:40:39 +02:00
José Valim
0d3c6b9d99 Small changes to token_authenticatable. 2010-04-06 13:26:56 +02:00
Andre Medeiros
71f74a10f7 Solved deprecation warnings
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-06 12:06:42 +02:00
José Valim
0bd75469ba Update README. 2010-04-05 12:21:02 +02:00
José Valim
1591294b7a Compatibility with Rails beta 3. 2010-04-05 11:46:26 +02:00
José Valim
f9cbd3c457 Add 1.0.6 entries to master changelog 2010-04-03 13:27:17 +02:00
José Valim
66ca9f5ce0 Update README to point to the RC0 gem. 2010-04-03 13:22:14 +02:00
118 changed files with 1556 additions and 1129 deletions

View File

@@ -1,2 +0,0 @@
---
BUNDLE_WITHOUT: ""

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
*~
coverage/*
*.sqlite3
.bundle
rdoc/*
pkg
log

View File

@@ -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
View File

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

View File

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

View File

@@ -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
View File

@@ -1,3 +1,3 @@
* Extract Activatable tests from Confirmable
* Move integration tests to Capybara
* Better ORM integration
* Extract activatable models tests from confirmable

View File

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

View 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

View 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

View File

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

View File

@@ -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 %>

View File

@@ -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 %>

View File

@@ -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 %>

View File

@@ -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 %>

View File

@@ -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 %>

View File

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

View File

@@ -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 -%>

View File

@@ -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 %>

View File

@@ -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'

View File

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

View File

@@ -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.

View File

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

View File

@@ -9,6 +9,7 @@ module Devise
included do
unloadable
helper DeviseHelper
helpers = %w(resource scope_name resource_name
resource_class devise_mapping devise_controller?)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

@@ -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?

View File

@@ -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'

View File

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

View File

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

View File

@@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

@@ -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 || ''

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "1.1.rc0".freeze
VERSION = "1.1.rc2".freeze
end

View 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

View File

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

View File

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

View 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

View File

@@ -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>
===============================================================================

View File

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

View 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

View File

@@ -0,0 +1,2 @@
# Remove this file on next rails release
require "generators/devise/devise/devise_generator"

View File

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

View 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

View File

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

View 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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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]

View File

@@ -1 +1,10 @@
require 'rails/test_help'
DataMapper.auto_migrate!
class ActiveSupport::TestCase
setup do
User.all.destroy!
Admin.all.destroy!
end
end

View File

@@ -1,3 +1,3 @@
class Admin < ActiveRecord::Base
devise :authenticatable, :registerable, :timeoutable, :recoverable
devise :database_authenticatable, :registerable, :timeoutable, :recoverable
end

View File

@@ -0,0 +1,2 @@
module Shim
end

View File

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

View File

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