mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-09 23:58:06 -05:00
Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
879b64edc9 | ||
|
|
5ef88a8fe6 | ||
|
|
9ab64c53f4 | ||
|
|
c5999c8f61 | ||
|
|
680f2612f4 | ||
|
|
81620fecab | ||
|
|
2939a61a49 | ||
|
|
058d433f28 | ||
|
|
5aeb8cf1cf | ||
|
|
abfd7e5a4b | ||
|
|
869c658e3b | ||
|
|
5e64699a5f | ||
|
|
aecc014d33 | ||
|
|
55fd7e3b0a | ||
|
|
b4794e041b | ||
|
|
4f6113ab68 | ||
|
|
05d23f1a00 | ||
|
|
e567c00dd8 | ||
|
|
ebe3e791d6 | ||
|
|
2602ef41cf | ||
|
|
a87bc4a861 | ||
|
|
eca511a8f2 | ||
|
|
9c5ff02ff1 | ||
|
|
9f29ca480b | ||
|
|
b9df42c350 | ||
|
|
bd0e2a3180 | ||
|
|
750560ae87 | ||
|
|
e2a4ebce4a | ||
|
|
77b7692b57 | ||
|
|
ae6322efb5 | ||
|
|
238226e33a | ||
|
|
96a9c88420 | ||
|
|
dd612753f9 | ||
|
|
35923c9c69 | ||
|
|
f54013a181 | ||
|
|
1cf77028c1 | ||
|
|
7774accb6c | ||
|
|
6c49b428b3 | ||
|
|
7113dfe93a | ||
|
|
4083d679d4 | ||
|
|
7a1adbb61e | ||
|
|
18cccae82f | ||
|
|
e9fbb3d7ef | ||
|
|
04c25539c2 | ||
|
|
55bc0ace5a | ||
|
|
421256d294 | ||
|
|
8e3ef2a620 | ||
|
|
aefcd53765 | ||
|
|
0eb9208503 | ||
|
|
8824b767f3 | ||
|
|
2103a673f0 | ||
|
|
78e7642bd2 | ||
|
|
8526056bde | ||
|
|
4b272767d6 | ||
|
|
84c34ff0c4 | ||
|
|
4db3ac820b | ||
|
|
503d27f2e1 | ||
|
|
2475faf9c7 | ||
|
|
819db39263 | ||
|
|
f864259f1e | ||
|
|
12ae21117c | ||
|
|
1a224c7486 | ||
|
|
f10b747f7f | ||
|
|
8370006591 | ||
|
|
1924a915a8 | ||
|
|
7a45043bc8 | ||
|
|
ad63e25c89 | ||
|
|
895a7a4951 | ||
|
|
b8c2bbe73c | ||
|
|
b76bf10203 | ||
|
|
748eced9e8 | ||
|
|
a39312e26b | ||
|
|
b2c2cb272f | ||
|
|
fccde42f20 | ||
|
|
e90732c8c3 | ||
|
|
21874d8559 | ||
|
|
cfadaf80a2 | ||
|
|
df444663ac | ||
|
|
5b63605c94 | ||
|
|
3660cbac30 | ||
|
|
92cf50454b | ||
|
|
29ba790e07 | ||
|
|
4e2cd157c1 | ||
|
|
194959f312 | ||
|
|
e3b815de49 | ||
|
|
ac0105d15f | ||
|
|
7dbd2eac2a | ||
|
|
025c3875b6 | ||
|
|
f1a990c2ae | ||
|
|
1f4a31f1cf | ||
|
|
31910b85a2 | ||
|
|
5e1ef9319e | ||
|
|
70a429d9ff | ||
|
|
f16d01869a | ||
|
|
290cfd1f72 | ||
|
|
ed22295963 | ||
|
|
a2f84852af | ||
|
|
c4a4032b6b | ||
|
|
80895c3b9a | ||
|
|
84686d285c | ||
|
|
6c18c92598 | ||
|
|
0333caeb92 | ||
|
|
bece09c653 | ||
|
|
cd78a26f88 | ||
|
|
5c9fe5e769 | ||
|
|
fb0aec09f1 | ||
|
|
5f2a19d784 | ||
|
|
cc608f82dd | ||
|
|
7e784b258c | ||
|
|
870912d458 | ||
|
|
f0c0f5f11b | ||
|
|
7dc1842cc4 | ||
|
|
28b10e397f | ||
|
|
6ff77c9fdf | ||
|
|
d98882d745 | ||
|
|
80977c6dee | ||
|
|
7c82d3ee67 | ||
|
|
0150fddb4c | ||
|
|
c8ec42a41c | ||
|
|
bff64a6291 | ||
|
|
a65fd873dd | ||
|
|
592fa59e88 | ||
|
|
02c2df65cd | ||
|
|
59bee679ca | ||
|
|
21129ae38c | ||
|
|
f1bbce58f3 | ||
|
|
8e173f486c | ||
|
|
e905762611 | ||
|
|
d38421dde8 | ||
|
|
6162e1f5ff | ||
|
|
08c5179869 | ||
|
|
bb39243da2 | ||
|
|
9bdc711324 | ||
|
|
a4351b0b77 | ||
|
|
416bff3daa | ||
|
|
07204c500d | ||
|
|
f5bc66521f | ||
|
|
fb0f8fcd0d | ||
|
|
61fbec858e | ||
|
|
25302de1f8 | ||
|
|
b86c1c241b | ||
|
|
2bf9e462fa | ||
|
|
57712737b2 | ||
|
|
c582e9cb0f | ||
|
|
d750b48879 | ||
|
|
708fe78d86 | ||
|
|
41311eb38d | ||
|
|
da971e4249 | ||
|
|
eb23ca0ca7 | ||
|
|
c9fe7900c3 | ||
|
|
9d6a78f7f4 | ||
|
|
4da63c5395 | ||
|
|
b5f892bcdb | ||
|
|
3135487931 | ||
|
|
9291ab55b8 | ||
|
|
1db86a0810 | ||
|
|
fb832e6ffe |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
*~
|
||||
coverage/*
|
||||
*.sqlite3
|
||||
.bundle
|
||||
rdoc/*
|
||||
pkg
|
||||
log
|
||||
|
||||
109
CHANGELOG.rdoc
109
CHANGELOG.rdoc
@@ -1,34 +1,95 @@
|
||||
== 1.1.1
|
||||
|
||||
* bugfix
|
||||
* Fix a small bug where generated locale file was empty on devise:install
|
||||
|
||||
== 1.1.0
|
||||
|
||||
* enhancements
|
||||
* Rememberable module allows user to be remembered across browsers and is enabled by default (by github.com/trevorturk)
|
||||
* Rememberable module allows you to activate the period the remember me token is extended (by github.com/trevorturk)
|
||||
* devise_for can now be used together with scope method in routes but with a few limitations (check the documentation)
|
||||
* Support `as` or `devise_scope` in the router to specify controller access scope
|
||||
* HTTP Basic Auth can now be disabled/enabled for xhr(ajax) requests using http_authenticatable_on_xhr option (by github.com/pellja)
|
||||
|
||||
* bug fix
|
||||
* Fix a bug in Devise::TestHelpers where current_user was returning a Response object for non active accounts
|
||||
* Devise should respect script_name and path_info contracts
|
||||
* Fix a bug when accessing a path with (.:format) (by github.com/klacointe)
|
||||
* Do not add unlock routes unless unlock strategy is email or both
|
||||
* Email should be case insensitive
|
||||
* Store classes as string in session, to avoid serialization and stale data issues
|
||||
|
||||
* deprecations
|
||||
* use_default_scope is deprecated and has no effect. Use :as or :devise_scope in the router instead
|
||||
|
||||
== 1.1.rc2
|
||||
|
||||
* enhancements
|
||||
* 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.rc1
|
||||
|
||||
* 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.
|
||||
* :activatable is included by default in your models.
|
||||
* 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 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
|
||||
* Fix a bug with STI
|
||||
|
||||
* 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.
|
||||
* :as and :scope in routes is deprecated. Use :path and :singular instead.
|
||||
* 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
|
||||
|
||||
|
||||
28
Gemfile
28
Gemfile
@@ -1,10 +1,14 @@
|
||||
source "http://gemcutter.org"
|
||||
source "http://rubygems.org"
|
||||
|
||||
# Need to install Rails from source
|
||||
gem "rails", "3.0.0.beta3"
|
||||
gem "warden", "0.10.3"
|
||||
gem "sqlite3-ruby", :require => "sqlite3"
|
||||
gem "webrat", "0.7"
|
||||
if File.exist? File.expand_path('../../rails', __FILE__)
|
||||
gem "rails", :path => "../rails"
|
||||
else
|
||||
gem "rails", :git => "git://github.com/rails/rails.git"
|
||||
end
|
||||
|
||||
gem "warden", "0.10.7"
|
||||
gem "sqlite3-ruby"
|
||||
gem "webrat", "0.7.0"
|
||||
gem "mocha", :require => false
|
||||
gem "bcrypt-ruby", :require => "bcrypt"
|
||||
|
||||
@@ -13,15 +17,7 @@ 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"
|
||||
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"
|
||||
gem "bson_ext"
|
||||
end
|
||||
118
Gemfile.lock
Normal file
118
Gemfile.lock
Normal file
@@ -0,0 +1,118 @@
|
||||
GIT
|
||||
remote: git://github.com/durran/mongoid.git
|
||||
revision: a5abe21
|
||||
specs:
|
||||
mongoid (2.0.0.beta9)
|
||||
activemodel (~> 3.0.0.beta)
|
||||
bson (~> 1.0.3)
|
||||
mongo (~> 1.0.3)
|
||||
tzinfo (~> 0.3.22)
|
||||
will_paginate (~> 3.0.pre)
|
||||
|
||||
PATH
|
||||
remote: /Users/jose/Work/github/rails
|
||||
specs:
|
||||
actionmailer (3.0.0.beta4)
|
||||
actionpack (= 3.0.0.beta4)
|
||||
mail (~> 2.2.5)
|
||||
actionpack (3.0.0.beta4)
|
||||
activemodel (= 3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
builder (~> 2.1.2)
|
||||
erubis (~> 2.6.6)
|
||||
i18n (~> 0.4.1)
|
||||
rack (~> 1.2.1)
|
||||
rack-mount (~> 0.6.9)
|
||||
rack-test (~> 0.5.4)
|
||||
tzinfo (~> 0.3.22)
|
||||
activemodel (3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
builder (~> 2.1.2)
|
||||
i18n (~> 0.4.1)
|
||||
activerecord (3.0.0.beta4)
|
||||
activemodel (= 3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
arel (~> 0.4.0)
|
||||
tzinfo (~> 0.3.22)
|
||||
activeresource (3.0.0.beta4)
|
||||
activemodel (= 3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
activesupport (3.0.0.beta4)
|
||||
rails (3.0.0.beta4)
|
||||
actionmailer (= 3.0.0.beta4)
|
||||
actionpack (= 3.0.0.beta4)
|
||||
activerecord (= 3.0.0.beta4)
|
||||
activeresource (= 3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
bundler (>= 1.0.0.beta.10)
|
||||
railties (= 3.0.0.beta4)
|
||||
railties (3.0.0.beta4)
|
||||
actionpack (= 3.0.0.beta4)
|
||||
activesupport (= 3.0.0.beta4)
|
||||
rake (>= 0.8.3)
|
||||
thor (~> 0.14.0)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
abstract (1.0.0)
|
||||
arel (0.4.0)
|
||||
activesupport (>= 3.0.0.beta)
|
||||
bcrypt-ruby (2.1.2)
|
||||
bson (1.0.4)
|
||||
bson_ext (1.0.4)
|
||||
builder (2.1.2)
|
||||
columnize (0.3.1)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
i18n (0.4.1)
|
||||
linecache (0.43)
|
||||
mail (2.2.5)
|
||||
activesupport (>= 2.3.6)
|
||||
mime-types
|
||||
treetop (>= 1.4.5)
|
||||
mime-types (1.16)
|
||||
mocha (0.9.8)
|
||||
rake
|
||||
mongo (1.0.5)
|
||||
bson (>= 1.0.4)
|
||||
nokogiri (1.4.2)
|
||||
polyglot (0.3.1)
|
||||
rack (1.2.1)
|
||||
rack-mount (0.6.9)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (0.5.4)
|
||||
rack (>= 1.0)
|
||||
rake (0.8.7)
|
||||
ruby-debug (0.10.3)
|
||||
columnize (>= 0.1)
|
||||
ruby-debug-base (~> 0.10.3.0)
|
||||
ruby-debug-base (0.10.3)
|
||||
linecache (>= 0.3)
|
||||
sqlite3-ruby (1.3.1)
|
||||
thor (0.14.0)
|
||||
treetop (1.4.8)
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.22)
|
||||
warden (0.10.7)
|
||||
rack (>= 1.0.0)
|
||||
webrat (0.7.0)
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
will_paginate (3.0.pre)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
bcrypt-ruby
|
||||
bson_ext
|
||||
mocha
|
||||
mongo
|
||||
mongoid!
|
||||
rails!
|
||||
ruby-debug (>= 0.10.3)
|
||||
sqlite3-ruby
|
||||
warden (= 0.10.7)
|
||||
webrat (= 0.7.0)
|
||||
122
README.rdoc
122
README.rdoc
@@ -13,53 +13,66 @@ 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.
|
||||
|
||||
== 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. You can use the latest Rails 3 beta gem with Devise latest gem:
|
||||
Devise 1.1 supports Rails 3 and is NOT backward compatible. You can use the latest Rails 3 beta gem with Devise latest gem:
|
||||
|
||||
sudo gem install devise --version=1.1.rc1
|
||||
gem install devise --version=1.1.rc2
|
||||
|
||||
If you want to use Rails master (from git repository) you need to use Devise from git repository and vice-versa.
|
||||
|
||||
After you install Devise and add it to your Gemfile, you need to run the generator:
|
||||
|
||||
rails generate devise_install
|
||||
rails generate devise:install
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
http://rdoc.info/projects/plataformatec/devise
|
||||
rails generate devise MODEL
|
||||
|
||||
The documentation above is for Rails 3. If you want to consult the documentation for Rails 2.3, you need to start `gem server` in your own machine. Finally, another good resource for information, is the wiki:
|
||||
|
||||
http://wiki.github.com/plataformatec/devise
|
||||
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.6
|
||||
gem install devise --version=1.0.8
|
||||
|
||||
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.
|
||||
|
||||
@@ -88,13 +101,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
|
||||
|
||||
@@ -133,13 +146,14 @@ Devise allows you to set up as many roles as you want. For example, you may have
|
||||
t.database_authenticatable
|
||||
t.lockable
|
||||
t.trackable
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
# Inside your Admin model
|
||||
devise :database_authenticatable, :trackable, :timeoutable, :lockable
|
||||
|
||||
# Inside your routes
|
||||
devise_for :admin
|
||||
devise_for :admins
|
||||
|
||||
# Inside your protected controller
|
||||
before_filter :authenticate_admin!
|
||||
@@ -149,27 +163,13 @@ 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 database_authenticatable:
|
||||
|
||||
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 views
|
||||
|
||||
@@ -177,7 +177,7 @@ We built Devise to help you quickly develop an application that uses authenticat
|
||||
|
||||
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
|
||||
|
||||
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".
|
||||
|
||||
@@ -257,10 +257,34 @@ 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.
|
||||
|
||||
== Security
|
||||
|
||||
Needless to say, security is extremely important to Devise. If you find yourself in a possible security issue with Devise, please go through the following steps, trying to reproduce the bug:
|
||||
|
||||
1) Look at the source code a bit to find out whether your assumptions are correct;
|
||||
2) If possible, provide a way to reproduce the bug: a small app on Github or a step-by-step to reproduce;
|
||||
3) E-mail us or send a Github private message instead of using the normal issues;
|
||||
|
||||
Being able to reproduce the bug is the first step to fix it. Thanks for your understanding.
|
||||
|
||||
== Maintainers
|
||||
|
||||
* José Valim (http://github.com/josevalim)
|
||||
@@ -268,15 +292,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
|
||||
|
||||
@@ -288,10 +306,6 @@ For support, send an e-mail to the mailing list.
|
||||
|
||||
http://groups.google.com/group/plataformatec-devise
|
||||
|
||||
See the wiki for additional documentation and support.
|
||||
|
||||
http://wiki.github.com/plataformatec/devise
|
||||
|
||||
== License
|
||||
|
||||
MIT License. Copyright 2009 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
MIT License. Copyright 2010 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
|
||||
5
Rakefile
5
Rakefile
@@ -45,10 +45,11 @@ begin
|
||||
s.authors = ['José Valim', 'Carlos Antônio']
|
||||
s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"]
|
||||
s.extra_rdoc_files = FileList["[A-Z]*"] - %w(Gemfile Rakefile)
|
||||
s.add_dependency("warden", "~> 0.10.3")
|
||||
s.add_dependency("warden", "~> 0.10.7")
|
||||
s.add_dependency("bcrypt-ruby", "~> 2.1.2")
|
||||
end
|
||||
|
||||
Jeweler::GemcutterTasks.new
|
||||
rescue LoadError
|
||||
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
||||
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
||||
end
|
||||
|
||||
1
TODO
1
TODO
@@ -1,2 +1,3 @@
|
||||
* Move integration tests to Capybara
|
||||
* Better ORM integration
|
||||
* Extract activatable models tests from confirmable
|
||||
|
||||
@@ -31,7 +31,7 @@ class Devise::RegistrationsController < ApplicationController
|
||||
def update
|
||||
if resource.update_with_password(params[resource_name])
|
||||
set_flash_message :notice, :updated
|
||||
redirect_to after_sign_in_path_for(self.resource)
|
||||
redirect_to after_update_path_for(resource)
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
render_with_scope :edit
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Devise::UnlocksController < ApplicationController
|
||||
prepend_before_filter :ensure_email_as_unlock_strategy
|
||||
prepend_before_filter :require_no_authentication
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
@@ -32,10 +31,4 @@ class Devise::UnlocksController < ApplicationController
|
||||
render_with_scope :new
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def ensure_email_as_unlock_strategy
|
||||
raise ActionController::UnknownAction unless resource_class.unlock_strategy_enabled?(:email)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
|
||||
attr_reader :devise_mapping, :resource
|
||||
|
||||
def confirmation_instructions(record)
|
||||
@@ -17,52 +16,56 @@ class Devise::Mailer < ::ActionMailer::Base
|
||||
|
||||
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)
|
||||
# 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_paths
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
|
||||
mail(headers)
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
# Fix a bug in Rails 3 beta 3
|
||||
def mail(*) #:nodoc:
|
||||
super
|
||||
@_message["template_path"] = nil
|
||||
@_message
|
||||
end
|
||||
def template_paths
|
||||
template_path = [self.class.mailer_name]
|
||||
template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
|
||||
template_path
|
||||
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
|
||||
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
|
||||
# based on the current mapping:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# user_subject: '...'
|
||||
#
|
||||
# If one does not exist, it fallbacks to ActionMailer default:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# subject: '...'
|
||||
#
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
|
||||
:default => [:subject, key.to_s.humanize])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name)) do |f| %>
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) 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 %>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<%= devise_error_messages! %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.submit "Change my password" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name)) do |f| %>
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) 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 %>
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
<%= 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 %>
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_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.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 "Sign up" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<h2>Sign in</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<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 %></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>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name)) do |f| %>
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.submit "Resend unlock instructions" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -24,13 +24,16 @@ en:
|
||||
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
|
||||
confirmed: 'Your account was successfully confirmed. You are now signed in.'
|
||||
registrations:
|
||||
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent your e-mail.'
|
||||
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
|
||||
updated: 'You updated your account successfully.'
|
||||
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
|
||||
unlocks:
|
||||
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
|
||||
unlocked: 'Your account was successfully unlocked. You are now signed in.'
|
||||
mailer:
|
||||
confirmation_instructions: 'Confirmation instructions'
|
||||
reset_password_instructions: 'Reset password instructions'
|
||||
unlock_instructions: 'Unlock Instructions'
|
||||
confirmation_instructions:
|
||||
subject: 'Confirmation instructions'
|
||||
reset_password_instructions:
|
||||
subject: 'Reset password instructions'
|
||||
unlock_instructions:
|
||||
subject: 'Unlock Instructions'
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{devise}
|
||||
s.version = "1.1.rc1"
|
||||
s.version = "1.1.1"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Jos\303\251 Valim", "Carlos Ant\303\264nio"]
|
||||
s.date = %q{2010-04-15}
|
||||
s.date = %q{2010-07-27}
|
||||
s.description = %q{Flexible authentication solution for Rails with Warden}
|
||||
s.email = %q{contact@plataformatec.com.br}
|
||||
s.extra_rdoc_files = [
|
||||
"CHANGELOG.rdoc",
|
||||
"Gemfile.lock",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"TODO"
|
||||
@@ -21,6 +22,7 @@ Gem::Specification.new do |s|
|
||||
s.files = [
|
||||
"CHANGELOG.rdoc",
|
||||
"Gemfile",
|
||||
"Gemfile.lock",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"Rakefile",
|
||||
@@ -77,8 +79,8 @@ Gem::Specification.new do |s|
|
||||
"lib/devise/models/validatable.rb",
|
||||
"lib/devise/modules.rb",
|
||||
"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",
|
||||
@@ -90,17 +92,22 @@ Gem::Specification.new do |s|
|
||||
"lib/devise/strategies/token_authenticatable.rb",
|
||||
"lib/devise/test_helpers.rb",
|
||||
"lib/devise/version.rb",
|
||||
"lib/generators/active_record/devise_generator.rb",
|
||||
"lib/generators/active_record/templates/migration.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/install_generator.rb",
|
||||
"lib/generators/devise/orm_helpers.rb",
|
||||
"lib/generators/devise/views_generator.rb",
|
||||
"lib/generators/devise_install_generator.rb",
|
||||
"lib/generators/devise_views_generator.rb",
|
||||
"lib/generators/mongoid/devise_generator.rb",
|
||||
"lib/generators/templates/README",
|
||||
"lib/generators/templates/devise.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",
|
||||
@@ -109,6 +116,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",
|
||||
@@ -134,19 +142,20 @@ Gem::Specification.new do |s|
|
||||
"test/models/validatable_test.rb",
|
||||
"test/models_test.rb",
|
||||
"test/orm/active_record.rb",
|
||||
"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",
|
||||
"test/rails_app/app/controllers/home_controller.rb",
|
||||
"test/rails_app/app/controllers/publisher/registrations_controller.rb",
|
||||
"test/rails_app/app/controllers/publisher/sessions_controller.rb",
|
||||
"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/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",
|
||||
@@ -175,13 +184,16 @@ Gem::Specification.new do |s|
|
||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||
s.specification_version = 3
|
||||
|
||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_runtime_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.3"])
|
||||
s.add_dependency(%q<warden>, ["~> 0.10.7"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require 'active_support/core_ext/numeric/time'
|
||||
require 'active_support/dependencies'
|
||||
|
||||
module Devise
|
||||
autoload :FailureApp, 'devise/failure_app'
|
||||
autoload :PathChecker, 'devise/path_checker'
|
||||
autoload :Schema, 'devise/schema'
|
||||
autoload :TestHelpers, 'devise/test_helpers'
|
||||
|
||||
@@ -47,6 +49,10 @@ module Devise
|
||||
:bcrypt => 60
|
||||
}
|
||||
|
||||
# Custom domain for cookies. Not set by default
|
||||
mattr_accessor :cookie_domain
|
||||
@@cookie_domain = false
|
||||
|
||||
# Used to encrypt password. Please generate one with rake secret.
|
||||
mattr_accessor :pepper
|
||||
@@pepper = nil
|
||||
@@ -63,6 +69,10 @@ module Devise
|
||||
mattr_accessor :http_authenticatable
|
||||
@@http_authenticatable = true
|
||||
|
||||
# If http authentication is used for ajax requests. True by default.
|
||||
mattr_accessor :http_authenticatable_on_xhr
|
||||
@@http_authenticatable_on_xhr = true
|
||||
|
||||
# If params authenticatable is enabled by default.
|
||||
mattr_accessor :params_authenticatable
|
||||
@@params_authenticatable = true
|
||||
@@ -79,10 +89,18 @@ module Devise
|
||||
mattr_accessor :password_length
|
||||
@@password_length = 6..20
|
||||
|
||||
# Time interval where the remember me token is valid.
|
||||
# The time the user will be remembered without asking for credentials again.
|
||||
mattr_accessor :remember_for
|
||||
@@remember_for = 2.weeks
|
||||
|
||||
# If true, a valid remember token can be re-used between multiple browsers.
|
||||
mattr_accessor :remember_across_browsers
|
||||
@@remember_across_browsers = true
|
||||
|
||||
# If true, extends the user's remember period when remembered via cookie.
|
||||
mattr_accessor :extend_remember_period
|
||||
@@extend_remember_period = false
|
||||
|
||||
# Time interval you can access your account before confirming your account.
|
||||
mattr_accessor :confirm_within
|
||||
@@confirm_within = 0.days
|
||||
@@ -93,7 +111,7 @@ module Devise
|
||||
|
||||
# Used to define the password encryption algorithm.
|
||||
mattr_accessor :encryptor
|
||||
@@encryptor = :sha1
|
||||
@@encryptor = nil
|
||||
|
||||
# Store scopes mappings.
|
||||
mattr_accessor :mappings
|
||||
@@ -127,10 +145,6 @@ module Devise
|
||||
mattr_accessor :unlock_in
|
||||
@@unlock_in = 1.hour
|
||||
|
||||
# Tell when to use the default scope, if one cannot be found from routes.
|
||||
mattr_accessor :use_default_scope
|
||||
@@use_default_scope = false
|
||||
|
||||
# The default scope which is used by warden.
|
||||
mattr_accessor :default_scope
|
||||
@@default_scope = nil
|
||||
@@ -143,27 +157,48 @@ module Devise
|
||||
mattr_accessor :token_authentication_key
|
||||
@@token_authentication_key = :auth_token
|
||||
|
||||
# Which formats should be treated as navigational.
|
||||
mattr_accessor :navigational_formats
|
||||
@@navigational_formats = [:html]
|
||||
|
||||
# Private methods to interface with Warden.
|
||||
mattr_accessor :warden_config
|
||||
@@warden_config = nil
|
||||
@@warden_config_block = nil
|
||||
|
||||
# When set to true, signing out an user signs out all other scopes.
|
||||
mattr_accessor :sign_out_all_scopes
|
||||
@@sign_out_all_scopes = false
|
||||
|
||||
def self.use_default_scope=(*)
|
||||
ActiveSupport::Deprecation.warn "config.use_default_scope is deprecated and removed from Devise. " <<
|
||||
"If you are using non conventional routes in Devise, all you need to do is to pass the devise " <<
|
||||
"scope in the router DSL:\n\n as :user do\n get \"sign_in\", :to => \"devise/sessions\"\n end\n\n" <<
|
||||
"The method :as is also aliased to :devise_scope. Choose the one you prefer.", caller
|
||||
end
|
||||
|
||||
# Default way to setup Devise. Run rails generate devise_install to create
|
||||
# a fresh initializer with all configuration values.
|
||||
def self.setup
|
||||
yield self
|
||||
end
|
||||
|
||||
# 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)
|
||||
# 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"
|
||||
|
||||
# Small method that adds a mapping to Devise.
|
||||
def self.add_mapping(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 +268,17 @@ module Devise
|
||||
# A method used internally to setup warden manager from the Rails initialize
|
||||
# block.
|
||||
def self.configure_warden! #:nodoc:
|
||||
@@warden_config_block.try :call, Devise.warden_config
|
||||
@@warden_configured ||= begin
|
||||
warden_config.failure_app = Devise::FailureApp
|
||||
warden_config.default_scope = Devise.default_scope
|
||||
|
||||
Devise.mappings.each_value do |mapping|
|
||||
warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
|
||||
end
|
||||
|
||||
@@warden_config_block.try :call, Devise.warden_config
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Generate a friendly string randomically to be used as token.
|
||||
|
||||
@@ -5,8 +5,8 @@ module Devise
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
helper_method :warden, :signed_in?, :devise_controller?,
|
||||
*Devise.mappings.keys.map { |m| [:"current_#{m}", :"#{m}_signed_in?"] }.flatten
|
||||
helper_method :warden, :signed_in?, :devise_controller?, :anybody_signed_in?,
|
||||
*Devise.mappings.keys.map { |m| [:"current_#{m}", :"#{m}_signed_in?", :"#{m}_session"] }.flatten
|
||||
end
|
||||
|
||||
# The main accessor for the warden proxy instance
|
||||
@@ -29,6 +29,12 @@ module Devise
|
||||
warden.authenticate?(:scope => scope)
|
||||
end
|
||||
|
||||
# Check if the any scope is signed in session, without running
|
||||
# authentication hooks.
|
||||
def anybody_signed_in?
|
||||
Devise.mappings.keys.any? { |scope| signed_in?(scope) }
|
||||
end
|
||||
|
||||
# Sign in an user that already was authenticated. This helper is useful for logging
|
||||
# users in after sign up.
|
||||
#
|
||||
@@ -58,6 +64,16 @@ module Devise
|
||||
warden.logout(scope)
|
||||
end
|
||||
|
||||
# Sign out all active users or scopes. This helper is useful for signing out all roles
|
||||
# in one click.
|
||||
def sign_out_all_scopes
|
||||
# Not "warden.logout" since we need to sign_out only devise-defined scopes.
|
||||
scopes = Devise.mappings.keys
|
||||
scopes.each { |scope| warden.user(scope) }
|
||||
warden.raw_session.inspect
|
||||
warden.logout(*scopes)
|
||||
end
|
||||
|
||||
# Returns and delete the url stored in the session for the given scope. Useful
|
||||
# for giving redirect backs after sign up:
|
||||
#
|
||||
@@ -80,13 +96,13 @@ module Devise
|
||||
#
|
||||
# map.user_root '/users', :controller => 'users' # creates user_root_path
|
||||
#
|
||||
# map.resources :users do |users|
|
||||
# users.root # creates user_root_path
|
||||
# map.namespace :user do |user|
|
||||
# user.root :controller => 'users' # 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:
|
||||
# If the resource root path is not defined, root_path is used. However,
|
||||
# if this default is not enough, you can customize it, for example:
|
||||
#
|
||||
# def after_sign_in_path_for(resource)
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
@@ -102,6 +118,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
|
||||
@@ -128,7 +174,11 @@ module Devise
|
||||
# after_sign_out_path_for.
|
||||
def sign_out_and_redirect(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
sign_out(scope)
|
||||
if Devise.sign_out_all_scopes
|
||||
sign_out_all_scopes
|
||||
else
|
||||
sign_out(scope)
|
||||
end
|
||||
redirect_to after_sign_out_path_for(scope)
|
||||
end
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ module Devise
|
||||
include Devise::Controllers::ScopedViews
|
||||
|
||||
included do
|
||||
unloadable
|
||||
helper DeviseHelper
|
||||
|
||||
helpers = %w(resource scope_name resource_name
|
||||
@@ -38,11 +37,7 @@ module Devise
|
||||
|
||||
# Attempt to find the mapped route for devise based on request path
|
||||
def devise_mapping
|
||||
@devise_mapping ||= begin
|
||||
mapping = Devise::Mapping.find_by_path(request.path)
|
||||
mapping ||= Devise.mappings[Devise.default_scope] if Devise.use_default_scope
|
||||
mapping
|
||||
end
|
||||
@devise_mapping ||= request.env["devise.mapping"]
|
||||
end
|
||||
|
||||
# Overwrites devise_controller? to return true
|
||||
@@ -54,8 +49,7 @@ module Devise
|
||||
|
||||
# Checks whether it's a devise mapped resource or not.
|
||||
def is_devise_resource? #:nodoc:
|
||||
raise ActionController::UnknownAction unless devise_mapping &&
|
||||
devise_mapping.allowed_controllers.include?(controller_path)
|
||||
raise ActionController::UnknownAction unless devise_mapping
|
||||
end
|
||||
|
||||
# Sets the resource creating an instance variable
|
||||
|
||||
@@ -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
|
||||
@@ -12,7 +12,7 @@ module Devise
|
||||
raise NotImplemented
|
||||
end
|
||||
|
||||
def self.salt
|
||||
def self.salt(stretches)
|
||||
Devise.friendly_token
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,17 +5,15 @@ 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)
|
||||
::BCrypt::Engine.hash_secret([password, pepper].join, salt, stretches)
|
||||
end
|
||||
|
||||
def self.salt
|
||||
::BCrypt::Engine.generate_salt
|
||||
def self.salt(stretches)
|
||||
::BCrypt::Engine.generate_salt(stretches)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,13 +7,11 @@ module Devise
|
||||
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
||||
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
|
||||
class ClearanceSha1 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Devise
|
||||
# = Sha1
|
||||
# Uses the Sha1 hash algorithm to encrypt passwords.
|
||||
class Sha1 < Base
|
||||
|
||||
# Gererates a default password digest based on stretches, salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -14,14 +13,13 @@ module Devise
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Devise
|
||||
# = Sha512
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
@@ -14,14 +13,13 @@ module Devise
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,7 @@ module Devise
|
||||
include ActionController::RackDelegation
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirecting
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
delegate :flash, :to => :request
|
||||
|
||||
@@ -46,7 +47,7 @@ module Devise
|
||||
def redirect
|
||||
store_location!
|
||||
flash[:alert] = i18n_message unless flash[:notice]
|
||||
redirect_to send(:"new_#{scope}_session_path")
|
||||
redirect_to redirect_url
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -62,8 +63,12 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_url
|
||||
send(:"new_#{scope}_session_path")
|
||||
end
|
||||
|
||||
def http_auth?
|
||||
request.authorization
|
||||
!Devise.navigational_formats.include?(request.format.to_sym) || (request.xhr? && Devise.http_authenticatable_on_xhr)
|
||||
end
|
||||
|
||||
def http_auth_body
|
||||
@@ -96,7 +101,7 @@ module Devise
|
||||
# yet, but we still need to store the uri based on scope, so different scopes
|
||||
# would never use the same uri to redirect.
|
||||
def store_location!
|
||||
session[:"#{scope}_return_to"] = attempted_path if request && request.get?
|
||||
session[:"#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# 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]
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
# 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|
|
||||
Warden::Manager.before_logout do |record, warden, options|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
warden.cookies.delete "remember_#{scope}_token"
|
||||
options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
|
||||
warden.cookies.delete("remember_#{options[:scope]}_token", options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,18 +9,29 @@ module Devise
|
||||
super
|
||||
|
||||
if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
|
||||
resource.remember_me!
|
||||
resource.remember_me!(extend_remember_period?)
|
||||
|
||||
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
|
||||
|
||||
def succeeded?
|
||||
@result == :success
|
||||
end
|
||||
|
||||
def extend_remember_period?
|
||||
false
|
||||
end
|
||||
|
||||
def remember_me?
|
||||
valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
|
||||
end
|
||||
@@ -28,4 +39,5 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
||||
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@
|
||||
# verify timeout in the following request.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
|
||||
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope)
|
||||
last_request_at = warden.session(scope)['last_request_at']
|
||||
|
||||
if record.timedout?(last_request_at)
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
path_checker = Devise::PathChecker.new(warden.env, scope)
|
||||
unless path_checker.signing_out?
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
end
|
||||
end
|
||||
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
|
||||
@@ -22,19 +22,9 @@ module Devise
|
||||
# # is the modules included in the class
|
||||
#
|
||||
class Mapping #:nodoc:
|
||||
attr_reader :singular, :plural, :path, :controllers, :path_names, :path_prefix
|
||||
attr_reader :singular, :plural, :path, :controllers, :path_names, :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.segment_position]
|
||||
return mapping if route && mapping.path == route.to_sym
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Receives an object and find a scope for it. If a scope cannot be found,
|
||||
# raises an error. If a symbol is given, it's considered to be the scope.
|
||||
def self.find_scope!(duck)
|
||||
@@ -51,42 +41,32 @@ module Devise
|
||||
end
|
||||
|
||||
def initialize(name, options) #:nodoc:
|
||||
if as = options.delete(:as)
|
||||
ActiveSupport::Deprecation.warn ":as is deprecated, please use :path instead."
|
||||
options[:path] ||= as
|
||||
end
|
||||
@plural = (options[:as] ? "#{options[:as]}_#{name}" : name).to_sym
|
||||
@singular = (options[:singular] || @plural.to_s.singularize).to_sym
|
||||
|
||||
if scope = options.delete(:scope)
|
||||
ActiveSupport::Deprecation.warn ":scope is deprecated, please use :singular instead."
|
||||
options[:singular] ||= scope
|
||||
end
|
||||
@class_name = (options[:class_name] || name.to_s.classify).to_s
|
||||
@ref = ActiveSupport::Dependencies.ref(@class_name)
|
||||
|
||||
@plural = name.to_sym
|
||||
@path = (options.delete(:path) || name).to_sym
|
||||
@klass = (options.delete(:class_name) || name.to_s.classify).to_s
|
||||
@singular = (options.delete(:singular) || name.to_s.singularize).to_sym
|
||||
@path = (options[:path] || name).to_s
|
||||
@path_prefix = options[:path_prefix]
|
||||
|
||||
@path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
|
||||
mod = options[:module] || "devise"
|
||||
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
||||
@controllers.merge!(options[:controllers] || {})
|
||||
|
||||
@controllers = Hash.new { |h,k| h[k] = "devise/#{k}" }
|
||||
@controllers.merge!(options.delete(:controllers) || {})
|
||||
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names.merge!(options.delete(:path_names) || {})
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names.merge!(:registration => "")
|
||||
@path_names.merge!(options[: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
|
||||
@@ -97,30 +77,14 @@ module Devise
|
||||
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
|
||||
end
|
||||
|
||||
# Keep a list of allowed controllers for this mapping. It's useful to ensure
|
||||
# that an Admin cannot access the registrations controller unless it has
|
||||
# :registerable in the model.
|
||||
def allowed_controllers
|
||||
@allowed_controllers ||= begin
|
||||
canonical = CONTROLLERS.values_at(*self.modules).compact
|
||||
@controllers.values_at(*canonical)
|
||||
end
|
||||
end
|
||||
|
||||
# Return in which position in the path prefix devise should find the as mapping.
|
||||
def segment_position
|
||||
self.path_prefix.count("/")
|
||||
end
|
||||
|
||||
# Returns the raw path using path_prefix and as.
|
||||
def full_path
|
||||
path_prefix + path.to_s
|
||||
end
|
||||
|
||||
def authenticatable?
|
||||
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
|
||||
end
|
||||
|
||||
def fullpath
|
||||
"#{@path_prefix}/#{@path}".squeeze("/")
|
||||
end
|
||||
|
||||
# Create magic predicates for verifying what module is activated by this map.
|
||||
# Example:
|
||||
#
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
module Devise
|
||||
module Models
|
||||
class << self
|
||||
def hook(base)
|
||||
base.class_eval do
|
||||
class_attribute :devise_modules, :instance_writer => false
|
||||
self.devise_modules ||= []
|
||||
end
|
||||
end
|
||||
|
||||
alias :included :hook
|
||||
alias :extended :hook
|
||||
end
|
||||
|
||||
# Creates configuration values for Devise and for the given module.
|
||||
#
|
||||
# Devise::Models.config(Devise::Authenticable, :stretches, 10)
|
||||
@@ -86,28 +74,6 @@ module Devise
|
||||
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
|
||||
|
||||
|
||||
@@ -39,10 +39,16 @@ module Devise
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# 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.
|
||||
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 need to overwrite this method, you should overwrite active? and
|
||||
# However, you should not overwrite this method, you should overwrite active? and
|
||||
# inactive_message instead.
|
||||
def valid_for_authentication?
|
||||
if active?
|
||||
@@ -86,6 +92,34 @@ 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
|
||||
|
||||
# Generate a token by looping and ensuring does not already exist.
|
||||
def generate_token(column)
|
||||
loop do
|
||||
token = Devise.friendly_token
|
||||
break token unless find(:first, :conditions => { column => token })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,12 +45,13 @@ module Devise
|
||||
|
||||
# Verifies whether a user is confirmed or not
|
||||
def confirmed?
|
||||
persisted? && !confirmed_at.nil?
|
||||
!!confirmed_at
|
||||
end
|
||||
|
||||
# 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.
|
||||
@@ -63,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.
|
||||
@@ -74,15 +75,14 @@ module Devise
|
||||
# If you don't want confirmation to be sent on create, neither a code
|
||||
# to be generated, call skip_confirmation!
|
||||
def skip_confirmation!
|
||||
self.confirmed_at = Time.now
|
||||
@skip_confirmation = true
|
||||
self.confirmed_at = Time.now
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Callback to overwrite if confirmation is required or not.
|
||||
def confirmation_required?
|
||||
!@skip_confirmation
|
||||
!confirmed?
|
||||
end
|
||||
|
||||
# Checks if the confirmation for the user is within the limit time.
|
||||
@@ -127,6 +127,10 @@ module Devise
|
||||
self.confirmation_sent_at = Time.now.utc
|
||||
end
|
||||
|
||||
def generate_confirmation_token!
|
||||
generate_confirmation_token && save(:validate => false)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attempt to find a user by it's email. If a record is found, send new
|
||||
# confirmation instructions to it. If not user is found, returns a new user
|
||||
@@ -148,8 +152,9 @@ module Devise
|
||||
confirmable
|
||||
end
|
||||
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def confirmation_token
|
||||
Devise.friendly_token
|
||||
generate_token(:confirmation_token)
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :confirm_within)
|
||||
|
||||
@@ -37,7 +37,7 @@ module Devise
|
||||
@password = new_password
|
||||
|
||||
if @password.present?
|
||||
self.password_salt = self.class.encryptor_class.salt
|
||||
self.password_salt = self.class.password_salt
|
||||
self.encrypted_password = password_digest(@password)
|
||||
end
|
||||
end
|
||||
@@ -58,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)
|
||||
@@ -91,6 +93,14 @@ module Devise
|
||||
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
||||
end
|
||||
|
||||
def password_salt
|
||||
self.encryptor_class.salt(self.stretches)
|
||||
end
|
||||
|
||||
# We assume this method already gets the sanitized values from the
|
||||
# DatabaseAuthenticatable strategy. If you are using this method on
|
||||
# your own, be sure to sanitize the conditions hash to only include
|
||||
# the proper fields.
|
||||
def find_for_database_authentication(conditions)
|
||||
find_for_authentication(conditions)
|
||||
end
|
||||
|
||||
@@ -49,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.
|
||||
|
||||
@@ -28,14 +28,14 @@ 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
|
||||
|
||||
# Generates a new random token for reset password
|
||||
def generate_reset_password_token
|
||||
self.reset_password_token = Devise.friendly_token
|
||||
self.reset_password_token = self.class.reset_password_token
|
||||
end
|
||||
|
||||
# Resets the reset password token with and save the record without
|
||||
@@ -60,6 +60,11 @@ module Devise
|
||||
recoverable
|
||||
end
|
||||
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def reset_password_token
|
||||
generate_token(:reset_password_token)
|
||||
end
|
||||
|
||||
# Attempt to find a user by it's reset_password_token to reset it's
|
||||
# password. If a user is found, reset it's password and automatically
|
||||
# try saving the record. If not user is found, returns a new user
|
||||
|
||||
@@ -18,7 +18,15 @@ module Devise
|
||||
# blocked and will have to enter his credentials again.
|
||||
# This configuration is also used to calculate the expires
|
||||
# time for the cookie created to remember the user.
|
||||
# By default remember_for is 2.weeks.
|
||||
# 2.weeks by default.
|
||||
#
|
||||
# remember_across_browsers: if true, a valid remember token can be
|
||||
# re-used between multiple browsers.
|
||||
# True by default.
|
||||
#
|
||||
# extend_remember_period: if true, extends the user's remember period
|
||||
# when remembered via cookie.
|
||||
# False by default.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
@@ -38,10 +46,11 @@ module Devise
|
||||
attr_accessor :remember_me
|
||||
end
|
||||
|
||||
# Generate a new remember token and save the record without validations.
|
||||
def remember_me!
|
||||
self.remember_token = Devise.friendly_token
|
||||
self.remember_created_at = Time.now.utc
|
||||
# Generate a new remember token and save the record without validations
|
||||
# unless remember_across_browsers is true and the user already has a valid token.
|
||||
def remember_me!(extend_period=false)
|
||||
self.remember_token = self.class.remember_token if generate_remember_token?
|
||||
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
|
||||
save(:validate => false)
|
||||
end
|
||||
|
||||
@@ -57,7 +66,7 @@ module Devise
|
||||
|
||||
# Remember token should be expired if expiration time not overpass now.
|
||||
def remember_expired?
|
||||
remember_expires_at <= Time.now.utc
|
||||
remember_created_at && (remember_expires_at <= Time.now.utc)
|
||||
end
|
||||
|
||||
# Remember token expires at created time + remember_for configuration
|
||||
@@ -65,6 +74,28 @@ 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
|
||||
|
||||
protected
|
||||
|
||||
# Generate a token unless remember_across_browsers is true and there is
|
||||
# an existing remember_token or the existing remember_token has expried.
|
||||
def generate_remember_token? #:nodoc:
|
||||
!(self.class.remember_across_browsers && remember_token) || remember_expired?
|
||||
end
|
||||
|
||||
# Generate a timestamp if extend_remember_period is true, if no remember_token
|
||||
# exists, or if an existing remember token has expired.
|
||||
def generate_remember_timestamp?(extend_period) #:nodoc:
|
||||
extend_period || remember_created_at.nil? || remember_expired?
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Create the cookie key using the record id and remember_token
|
||||
def serialize_into_cookie(record)
|
||||
@@ -78,7 +109,13 @@ module Devise
|
||||
record if record && !record.remember_expired?
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :remember_for)
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def remember_token
|
||||
generate_token(:remember_token)
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :remember_for, :remember_across_browsers,
|
||||
:extend_remember_period, :cookie_domain)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -44,16 +44,16 @@ module Devise
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
::Devise::Models.config(self, :token_authentication_key)
|
||||
|
||||
def find_for_token_authentication(conditions)
|
||||
conditions[:authentication_token] ||= conditions.delete(token_authentication_key)
|
||||
find_for_authentication(conditions)
|
||||
find_for_authentication(:authentication_token => conditions[token_authentication_key])
|
||||
end
|
||||
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def authentication_token
|
||||
::Devise.friendly_token
|
||||
generate_token(:authentication_token)
|
||||
end
|
||||
|
||||
::Devise::Models.config(self, :token_authentication_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ module Devise
|
||||
|
||||
base.class_eval do
|
||||
validates_presence_of :email
|
||||
validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :allow_blank => true
|
||||
validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :case_sensitive => false, :allow_blank => true
|
||||
validates_format_of :email, :with => email_regexp, :allow_blank => true
|
||||
|
||||
with_options :if => :password_required? do |v|
|
||||
|
||||
@@ -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
|
||||
@@ -1,99 +0,0 @@
|
||||
module Devise
|
||||
module Orm
|
||||
module DataMapper
|
||||
module Hook
|
||||
def devise_modules_hook!
|
||||
extend Schema
|
||||
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
|
||||
|
||||
SCHEMA_OPTIONS = {
|
||||
:null => :required,
|
||||
:limit => :length
|
||||
}
|
||||
|
||||
# Tell how to apply schema methods. This automatically maps :limit to
|
||||
# :length and :null to :required.
|
||||
def apply_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)
|
||||
end
|
||||
|
||||
options.delete(:default) if options[:default].nil?
|
||||
property name, type, options
|
||||
end
|
||||
end
|
||||
|
||||
module Compatibility
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# Hooks for confirmable
|
||||
def before_create(*args)
|
||||
wrap_hook(:before, :create, *args)
|
||||
end
|
||||
|
||||
def after_create(*args)
|
||||
wrap_hook(:after, :create, *args)
|
||||
end
|
||||
|
||||
def before_save(*args)
|
||||
wrap_hook(:before, :save, *args)
|
||||
end
|
||||
|
||||
def wrap_hook(action, method, *args)
|
||||
options = args.extract_options!
|
||||
|
||||
args.each do |callback|
|
||||
send action, method, callback
|
||||
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
||||
def #{callback}
|
||||
super if #{options[:if] || true}
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
# Add ActiveRecord like finder
|
||||
def find(*args)
|
||||
case args.first
|
||||
when :first, :all
|
||||
send(args.shift, *args)
|
||||
else
|
||||
get(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def changed?
|
||||
dirty?
|
||||
end
|
||||
|
||||
def save(options=nil)
|
||||
if options.is_a?(Hash) && options[:validate] == false
|
||||
save!
|
||||
else
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
def update_attributes(*args)
|
||||
update(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DataMapper::Model.class_eval do
|
||||
include Devise::Models
|
||||
include Devise::Orm::DataMapper::Hook
|
||||
end
|
||||
@@ -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
|
||||
|
||||
18
lib/devise/path_checker.rb
Normal file
18
lib/devise/path_checker.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
module Devise
|
||||
class PathChecker
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def self.default_url_options(*args)
|
||||
ApplicationController.default_url_options(*args)
|
||||
end
|
||||
|
||||
def initialize(env, scope)
|
||||
@current_path = "/#{env["SCRIPT_NAME"]}/#{env["PATH_INFO"]}".squeeze("/")
|
||||
@scope = scope
|
||||
end
|
||||
|
||||
def signing_out?
|
||||
@current_path == send("destroy_#{@scope}_session_path")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,35 +1,67 @@
|
||||
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." if Devise.mailer_sender
|
||||
:bcrypt
|
||||
end
|
||||
end
|
||||
|
||||
initializer "devise.add_url_helpers" do |app|
|
||||
Devise::FailureApp.send :include, app.routes.url_helpers
|
||||
ActionController::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
ActionView::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
initializer "devise.add_filters" do |app|
|
||||
app.config.filter_parameters += [:password, :password_confirmation]
|
||||
app.config.filter_parameters.uniq
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
I18n.available_locales
|
||||
flash = [:unauthenticated, :unconfirmed, :invalid, :invalid_token, :timeout, :inactive, :locked]
|
||||
unless Rails.env.production?
|
||||
config.after_initialize do
|
||||
actions = [:confirmation_instructions, :reset_password_instructions, :unlock_instructions]
|
||||
|
||||
I18n.backend.send(:translations).each do |locale, translations|
|
||||
keys = flash & (translations[:devise][:sessions].keys) rescue []
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -15,9 +15,10 @@ module ActionDispatch::Routing
|
||||
# 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:
|
||||
# ==== 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
|
||||
#
|
||||
@@ -25,20 +26,22 @@ module ActionDispatch::Routing
|
||||
# needed routes:
|
||||
#
|
||||
# # Session routes for Authenticatable (default)
|
||||
# new_user_session GET /users/sign_in {:controller=>"sessions", :action=>"new"}
|
||||
# user_session POST /users/sign_in {:controller=>"sessions", :action=>"create"}
|
||||
# destroy_user_session GET /users/sign_out {:controller=>"sessions", :action=>"destroy"}
|
||||
# new_user_session GET /users/sign_in {:controller=>"devise/sessions", :action=>"new"}
|
||||
# user_session POST /users/sign_in {:controller=>"devise/sessions", :action=>"create"}
|
||||
# destroy_user_session GET /users/sign_out {:controller=>"devise/sessions", :action=>"destroy"}
|
||||
#
|
||||
# # Password routes for Recoverable, if User model has :recoverable configured
|
||||
# new_user_password GET /users/password/new(.:format) {:controller=>"passwords", :action=>"new"}
|
||||
# edit_user_password GET /users/password/edit(.:format) {:controller=>"passwords", :action=>"edit"}
|
||||
# user_password PUT /users/password(.:format) {:controller=>"passwords", :action=>"update"}
|
||||
# POST /users/password(.:format) {:controller=>"passwords", :action=>"create"}
|
||||
# new_user_password GET /users/password/new(.:format) {:controller=>"devise/passwords", :action=>"new"}
|
||||
# edit_user_password GET /users/password/edit(.:format) {:controller=>"devise/passwords", :action=>"edit"}
|
||||
# user_password PUT /users/password(.:format) {:controller=>"devise/passwords", :action=>"update"}
|
||||
# POST /users/password(.:format) {:controller=>"devise/passwords", :action=>"create"}
|
||||
#
|
||||
# # Confirmation routes for Confirmable, if User model has :confirmable configured
|
||||
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"confirmations", :action=>"new"}
|
||||
# user_confirmation GET /users/confirmation(.:format) {:controller=>"confirmations", :action=>"show"}
|
||||
# POST /users/confirmation(.:format) {:controller=>"confirmations", :action=>"create"}
|
||||
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"devise/confirmations", :action=>"new"}
|
||||
# user_confirmation GET /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"show"}
|
||||
# POST /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"create"}
|
||||
#
|
||||
# ==== Options
|
||||
#
|
||||
# You can configure your routes with some options:
|
||||
#
|
||||
@@ -62,83 +65,184 @@ module ActionDispatch::Routing
|
||||
#
|
||||
# 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"
|
||||
#
|
||||
# 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 }
|
||||
# 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" }
|
||||
#
|
||||
# * :module => the namespace to find controlers. By default, devise will access devise/sessions,
|
||||
# devise/registrations and so on. If you want to namespace all at once, use module:
|
||||
#
|
||||
# devise_for :users, :module => "users"
|
||||
#
|
||||
# Notice that whenever you use namespace in the router DSL, it automatically sets the module.
|
||||
# So the following setup:
|
||||
#
|
||||
# namespace :publisher
|
||||
# devise_for :account
|
||||
# end
|
||||
#
|
||||
# Will use publisher/sessions controller instead of devise/sessions controller. You can revert
|
||||
# this by providing the :module option to devise_for.
|
||||
#
|
||||
# * :skip => tell which controller you want to skip routes from being created:
|
||||
#
|
||||
# devise_for :users, :skip => :sessions
|
||||
#
|
||||
# ==== Scoping
|
||||
#
|
||||
# Following Rails 3 routes DSL, you can nest devise_for calls inside a scope:
|
||||
#
|
||||
# scope "/my" do
|
||||
# devise_for :users
|
||||
# end
|
||||
#
|
||||
# However, since Devise uses the request path to retrieve the current user, it has one caveats.
|
||||
# If you are using a dynamic segment, as below:
|
||||
#
|
||||
# scope ":locale" do
|
||||
# devise_for :users
|
||||
# end
|
||||
#
|
||||
# You are required 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 }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def devise_for(*resources)
|
||||
options = resources.extract_options!
|
||||
|
||||
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
|
||||
|
||||
options[:as] ||= @scope[:as] if @scope[:as].present?
|
||||
options[:module] ||= @scope[:module] if @scope[:module].present?
|
||||
options[:path_prefix] ||= @scope[:path] if @scope[:path].present?
|
||||
options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {})
|
||||
|
||||
resources.map!(&:to_sym)
|
||||
|
||||
resources.each do |resource|
|
||||
mapping = Devise.register(resource, options)
|
||||
mapping = Devise.add_mapping(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 NameError => e
|
||||
raise unless mapping.class_name == resource.to_s.classify
|
||||
warn "[WARNING] You provided devise_for #{resource.inspect} but there is " <<
|
||||
"no model #{mapping.class_name} defined in your application"
|
||||
next
|
||||
rescue NoMethodError => e
|
||||
raise unless e.message.include?("undefined method `devise'")
|
||||
raise_no_devise_method_error!(mapping.class_name)
|
||||
end
|
||||
|
||||
routes = mapping.routes
|
||||
routes -= Array(options.delete(:skip)).map { |s| s.to_s.singularize.to_sym }
|
||||
|
||||
routes.each do |mod|
|
||||
send(:"devise_#{mod}", mapping, mapping.controllers)
|
||||
devise_scope mapping.name do
|
||||
yield if block_given?
|
||||
with_devise_exclusive_scope mapping.fullpath, mapping.name do
|
||||
routes.each { |mod| send(:"devise_#{mod}", mapping, mapping.controllers) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Allow you to add authentication request from the router:
|
||||
#
|
||||
# authenticate(:user) do
|
||||
# resources :post
|
||||
# end
|
||||
#
|
||||
def authenticate(scope)
|
||||
constraint = lambda do |request|
|
||||
request.env["warden"].authenticate!(:scope => scope)
|
||||
end
|
||||
|
||||
constraints(constraint) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the devise scope to be used in the controller. If you have custom routes,
|
||||
# you are required to call this method (also aliased as :as) in order to specify
|
||||
# to which controller it is targetted.
|
||||
#
|
||||
# as :user do
|
||||
# get "sign_in", :to => "devise/sessions#new"
|
||||
# end
|
||||
#
|
||||
# Notice you cannot have two scopes mapping to the same URL. And remember, if
|
||||
# you try to access a devise controller without specifying a scope, it will
|
||||
# raise ActionNotFound error.
|
||||
def devise_scope(scope)
|
||||
constraint = lambda do |request|
|
||||
request.env["devise.mapping"] = Devise.mappings[scope]
|
||||
true
|
||||
end
|
||||
|
||||
constraints(constraint) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
alias :as :devise_scope
|
||||
|
||||
protected
|
||||
|
||||
def devise_session(mapping, controllers)
|
||||
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"
|
||||
def devise_session(mapping, controllers) #:nodoc:
|
||||
scope :controller => controllers[:sessions], :as => :session do
|
||||
get :new, :path => mapping.path_names[:sign_in]
|
||||
post :create, :path => mapping.path_names[:sign_in], :as => ""
|
||||
get :destroy, :path => mapping.path_names[:sign_out]
|
||||
end
|
||||
end
|
||||
|
||||
def devise_password(mapping, controllers)
|
||||
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
|
||||
def devise_password(mapping, controllers) #:nodoc:
|
||||
resource :password, :only => [:new, :create, :edit, :update],
|
||||
:path => mapping.path_names[:password], :controller => controllers[:passwords]
|
||||
end
|
||||
|
||||
def devise_confirmation(mapping, controllers)
|
||||
scope mapping.full_path, :name_prefix => mapping.name do
|
||||
resource :confirmation, :only => [:new, :create, :show], :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
|
||||
end
|
||||
def devise_confirmation(mapping, controllers) #:nodoc:
|
||||
resource :confirmation, :only => [:new, :create, :show],
|
||||
:path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
|
||||
end
|
||||
|
||||
def devise_unlock(mapping, controllers)
|
||||
scope mapping.full_path, :name_prefix => mapping.name do
|
||||
resource :unlock, :only => [:new, :create, :show], :path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
|
||||
def devise_unlock(mapping, controllers) #:nodoc:
|
||||
if mapping.to.unlock_strategy_enabled?(:email)
|
||||
resource :unlock, :only => [:new, :create, :show],
|
||||
:path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
|
||||
end
|
||||
end
|
||||
|
||||
def devise_registration(mapping, controllers)
|
||||
scope mapping.full_path[1..-1], :name_prefix => mapping.name do
|
||||
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => "",
|
||||
:path_names => { :new => mapping.path_names[:sign_up] }, :controller => controllers[:registrations]
|
||||
end
|
||||
def devise_registration(mapping, controllers) #:nodoc:
|
||||
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
|
||||
|
||||
def with_devise_exclusive_scope(new_path, new_as) #:nodoc:
|
||||
old_as, old_path, old_module = @scope[:as], @scope[:path], @scope[:module]
|
||||
@scope[:as], @scope[:path], @scope[:module] = new_as, new_path, nil
|
||||
yield
|
||||
ensure
|
||||
@scope[:as], @scope[:path], @scope[:module] = old_as, old_path, old_module
|
||||
end
|
||||
|
||||
def raise_no_devise_method_error!(klass) #:nodoc:
|
||||
raise "#{klass} does not respond to 'devise' method. This usually means you haven't " <<
|
||||
"loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " <<
|
||||
"inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,11 +15,25 @@ end
|
||||
|
||||
class Warden::SessionSerializer
|
||||
def serialize(record)
|
||||
[record.class, record.id]
|
||||
[record.class.name, record.id]
|
||||
end
|
||||
|
||||
def deserialize(keys)
|
||||
klass, id = keys
|
||||
klass.find(:first, :conditions => { :id => id })
|
||||
|
||||
if klass.is_a?(Class)
|
||||
raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
|
||||
"you can fix it by changing one character in your cookie secret, forcing all previous " <<
|
||||
"cookies to expire, or cleaning up your database sessions if you are using a db store."
|
||||
end
|
||||
|
||||
klass.constantize.find(:first, :conditions => { :id => id })
|
||||
rescue NameError => e
|
||||
if e.message =~ /uninitialized constant/
|
||||
Rails.logger.debug "Trying to deserialize invalid class #{klass}"
|
||||
nil
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,10 @@ module Devise
|
||||
# == Options
|
||||
# * :null - When true, allow columns to be null.
|
||||
# * :default - Should be set to "" when :null is false.
|
||||
#
|
||||
# == Notes
|
||||
# For Datamapper compatibility, we explicitly hardcode the limit for the
|
||||
# encrypter password field in 128 characters.
|
||||
def database_authenticatable(options={})
|
||||
null = options[:null] || false
|
||||
default = options[:default] || ""
|
||||
@@ -21,42 +25,42 @@ module Devise
|
||||
ActiveSupport::Deprecation.warn ":encryptor as option is deprecated, simply remove it."
|
||||
end
|
||||
|
||||
apply_schema :email, String, :null => null, :default => default
|
||||
apply_schema :encrypted_password, String, :null => null, :default => default, :limit => 128
|
||||
apply_schema :password_salt, String, :null => null, :default => default
|
||||
apply_devise_schema :email, String, :null => null, :default => default
|
||||
apply_devise_schema :encrypted_password, String, :null => null, :default => default, :limit => 128
|
||||
apply_devise_schema :password_salt, String, :null => null, :default => default
|
||||
end
|
||||
|
||||
# Creates authentication_token.
|
||||
def token_authenticatable(options={})
|
||||
apply_schema :authentication_token, String
|
||||
apply_devise_schema :authentication_token, String
|
||||
end
|
||||
|
||||
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
|
||||
def confirmable
|
||||
apply_schema :confirmation_token, String
|
||||
apply_schema :confirmed_at, DateTime
|
||||
apply_schema :confirmation_sent_at, DateTime
|
||||
apply_devise_schema :confirmation_token, String
|
||||
apply_devise_schema :confirmed_at, DateTime
|
||||
apply_devise_schema :confirmation_sent_at, DateTime
|
||||
end
|
||||
|
||||
# Creates reset_password_token.
|
||||
def recoverable
|
||||
apply_schema :reset_password_token, String
|
||||
apply_devise_schema :reset_password_token, String
|
||||
end
|
||||
|
||||
# Creates remember_token and remember_created_at.
|
||||
def rememberable
|
||||
apply_schema :remember_token, String
|
||||
apply_schema :remember_created_at, DateTime
|
||||
apply_devise_schema :remember_token, String
|
||||
apply_devise_schema :remember_created_at, DateTime
|
||||
end
|
||||
|
||||
# Creates sign_in_count, current_sign_in_at, last_sign_in_at,
|
||||
# current_sign_in_ip, last_sign_in_ip.
|
||||
def trackable
|
||||
apply_schema :sign_in_count, Integer, :default => 0
|
||||
apply_schema :current_sign_in_at, DateTime
|
||||
apply_schema :last_sign_in_at, DateTime
|
||||
apply_schema :current_sign_in_ip, String
|
||||
apply_schema :last_sign_in_ip, String
|
||||
apply_devise_schema :sign_in_count, Integer, :default => 0
|
||||
apply_devise_schema :current_sign_in_at, DateTime
|
||||
apply_devise_schema :last_sign_in_at, DateTime
|
||||
apply_devise_schema :current_sign_in_ip, String
|
||||
apply_devise_schema :last_sign_in_ip, String
|
||||
end
|
||||
|
||||
# Creates failed_attempts, unlock_token and locked_at depending on the options given.
|
||||
@@ -75,18 +79,18 @@ module Devise
|
||||
lock_strategy ||= :failed_attempts
|
||||
|
||||
if lock_strategy == :failed_attempts
|
||||
apply_schema :failed_attempts, Integer, :default => 0
|
||||
apply_devise_schema :failed_attempts, Integer, :default => 0
|
||||
end
|
||||
|
||||
if [:both, :email].include?(unlock_strategy)
|
||||
apply_schema :unlock_token, String
|
||||
apply_devise_schema :unlock_token, String
|
||||
end
|
||||
|
||||
apply_schema :locked_at, DateTime
|
||||
apply_devise_schema :locked_at, DateTime
|
||||
end
|
||||
|
||||
# Overwrite with specific modification to create your own schema.
|
||||
def apply_schema(name, type, options={})
|
||||
def apply_devise_schema(name, type, options={})
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,12 +14,35 @@ module Devise
|
||||
|
||||
private
|
||||
|
||||
# Check if this is strategy is valid for http authentication.
|
||||
# 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 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)
|
||||
@@ -51,12 +74,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
|
||||
@@ -66,6 +89,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 || ''
|
||||
|
||||
@@ -10,24 +10,6 @@ module Devise
|
||||
mapping
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def succeeded?
|
||||
@result == :success
|
||||
end
|
||||
|
||||
# Simply invokes valid_for_authentication? with the given block and deal with the result.
|
||||
def validate(resource, &block)
|
||||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
case result
|
||||
when Symbol, String
|
||||
fail!(result)
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ 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
|
||||
|
||||
@@ -6,7 +6,7 @@ module Devise
|
||||
# to verify whether there is a cookie with the remember token, and to
|
||||
# recreate the user from this cookie if it exists. Must be called *before*
|
||||
# authenticatable.
|
||||
class Rememberable < Devise::Strategies::Base
|
||||
class Rememberable < Authenticatable
|
||||
# A valid strategy for rememberable needs a remember token in the cookies.
|
||||
def valid?
|
||||
remember_cookie.present?
|
||||
@@ -28,10 +28,18 @@ module Devise
|
||||
|
||||
private
|
||||
|
||||
def remember_me?
|
||||
true
|
||||
end
|
||||
|
||||
def remember_key
|
||||
"remember_#{scope}_token"
|
||||
end
|
||||
|
||||
def extend_remember_period?
|
||||
mapping.to.extend_remember_period
|
||||
end
|
||||
|
||||
# Accessor for remember cookie
|
||||
def remember_cookie
|
||||
@remember_cookie ||= cookies.signed[remember_key]
|
||||
|
||||
@@ -7,8 +7,8 @@ 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!
|
||||
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
||||
|
||||
@@ -40,7 +40,10 @@ 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"]
|
||||
|
||||
nil
|
||||
else
|
||||
result
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Devise
|
||||
VERSION = "1.1.rc1".freeze
|
||||
VERSION = "1.1.1".freeze
|
||||
end
|
||||
|
||||
28
lib/generators/active_record/devise_generator.rb
Normal file
28
lib/generators/active_record/devise_generator.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
require 'rails/generators/active_record'
|
||||
require 'generators/devise/orm_helpers'
|
||||
|
||||
module ActiveRecord
|
||||
module Generators
|
||||
class DeviseGenerator < ActiveRecord::Generators::Base
|
||||
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
||||
|
||||
include Devise::Generators::OrmHelpers
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
|
||||
def generate_model
|
||||
invoke "active_record:model", [name], :migration => false unless model_exists?
|
||||
end
|
||||
|
||||
def copy_devise_migration
|
||||
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
|
||||
end
|
||||
|
||||
def inject_devise_content
|
||||
inject_into_class model_path, class_name, model_contents + <<-CONTENT
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
attr_accessible :email, :password, :password_confirmation, :remember_me
|
||||
CONTENT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,20 +2,24 @@ 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
|
||||
|
||||
<% for attribute in attributes -%>
|
||||
t.<%= attribute.type %> :<%= attribute.name %>
|
||||
<% end -%>
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :<%= table_name %>, :email, :unique => true
|
||||
add_index :<%= table_name %>, :confirmation_token, :unique => true
|
||||
add_index :<%= table_name %>, :reset_password_token, :unique => true
|
||||
# add_index :<%= table_name %>, :confirmation_token, :unique => true
|
||||
# add_index :<%= table_name %>, :unlock_token, :unique => true
|
||||
end
|
||||
|
||||
@@ -1,67 +1,17 @@
|
||||
require 'rails/generators/migration'
|
||||
module Devise
|
||||
module Generators
|
||||
class DeviseGenerator < Rails::Generators::NamedBase
|
||||
namespace "devise"
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
|
||||
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."
|
||||
|
||||
desc "Generates a model with the given NAME (if one does not exist) with devise " <<
|
||||
"configuration plus a migration file and devise routes."
|
||||
hook_for :orm
|
||||
|
||||
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}`."
|
||||
def add_devise_routes
|
||||
route "devise_for :#{table_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 and :timeoutable
|
||||
devise :database_authenticatable, :registerable, :confirmable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
attr_accessible :email, :password, :password_confirmation
|
||||
CONTENT
|
||||
end
|
||||
|
||||
def copy_migration_template
|
||||
return unless options.migration?
|
||||
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
|
||||
end
|
||||
|
||||
def add_devise_routes
|
||||
route "devise_for :#{table_name}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def model_exists?
|
||||
File.exists?(File.join(destination_root, model_path))
|
||||
end
|
||||
|
||||
def model_path
|
||||
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
||||
end
|
||||
end
|
||||
|
||||
24
lib/generators/devise/install_generator.rb
Normal file
24
lib/generators/devise/install_generator.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
require 'active_support/secure_random'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
class InstallGenerator < Rails::Generators::Base
|
||||
source_root File.expand_path("../../templates", __FILE__)
|
||||
|
||||
desc "Creates a Devise initializer and copy locale files to your application."
|
||||
class_option :orm
|
||||
|
||||
def copy_initializer
|
||||
template "devise.rb", "config/initializers/devise.rb"
|
||||
end
|
||||
|
||||
def copy_locale
|
||||
copy_file "../../../config/locales/en.yml", "config/locales/devise.en.yml"
|
||||
end
|
||||
|
||||
def show_readme
|
||||
readme "README" if behavior == :invoke
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
23
lib/generators/devise/orm_helpers.rb
Normal file
23
lib/generators/devise/orm_helpers.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
module Devise
|
||||
module Generators
|
||||
module OrmHelpers
|
||||
def model_contents
|
||||
<<-CONTENT
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :confirmable, :lockable and :timeoutable
|
||||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
CONTENT
|
||||
end
|
||||
|
||||
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
|
||||
63
lib/generators/devise/views_generator.rb
Normal file
63
lib/generators/devise/views_generator.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
module Devise
|
||||
module Generators
|
||||
class ViewsGenerator < Rails::Generators::Base
|
||||
source_root File.expand_path("../../../../app/views", __FILE__)
|
||||
desc "Copies all Devise views to your application."
|
||||
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
class_option :template_engine, :type => :string, :aliases => "-t", :default => "erb",
|
||||
:desc => "Template engine for the views. Available options are 'erb' and 'haml'."
|
||||
|
||||
def copy_views
|
||||
case options[:template_engine].to_s
|
||||
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
|
||||
@@ -1,25 +0,0 @@
|
||||
class DeviseInstallGenerator < Rails::Generators::Base
|
||||
desc "Creates a Devise initializer and copy locale files to your application."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../templates", __FILE__)
|
||||
end
|
||||
|
||||
def copy_initializer
|
||||
template "devise.rb", "config/initializers/devise.rb"
|
||||
end
|
||||
|
||||
def copy_locale
|
||||
copy_file "../../../../config/locales/en.yml", "config/locales/devise.en.yml"
|
||||
end
|
||||
|
||||
def show_readme
|
||||
readme "README"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def readme(path)
|
||||
say File.read(File.expand_path(path, self.class.source_root))
|
||||
end
|
||||
end
|
||||
4
lib/generators/devise_install_generator.rb
Normal file
4
lib/generators/devise_install_generator.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
# Remove this file after deprecation
|
||||
if caller.none? { |l| l =~ %r{lib/rails/generators\.rb:(\d+):in `lookup!'$} }
|
||||
warn "[WARNING] `rails g devise_install` is deprecated, please use `rails g devise:install` instead."
|
||||
end
|
||||
@@ -1,62 +0,0 @@
|
||||
class DeviseViewsGenerator < Rails::Generators::Base
|
||||
desc "Copies all Devise views to your application."
|
||||
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
class_option :template_engine, :type => :string, :aliases => "-t", :default => "erb",
|
||||
:desc => "Template engine for the views. Available options are 'erb' and 'haml'."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../../../../app/views", __FILE__)
|
||||
end
|
||||
|
||||
def copy_views
|
||||
case options[:template_engine]
|
||||
when "haml"
|
||||
verify_haml_existence
|
||||
verify_haml_version
|
||||
create_and_copy_haml_views
|
||||
else
|
||||
directory "devise", "app/views/#{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
|
||||
4
lib/generators/devise_views_generator.rb
Normal file
4
lib/generators/devise_views_generator.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
# Remove this file after deprecation
|
||||
if caller.none? { |l| l =~ %r{lib/rails/generators\.rb:(\d+):in `lookup!'$} }
|
||||
warn "[WARNING] `rails g devise_views` is deprecated, please use `rails g devise:views` instead."
|
||||
end
|
||||
17
lib/generators/mongoid/devise_generator.rb
Normal file
17
lib/generators/mongoid/devise_generator.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
require 'generators/devise/orm_helpers'
|
||||
|
||||
module Mongoid
|
||||
module Generators
|
||||
class DeviseGenerator < Rails::Generators::NamedBase
|
||||
include Devise::Generators::OrmHelpers
|
||||
|
||||
def generate_model
|
||||
invoke "mongoid:model", [name] unless model_exists?
|
||||
end
|
||||
|
||||
def inject_devise_content
|
||||
inject_into_file model_path, model_contents, :after => "include Mongoid::Document\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,7 @@ Some setup you must do manually if you haven't yet:
|
||||
|
||||
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
|
||||
|
||||
This is a required Rails configuration. In production is must be the
|
||||
This is a required Rails configuration. In production it must be the
|
||||
actual host of your application
|
||||
|
||||
2. Ensure you have defined root_url to *something* in your config/routes.rb.
|
||||
@@ -1,9 +1,19 @@
|
||||
# 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) and
|
||||
# :mongoid (bson_ext recommended) by default. Other ORMs may be
|
||||
# available as additional gems.
|
||||
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
|
||||
@@ -18,33 +28,45 @@ Devise.setup do |config|
|
||||
# Tell if authentication through HTTP Basic Auth is enabled. True by default.
|
||||
# config.http_authenticatable = true
|
||||
|
||||
# Set this to true to use Basic Auth for AJAX requests. True by default.
|
||||
# config.http_authenticatable_on_xhr = true
|
||||
|
||||
# The realm used in Http Basic Authentication
|
||||
# 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
|
||||
# The time the user will be remembered without asking for credentials again.
|
||||
# config.remember_for = 2.weeks
|
||||
|
||||
# If true, a valid remember token can be re-used between multiple browsers.
|
||||
# config.remember_across_browsers = true
|
||||
|
||||
# If true, extends the user's remember period when remembered via cookie.
|
||||
# config.extend_remember_period = false
|
||||
|
||||
# ==> Configuration for :validatable
|
||||
# Range for password length
|
||||
# config.password_length = 6..20
|
||||
@@ -65,7 +87,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,26 +103,30 @@ 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
|
||||
# "users/sessions/new". It's turned off by default because it's slower if you
|
||||
# are using only default views.
|
||||
# config.scoped_views = true
|
||||
|
||||
# By default, devise detects the role accessed based on the url. So whenever
|
||||
# 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.
|
||||
# config.use_default_scope = true
|
||||
|
||||
# Configure the default scope used by Devise. By default it's the first devise
|
||||
# role declared in your routes.
|
||||
# Configure the default scope given to Warden. By default it's the first
|
||||
# devise role declared in your routes.
|
||||
# config.default_scope = :user
|
||||
|
||||
# Configure sign_out behavior.
|
||||
# By default sign_out is scoped (i.e. /users/sign_out affects only :user scope).
|
||||
# In case of sign_out_all_scopes set to true any logout action will sign out all active scopes.
|
||||
# config.sign_out_all_scopes = false
|
||||
|
||||
# ==> 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
|
||||
@@ -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
|
||||
@@ -119,6 +126,15 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.sign_out(User.new)
|
||||
end
|
||||
|
||||
test 'sign out everybody proxy to logout on warden' do
|
||||
Devise.mappings.keys.each { |scope|
|
||||
@mock_warden.expects(:user).with(scope).returns(true)
|
||||
}
|
||||
|
||||
@mock_warden.expects(:logout).with(*Devise.mappings.keys).returns(true)
|
||||
@controller.sign_out_all_scopes
|
||||
end
|
||||
|
||||
test 'stored location for returns the location for a given scope' do
|
||||
assert_nil @controller.stored_location_for(:user)
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
@@ -145,6 +161,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)
|
||||
|
||||
@@ -10,37 +10,28 @@ class HelpersTest < ActionController::TestCase
|
||||
def setup
|
||||
@mock_warden = OpenStruct.new
|
||||
@controller.request.env['warden'] = @mock_warden
|
||||
@controller.request.env['devise.mapping'] = Devise.mappings[:user]
|
||||
end
|
||||
|
||||
test 'get resource name from request path' do
|
||||
@request.path = '/users/session'
|
||||
test 'get resource name from env' do
|
||||
assert_equal :user, @controller.resource_name
|
||||
end
|
||||
|
||||
test 'get resource name from specific request path' do
|
||||
@request.path = '/admin_area/session'
|
||||
assert_equal :admin, @controller.resource_name
|
||||
end
|
||||
|
||||
test 'get resource class from request path' do
|
||||
@request.path = '/users/session'
|
||||
test 'get resource class from env' do
|
||||
assert_equal User, @controller.resource_class
|
||||
end
|
||||
|
||||
test 'get resource instance variable from request path' do
|
||||
@request.path = '/admin_area/session'
|
||||
@controller.instance_variable_set(:@admin, admin = Admin.new)
|
||||
test 'get resource instance variable from env' do
|
||||
@controller.instance_variable_set(:@user, admin = Admin.new)
|
||||
assert_equal admin, @controller.resource
|
||||
end
|
||||
|
||||
test 'set resource instance variable from request path' do
|
||||
@request.path = '/admin_area/session'
|
||||
|
||||
test 'set resource instance variable from env' do
|
||||
admin = @controller.send(:resource_class).new
|
||||
@controller.send(:resource=, admin)
|
||||
|
||||
assert_equal admin, @controller.send(:resource)
|
||||
assert_equal admin, @controller.instance_variable_get(:@admin)
|
||||
assert_equal admin, @controller.instance_variable_get(:@user)
|
||||
end
|
||||
|
||||
test 'resources methods are not controller actions' do
|
||||
|
||||
@@ -44,4 +44,15 @@ class RoutesTest < ActionController::TestCase
|
||||
assert_path_and_url :confirmation
|
||||
assert_path_and_url :confirmation, :new
|
||||
end
|
||||
|
||||
test 'should alias unlock to mapped user unlock' do
|
||||
assert_path_and_url :unlock
|
||||
assert_path_and_url :unlock, :new
|
||||
end
|
||||
|
||||
test 'should alias registration to mapped user registration' do
|
||||
assert_path_and_url :registration
|
||||
assert_path_and_url :registration, :new
|
||||
assert_path_and_url :registration, :edit
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,7 +23,7 @@ class Encryptors < ActiveSupport::TestCase
|
||||
test "should have length #{value} for #{key.inspect}" do
|
||||
swap Devise, :encryptor => key do
|
||||
encryptor = Devise::Encryptors.const_get(key.to_s.classify)
|
||||
assert_equal value, encryptor.digest('a', 4, encryptor.salt, nil).size
|
||||
assert_equal value, encryptor.digest('a', 4, encryptor.salt(4), nil).size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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,53 @@ 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 'dont return WWW-authenticate on ajax call if http_authenticatable_on_xhr false' do
|
||||
swap Devise, :http_authenticatable_on_xhr => false do
|
||||
call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
|
||||
assert_equal 302, @response.first
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
|
||||
assert_nil @response.second['WWW-Authenticate']
|
||||
end
|
||||
end
|
||||
|
||||
test 'return WWW-authenticate on ajax call if http_authenticatable_on_xhr true' do
|
||||
swap Devise, :http_authenticatable_on_xhr => true do
|
||||
call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
|
||||
assert_equal 401, @response.first
|
||||
assert_equal 'Basic realm="Application"', @response.second["WWW-Authenticate"]
|
||||
end
|
||||
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
|
||||
end
|
||||
|
||||
@@ -85,6 +112,7 @@ class FailureTest < ActiveSupport::TestCase
|
||||
env = {
|
||||
"action_dispatch.request.parameters" => { :controller => "devise/sessions" },
|
||||
"warden.options" => { :recall => "new", :attempted_path => "/users/sign_in" },
|
||||
"devise.mapping" => Devise.mappings[:user],
|
||||
"warden" => stub_everything
|
||||
}
|
||||
call_failure(env)
|
||||
|
||||
344
test/integration/authenticatable_test.rb
Normal file
344
test/integration/authenticatable_test.rb
Normal file
@@ -0,0 +1,344 @@
|
||||
require 'test_helper'
|
||||
|
||||
class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
Devise.sign_out_all_scopes = false
|
||||
end
|
||||
|
||||
def teardown
|
||||
Devise.sign_out_all_scopes = false
|
||||
end
|
||||
|
||||
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 if sign_out_all_scopes is false' 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 if sign_out_all_scopes is false' 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 'sign out as user should also sign out admin if sign_out_all_scopes is true' do
|
||||
Devise.sign_out_all_scopes = true
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_user_session_path
|
||||
assert_not warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as admin should also sign out user if sign_out_all_scopes is true' do
|
||||
Devise.sign_out_all_scopes = true
|
||||
sign_in_as_user
|
||||
sign_in_as_admin
|
||||
|
||||
get destroy_admin_session_path
|
||||
assert_not warden.authenticated?(:admin)
|
||||
assert_not 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_current_url '/users'
|
||||
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_current_url '/users'
|
||||
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 for 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 router' do
|
||||
sign_in_as_user :visit => "/as/sign_in"
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'uses the mapping from nested devise_for call' do
|
||||
sign_in_as_user :visit => "/devise_for/sign_in"
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
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
|
||||
|
||||
test 'sign in with script name' do
|
||||
assert_nothing_raised do
|
||||
get new_user_session_path, {}, "SCRIPT_NAME" => "/omg"
|
||||
fill_in "email", "user@test.com"
|
||||
end
|
||||
end
|
||||
|
||||
test 'registration in xml format' do
|
||||
assert_nothing_raised do
|
||||
post user_registration_path(:format => 'xml', :user => {:email => "test@example.com", :password => "invalid"} )
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not explode when invalid user class is stored in session' do
|
||||
klass = User
|
||||
paths = ActiveSupport::Dependencies.autoload_paths.dup
|
||||
|
||||
begin
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
|
||||
Object.send :remove_const, :User
|
||||
ActiveSupport::Dependencies.autoload_paths.clear
|
||||
|
||||
visit "/users"
|
||||
assert_not warden.authenticated?(:user)
|
||||
ensure
|
||||
Object.const_set(:User, klass)
|
||||
ActiveSupport::Dependencies.autoload_paths.replace(paths)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,16 +16,13 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend confirmation instructions'
|
||||
|
||||
assert_template 'sessions/new'
|
||||
assert_current_url '/users/sign_in'
|
||||
assert_contain 'You will receive an email with instructions about how to confirm your account in a few minutes'
|
||||
assert_equal 1, ActionMailer::Base.deliveries.size
|
||||
end
|
||||
|
||||
test 'user with invalid confirmation token should not be able to confirm an account' do
|
||||
visit_user_confirmation_with_token('invalid_confirmation')
|
||||
|
||||
assert_response :success
|
||||
assert_template 'confirmations/new'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Confirmation token(.*)invalid/
|
||||
end
|
||||
@@ -33,26 +30,36 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
test 'user with valid confirmation token should be able to confirm an account' do
|
||||
user = create_user(:confirm => false)
|
||||
assert_not user.confirmed?
|
||||
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
assert_template 'home/index'
|
||||
assert_contain 'Your account was successfully confirmed.'
|
||||
|
||||
assert_current_url '/'
|
||||
assert user.reload.confirmed?
|
||||
end
|
||||
|
||||
test 'user already confirmed user should not be able to confirm the account again' do
|
||||
test 'already confirmed user should not be able to confirm the account again' do
|
||||
user = create_user(:confirm => false)
|
||||
user.confirmed_at = Time.now
|
||||
user.save
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
assert_template 'confirmations/new'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain 'already confirmed'
|
||||
end
|
||||
|
||||
test 'already confirmed user should not be able to confirm the account again neither request confirmation' do
|
||||
user = create_user(:confirm => false)
|
||||
user.confirmed_at = Time.now
|
||||
user.save
|
||||
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
assert_contain 'already confirmed'
|
||||
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend confirmation instructions'
|
||||
assert_contain 'already confirmed'
|
||||
end
|
||||
|
||||
test 'sign in user automatically after confirming it\'s email' do
|
||||
user = create_user(:confirm => false)
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
@@ -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 routes' do
|
||||
assert_raise ActionController::RoutingError do
|
||||
get '/admin_area/password/new'
|
||||
end
|
||||
end
|
||||
|
||||
test 'render 404 on roles without mapping' do
|
||||
assert_raise AbstractController::ActionNotFound do
|
||||
get '/sign_in'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,8 +5,7 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
test 'sign in should authenticate with http' do
|
||||
sign_in_as_new_user_with_http
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
@@ -17,10 +16,10 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
test 'uses the request format as response content type' do
|
||||
sign_in_as_new_user_with_http("unknown", "123456", :xml)
|
||||
sign_in_as_new_user_with_http("unknown")
|
||||
assert_equal 401, status
|
||||
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
|
||||
assert response.body.include?("<error>Invalid email or password.</error>")
|
||||
assert_match "<error>Invalid email or password.</error>", response.body
|
||||
end
|
||||
|
||||
test 'returns a custom response with www-authenticate and chosen realm' do
|
||||
@@ -33,19 +32,18 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
|
||||
|
||||
test 'sign in should authenticate with http even with specific authentication keys' do
|
||||
swap Devise, :authentication_keys => [:username] do
|
||||
sign_in_as_new_user_with_http "usertest"
|
||||
sign_in_as_new_user_with_http("usertest")
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sign_in_as_new_user_with_http(username="user@test.com", password="123456", format=:html)
|
||||
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
|
||||
user = create_user
|
||||
get users_path(:format => format), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
|
||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
|
||||
user
|
||||
end
|
||||
end
|
||||
@@ -37,27 +37,25 @@ class LockTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
test 'unlocked pages should not be available if email strategy is disabled' do
|
||||
visit "/users/sign_in"
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
visit "/admins/sign_in"
|
||||
|
||||
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
|
||||
assert_raise Webrat::NotFoundError do
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
end
|
||||
|
||||
assert_raise NameError do
|
||||
visit new_admin_unlock_path
|
||||
end
|
||||
|
||||
visit "/admins/unlock/new"
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
test 'user with invalid unlock token should not be able to unlock an account' do
|
||||
visit_user_unlock_with_token('invalid_token')
|
||||
|
||||
assert_response :success
|
||||
assert_template 'unlocks/new'
|
||||
assert_current_url '/users/unlock?unlock_token=invalid_token'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Unlock token(.*)invalid/
|
||||
end
|
||||
@@ -68,7 +66,7 @@ class LockTest < ActionController::IntegrationTest
|
||||
|
||||
visit_user_unlock_with_token(user.unlock_token)
|
||||
|
||||
assert_template 'home/index'
|
||||
assert_current_url '/'
|
||||
assert_contain 'Your account was successfully unlocked.'
|
||||
|
||||
assert_not user.reload.access_locked?
|
||||
|
||||
@@ -65,8 +65,8 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
fill_in 'password confirmation', :with => '123456'
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_template 'registrations/new'
|
||||
assert_contain 'Email has already been taken'
|
||||
assert_current_url '/users'
|
||||
assert_contain(/Email .* already .* taken/)
|
||||
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
@@ -92,7 +92,7 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
fill_in 'current password', :with => '123456'
|
||||
click_button 'Update'
|
||||
|
||||
assert_template 'home/index'
|
||||
assert_current_url '/'
|
||||
assert_contain 'You updated your account successfully.'
|
||||
|
||||
assert_equal "user.new@email.com", User.first.email
|
||||
@@ -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
|
||||
@@ -123,12 +122,25 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
fill_in 'current password', :with => '123456'
|
||||
click_button 'Update'
|
||||
|
||||
assert_template 'home/index'
|
||||
assert_current_url '/'
|
||||
assert_contain 'You updated your account successfully.'
|
||||
|
||||
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
|
||||
|
||||
@@ -3,7 +3,6 @@ require 'test_helper'
|
||||
class RememberMeTest < ActionController::IntegrationTest
|
||||
|
||||
def create_user_and_remember(add_to_token='')
|
||||
Devise.remember_for = 1
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
raw_cookie = User.serialize_into_cookie(user).tap { |a| a.last << add_to_token }
|
||||
@@ -17,14 +16,36 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
request.cookie_jar['raw_cookie']
|
||||
end
|
||||
|
||||
def signed_cookie(key)
|
||||
controller.send(:cookies).signed[key]
|
||||
end
|
||||
|
||||
def cookie_expires(key)
|
||||
cookie = response.headers["Set-Cookie"].split("\n").grep(/^#{key}/).first
|
||||
cookie.split(";").map(&:strip).grep(/^expires=/)
|
||||
Time.parse($')
|
||||
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 +56,51 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
assert warden.user(:user) == user
|
||||
end
|
||||
|
||||
test 'does not remember other scopes' do
|
||||
test 'does not extend remember period through sign in' do
|
||||
swap Devise, :extend_remember_period => true, :remember_for => 1.year do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
|
||||
user.remember_created_at = old = 10.days.ago
|
||||
user.save
|
||||
|
||||
sign_in_as_user :remember_me => true
|
||||
user.reload
|
||||
|
||||
assert warden.user(:user) == user
|
||||
assert_equal old.to_i, user.remember_created_at.to_i
|
||||
end
|
||||
end
|
||||
|
||||
test 'if both extend_remember_period and remember_across_browsers are true, sends the same token with a new expire date' do
|
||||
swap Devise, :remember_across_browsers => true, :extend_remember_period => true, :remember_for => 1.year do
|
||||
user = create_user_and_remember
|
||||
token = user.remember_token
|
||||
|
||||
user.remember_created_at = old = 10.minutes.ago
|
||||
user.save!
|
||||
|
||||
get users_path
|
||||
assert (cookie_expires("remember_user_token") - 1.year) > (old + 5.minutes)
|
||||
assert_equal token, signed_cookie("remember_user_token").last
|
||||
end
|
||||
end
|
||||
|
||||
test 'if both extend_remember_period and remember_across_browsers are false, sends a new token with old expire date' do
|
||||
swap Devise, :remember_across_browsers => false, :extend_remember_period => false, :remember_for => 1.year do
|
||||
user = create_user_and_remember
|
||||
token = user.remember_token
|
||||
|
||||
user.remember_created_at = old = 10.minutes.ago
|
||||
user.save!
|
||||
|
||||
get users_path
|
||||
assert (cookie_expires("remember_user_token") - 1.year) < (old + 5.minutes)
|
||||
assert_not_equal token, signed_cookie("remember_user_token").last
|
||||
end
|
||||
end
|
||||
|
||||
test 'do not remember other scopes' do
|
||||
user = create_user_and_remember
|
||||
get root_path
|
||||
assert_response :success
|
||||
@@ -50,7 +115,7 @@ class RememberMeTest < ActionController::IntegrationTest
|
||||
assert_redirected_to new_user_session_path
|
||||
end
|
||||
|
||||
test 'do not remember with token expired' do
|
||||
test 'do not remember with expired token' do
|
||||
user = create_user_and_remember
|
||||
swap Devise, :remember_for => 0 do
|
||||
get users_path
|
||||
|
||||
@@ -36,6 +36,18 @@ class SessionTimeoutTest < ActionController::IntegrationTest
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'time out is not triggered on sign out' do
|
||||
user = sign_in_as_user
|
||||
get expire_user_path(user)
|
||||
|
||||
get destroy_user_session_path
|
||||
assert_response :redirect
|
||||
assert_redirected_to root_path
|
||||
|
||||
follow_redirect!
|
||||
assert_contain 'Signed out successfully'
|
||||
end
|
||||
|
||||
test 'user configured timeout limit' do
|
||||
swap Devise, :timeout_in => 8.minutes do
|
||||
user = sign_in_as_user
|
||||
|
||||
@@ -18,8 +18,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
sign_in_as_new_user_with_token(:http_auth => true)
|
||||
|
||||
assert_response :success
|
||||
assert_template 'users/index'
|
||||
assert_contain 'Welcome'
|
||||
assert_match '<email>user@test.com</email>', response.body
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
@@ -78,7 +77,7 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
|
||||
if options[:http_auth]
|
||||
header = "Basic #{ActiveSupport::Base64.encode64("#{VALID_AUTHENTICATION_TOKEN}:X")}"
|
||||
get users_path, {}, "HTTP_AUTHORIZATION" => header
|
||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => header
|
||||
else
|
||||
visit users_path(options[:auth_token_key].to_sym => options[:auth_token])
|
||||
end
|
||||
|
||||
@@ -36,13 +36,13 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => 'Account Confirmation' } } do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => { :subject => 'Account Confirmation' } } } do
|
||||
assert_equal 'Account Confirmation', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :confirmation_instructions => 'User Account Confirmation' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :confirmation_instructions => { :user_subject => 'User Account Confirmation' } } } do
|
||||
assert_equal 'User Account Confirmation', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,13 +39,13 @@ class ResetPasswordInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => 'Reset instructions' } } do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => { :subject => 'Reset instructions' } } } do
|
||||
assert_equal 'Reset instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :reset_password_instructions => 'User Reset Instructions' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :reset_password_instructions => { :user_subject => 'User Reset Instructions' } } } do
|
||||
assert_equal 'User Reset Instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,13 +39,13 @@ class UnlockInstructionsTest < ActionMailer::TestCase
|
||||
end
|
||||
|
||||
test 'setup subject from I18n' do
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => 'Unlock instructions' } } do
|
||||
assert_equal 'Unlock instructions', mail.subject
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => { :subject => 'Yo unlock instructions' } } } do
|
||||
assert_equal 'Yo unlock instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
test 'subject namespaced by model' do
|
||||
store_translations :en, :devise => { :mailer => { :user => { :unlock_instructions => 'User Unlock Instructions' } } } do
|
||||
store_translations :en, :devise => { :mailer => { :unlock_instructions => { :user_subject => 'User Unlock Instructions' } } } do
|
||||
assert_equal 'User Unlock Instructions', mail.subject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
require 'test_helper'
|
||||
|
||||
class FakeRequest < Struct.new(:path_info, :params)
|
||||
end
|
||||
|
||||
class MappingTest < ActiveSupport::TestCase
|
||||
def fake_request(path, params={})
|
||||
FakeRequest.new(path, params)
|
||||
end
|
||||
|
||||
test 'store options' do
|
||||
mapping = Devise.mappings[:user]
|
||||
@@ -8,27 +14,15 @@ class MappingTest < ActiveSupport::TestCase
|
||||
assert_equal User.devise_modules, mapping.modules
|
||||
assert_equal :users, mapping.plural
|
||||
assert_equal :user, mapping.singular
|
||||
assert_equal :users, mapping.path
|
||||
assert_equal "users", mapping.path
|
||||
end
|
||||
|
||||
test 'allows path to be given' do
|
||||
assert_equal :admin_area, Devise.mappings[:admin].path
|
||||
assert_equal "admin_area", Devise.mappings[:admin].path
|
||||
end
|
||||
|
||||
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
|
||||
allowed = Devise.mappings[:user].allowed_controllers
|
||||
assert allowed.include?("devise/sessions")
|
||||
assert allowed.include?("devise/confirmations")
|
||||
assert allowed.include?("devise/passwords")
|
||||
|
||||
allowed = Devise.mappings[:admin].allowed_controllers
|
||||
assert allowed.include?("sessions")
|
||||
assert_not allowed.include?("devise/confirmations")
|
||||
assert_not allowed.include?("devise/unlocks")
|
||||
assert_equal "accounts", Devise.mappings[:manager].path
|
||||
end
|
||||
|
||||
test 'has strategies depending on the model declaration' do
|
||||
@@ -36,15 +30,6 @@ class MappingTest < ActiveSupport::TestCase
|
||||
assert_equal [:database_authenticatable], Devise.mappings[:admin].strategies
|
||||
end
|
||||
|
||||
test 'find mapping by path' do
|
||||
assert_nil Devise::Mapping.find_by_path("/foo/bar")
|
||||
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session")
|
||||
end
|
||||
|
||||
test 'find mapping by customized path' do
|
||||
assert_equal Devise.mappings[:admin], Devise::Mapping.find_by_path("/admin_area/session")
|
||||
end
|
||||
|
||||
test 'find scope for a given object' do
|
||||
assert_equal :user, Devise::Mapping.find_scope!(User)
|
||||
assert_equal :user, Devise::Mapping.find_scope!(:user)
|
||||
@@ -82,26 +67,6 @@ class MappingTest < ActiveSupport::TestCase
|
||||
assert_equal 'unblock', mapping.path_names[:unlock]
|
||||
end
|
||||
|
||||
test 'has an empty path as default path prefix' do
|
||||
mapping = Devise.mappings[:user]
|
||||
assert_equal '/', mapping.path_prefix
|
||||
end
|
||||
|
||||
test 'allow path prefix to be configured' do
|
||||
mapping = Devise.mappings[:manager]
|
||||
assert_equal '/:locale/', mapping.path_prefix
|
||||
end
|
||||
|
||||
test 'retrieve as from the proper position' do
|
||||
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].full_path
|
||||
assert_equal '/:locale/accounts', Devise.mappings[:manager].full_path
|
||||
end
|
||||
|
||||
test 'magic predicates' do
|
||||
mapping = Devise.mappings[:user]
|
||||
assert mapping.authenticatable?
|
||||
@@ -113,8 +78,8 @@ class MappingTest < ActiveSupport::TestCase
|
||||
mapping = Devise.mappings[:admin]
|
||||
assert mapping.authenticatable?
|
||||
assert mapping.recoverable?
|
||||
assert mapping.lockable?
|
||||
assert_not mapping.confirmable?
|
||||
assert_not mapping.lockable?
|
||||
assert_not mapping.rememberable?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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.reload.confirmation_token
|
||||
end
|
||||
|
||||
test 'should not resend email instructions if the user change his email' do
|
||||
user = create_user
|
||||
@@ -202,4 +210,12 @@ class ConfirmableTest < ActiveSupport::TestCase
|
||||
user.save
|
||||
assert_not user.reload.active?
|
||||
end
|
||||
|
||||
test 'should be active without confirmation when confirmation is not required' do
|
||||
user = create_user
|
||||
user.instance_eval { def confirmation_required?; false end }
|
||||
user.confirmation_sent_at = nil
|
||||
user.save
|
||||
assert user.reload.active?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,22 @@ require 'digest/sha1'
|
||||
|
||||
class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
|
||||
def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encryptor=::Devise::Encryptors::Sha1)
|
||||
def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encryptor=User.encryptor_class)
|
||||
encryptor.digest('123456', stretches, user.password_salt, pepper)
|
||||
end
|
||||
|
||||
def swap_with_encryptor(klass, encryptor, options={})
|
||||
klass.instance_variable_set(:@encryptor_class, nil)
|
||||
|
||||
swap klass, options.merge(:encryptor => encryptor) do
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
klass.instance_variable_set(:@encryptor_class, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test 'should respond to password and password confirmation' do
|
||||
user = new_user
|
||||
assert user.respond_to?(:password)
|
||||
@@ -28,8 +40,10 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'should generate a base64 hash using SecureRandom for password salt' do
|
||||
ActiveSupport::SecureRandom.expects(:base64).with(15).returns('friendly_token')
|
||||
assert_equal 'friendly_token', new_user.password_salt
|
||||
swap_with_encryptor User, :sha1 do
|
||||
ActiveSupport::SecureRandom.expects(:base64).with(15).returns('friendly_token')
|
||||
assert_equal 'friendly_token', new_user.password_salt
|
||||
end
|
||||
end
|
||||
|
||||
test 'should not generate salt if password is blank' do
|
||||
@@ -71,24 +85,10 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test 'should fallback to devise stretches default configuration' do
|
||||
swap Devise, :stretches => 1 do
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user, nil, 1), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, nil, 2), user.encrypted_password
|
||||
end
|
||||
end
|
||||
|
||||
test 'should respect encryptor configuration' do
|
||||
User.instance_variable_set(:@encryptor_class, nil)
|
||||
|
||||
swap Devise, :encryptor => :sha512 do
|
||||
begin
|
||||
user = create_user
|
||||
assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512)
|
||||
ensure
|
||||
User.instance_variable_set(:@encryptor_class, nil)
|
||||
end
|
||||
swap_with_encryptor User, :sha512 do
|
||||
user = create_user
|
||||
assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
user.unlock_access!
|
||||
assert_nil user.reload.locked_at
|
||||
assert_nil user.reload.unlock_token
|
||||
assert 0, user.reload.failed_attempts
|
||||
assert_equal 0, user.reload.failed_attempts
|
||||
end
|
||||
|
||||
test 'should not unlock an unlocked user' do
|
||||
|
||||
@@ -18,19 +18,19 @@ class RememberableTest < ActiveSupport::TestCase
|
||||
test 'forget_me should clear remember token and save the record without validating' do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
assert user.remember_token?
|
||||
assert_not user.remember_token.nil?
|
||||
user.expects(:valid?).never
|
||||
user.forget_me!
|
||||
assert_not user.remember_token?
|
||||
assert user.remember_token.nil?
|
||||
assert_not user.changed?
|
||||
end
|
||||
|
||||
test 'forget_me should clear remember_created_at' do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
assert user.remember_created_at?
|
||||
assert_not user.remember_created_at.nil?
|
||||
user.forget_me!
|
||||
assert_not user.remember_created_at?
|
||||
assert user.remember_created_at.nil?
|
||||
end
|
||||
|
||||
test 'forget should do nothing if no remember token exists' do
|
||||
@@ -107,4 +107,112 @@ class RememberableTest < ActiveSupport::TestCase
|
||||
assert_not user.remember_expired?
|
||||
end
|
||||
end
|
||||
|
||||
test 'if extend_remember_period is false, remember_me! should generate a new timestamp if expired' do
|
||||
swap Devise, :remember_for => 5.minutes do
|
||||
user = create_user
|
||||
user.remember_me!(false)
|
||||
assert user.remember_created_at
|
||||
|
||||
user.remember_created_at = old = 10.minutes.ago
|
||||
user.save
|
||||
|
||||
user.remember_me!(false)
|
||||
assert_not_equal old.to_i, user.remember_created_at.to_i
|
||||
end
|
||||
end
|
||||
|
||||
test 'if extend_remember_period is false, remember_me! should not generate a new timestamp' do
|
||||
swap Devise, :remember_for => 1.year do
|
||||
user = create_user
|
||||
user.remember_me!(false)
|
||||
assert user.remember_created_at
|
||||
|
||||
user.remember_created_at = old = 10.minutes.ago.utc
|
||||
user.save
|
||||
|
||||
user.remember_me!(false)
|
||||
assert_equal old.to_i, user.remember_created_at.to_i
|
||||
end
|
||||
end
|
||||
|
||||
test 'if extend_remember_period is true, remember_me! should always generate a new timestamp' do
|
||||
swap Devise, :remember_for => 1.year do
|
||||
user = create_user
|
||||
user.remember_me!(true)
|
||||
assert user.remember_created_at
|
||||
|
||||
user.remember_created_at = old = 10.minutes.ago
|
||||
user.save
|
||||
|
||||
user.remember_me!(true)
|
||||
assert_not_equal old, user.remember_created_at
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is true, remember_me! should create a new token if no token exists' do
|
||||
swap Devise, :remember_across_browsers => true, :remember_for => 1.year do
|
||||
user = create_user
|
||||
assert_equal nil, user.remember_token
|
||||
user.remember_me!
|
||||
assert_not_equal nil, user.remember_token
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is true, remember_me! should create a new token if a token exists but has expired' do
|
||||
swap Devise, :remember_across_browsers => true, :remember_for => 1.day do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
user.remember_created_at = 2.days.ago
|
||||
user.save
|
||||
token = user.remember_token
|
||||
user.remember_me!
|
||||
assert_not_equal token, user.remember_token
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is true, remember_me! should not create a new token if a token exists and has not expired' do
|
||||
swap Devise, :remember_across_browsers => true, :remember_for => 2.days do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
user.remember_created_at = 1.day.ago
|
||||
user.save
|
||||
token = user.remember_token
|
||||
user.remember_me!
|
||||
assert_equal token, user.remember_token
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is false, remember_me! should create a new token if no token exists' do
|
||||
swap Devise, :remember_across_browsers => false do
|
||||
user = create_user
|
||||
assert_equal nil, user.remember_token
|
||||
user.remember_me!
|
||||
assert_not_equal nil, user.remember_token
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists but has expired' do
|
||||
swap Devise, :remember_across_browsers => false, :remember_for => 1.day do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
user.remember_created_at = 2.days.ago
|
||||
user.save
|
||||
token = user.remember_token
|
||||
user.remember_me!
|
||||
assert_not_equal token, user.remember_token
|
||||
end
|
||||
end
|
||||
|
||||
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists and has not expired' do
|
||||
swap Devise, :remember_across_browsers => false, :remember_for => 2.days do
|
||||
user = create_user
|
||||
user.remember_me!
|
||||
user.remember_created_at = 1.day.ago
|
||||
user.save
|
||||
token = user.remember_token
|
||||
user.remember_me!
|
||||
assert_not_equal token, user.remember_token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
class ValidatableTest < ActiveSupport::TestCase
|
||||
extend Devise::TestSilencer if [:mongoid, :data_mapper].include?(DEVISE_ORM)
|
||||
|
||||
test 'should require email to be set' do
|
||||
user = new_user(:email => nil)
|
||||
assert user.invalid?
|
||||
@@ -15,11 +13,11 @@ class ValidatableTest < ActiveSupport::TestCase
|
||||
|
||||
user = new_user(:email => '')
|
||||
assert user.invalid?
|
||||
assert_not_equal 'has already been taken', user.errors[:email].join
|
||||
assert_no_match(/taken/, user.errors[:email].join)
|
||||
|
||||
user.email = existing_user.email
|
||||
assert user.invalid?
|
||||
assert_equal 'has already been taken', user.errors[:email].join
|
||||
assert_match(/taken/, user.errors[:email].join)
|
||||
end
|
||||
|
||||
test 'should require correct email format, allowing blank' do
|
||||
|
||||
@@ -26,16 +26,16 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'can cherry pick modules' do
|
||||
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable
|
||||
end
|
||||
|
||||
test 'chosen modules are inheritable' do
|
||||
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable
|
||||
end
|
||||
|
||||
test 'order of module inclusion' do
|
||||
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :timeoutable]
|
||||
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable]
|
||||
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :lockable, :timeoutable]
|
||||
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable]
|
||||
|
||||
assert_include_modules Admin, *incorrect_module_order
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
DataMapper.auto_migrate!
|
||||
@@ -7,4 +7,4 @@ require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
|
||||
Rails::Application.load_tasks
|
||||
Rails.application.load_tasks
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Admin < ActiveRecord::Base
|
||||
devise :database_authenticatable, :registerable, :timeoutable, :recoverable
|
||||
devise :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :unlock_strategy => :time
|
||||
end
|
||||
|
||||
2
test/rails_app/app/active_record/shim.rb
Normal file
2
test/rails_app/app/active_record/shim.rb
Normal file
@@ -0,0 +1,2 @@
|
||||
module Shim
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user