mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-09 23:58:06 -05:00
Compare commits
314 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e0d517cdb | ||
|
|
17cd4b0c85 | ||
|
|
1d85f389a0 | ||
|
|
e358f8256b | ||
|
|
12ba8603a5 | ||
|
|
2b123f3017 | ||
|
|
5396b04202 | ||
|
|
acac9b43a7 | ||
|
|
6e020af959 | ||
|
|
c3983d7807 | ||
|
|
4803d5d6b1 | ||
|
|
d8dedec1f8 | ||
|
|
b328655f0f | ||
|
|
0dd921c460 | ||
|
|
c2feed6b3e | ||
|
|
dea0f68291 | ||
|
|
5fc2c2e6f5 | ||
|
|
3bba7edc4f | ||
|
|
36906a03f3 | ||
|
|
d6af3d7dc6 | ||
|
|
767331657b | ||
|
|
55860675c2 | ||
|
|
da3af3f341 | ||
|
|
0f46ed3a33 | ||
|
|
8d33e8f313 | ||
|
|
fb1e9bc8a7 | ||
|
|
4310ad798c | ||
|
|
8def06e1a6 | ||
|
|
3b0aaaaae8 | ||
|
|
cb83c66139 | ||
|
|
2104397bee | ||
|
|
374948cf4b | ||
|
|
7c51ec0742 | ||
|
|
ed05225dd5 | ||
|
|
c32cb3da6c | ||
|
|
70c32e48fc | ||
|
|
522219e5db | ||
|
|
a843b74c86 | ||
|
|
56834284bd | ||
|
|
5b762ff85a | ||
|
|
73822fe109 | ||
|
|
85a4aa2afa | ||
|
|
c49fe8c6d7 | ||
|
|
a59e20e3bb | ||
|
|
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 | ||
|
|
ca6248cfd3 | ||
|
|
b9c0676a01 | ||
|
|
731f156f50 | ||
|
|
b2a50db1df | ||
|
|
6bd0c7fc2b | ||
|
|
4e674ab9a0 | ||
|
|
cbfeb59fb3 | ||
|
|
8db559148c | ||
|
|
7403c9f80e | ||
|
|
f3d654a733 | ||
|
|
bafc859f75 | ||
|
|
bf63824aae | ||
|
|
32d37cebed | ||
|
|
d2ebaa43ec | ||
|
|
045af3a614 | ||
|
|
a96fdcf0bd | ||
|
|
fd934f1434 | ||
|
|
b2fe7e49fd | ||
|
|
22392f23f2 | ||
|
|
3ce98d4163 | ||
|
|
c07b5ae858 | ||
|
|
dbe116c255 | ||
|
|
9d1a52978c | ||
|
|
0d3c6b9d99 | ||
|
|
71f74a10f7 | ||
|
|
0bd75469ba | ||
|
|
1591294b7a | ||
|
|
f9cbd3c457 | ||
|
|
66ca9f5ce0 | ||
|
|
d3c31ef16d | ||
|
|
b974b7bc78 | ||
|
|
23e608e27b | ||
|
|
0f7b311171 | ||
|
|
27c4280eca | ||
|
|
1ba525a0e9 | ||
|
|
d8b6ba9022 | ||
|
|
f5d01c217d | ||
|
|
2b5a068246 | ||
|
|
13b8ddf54c | ||
|
|
16666b7587 | ||
|
|
dac7887d7c | ||
|
|
42d06a241b | ||
|
|
3d1a04fd83 | ||
|
|
1d65a76cf3 | ||
|
|
015c74e734 | ||
|
|
6cc32db2dd | ||
|
|
597a930c74 | ||
|
|
d7f614b726 | ||
|
|
e04c5ba977 | ||
|
|
4fc41dd68a | ||
|
|
22e1fa0cb9 | ||
|
|
a6a018253e | ||
|
|
81926c2cd2 | ||
|
|
7d14f0bbb9 | ||
|
|
e038d82410 | ||
|
|
65b8908960 | ||
|
|
1c5d4771ff | ||
|
|
604b7ef61c | ||
|
|
0d704c02ca | ||
|
|
1c39590e20 | ||
|
|
6d31e368bf | ||
|
|
63deb0e80a | ||
|
|
2a082f3e4c | ||
|
|
97b7ba8659 | ||
|
|
bc00a13a3a | ||
|
|
033db1ca7c | ||
|
|
066c6e8771 | ||
|
|
96c8238b02 | ||
|
|
4b7a9204b8 | ||
|
|
ea71be8d2a | ||
|
|
6bcf18b04f | ||
|
|
bb504e08aa | ||
|
|
afe6a8c8c8 | ||
|
|
a53cc74fd9 | ||
|
|
fd035b841b | ||
|
|
e127463ac8 | ||
|
|
bd4b29c0fd | ||
|
|
6f41284714 | ||
|
|
a5ba2ac1a8 | ||
|
|
386e7be823 | ||
|
|
ca4e09390e | ||
|
|
5c19605d6f | ||
|
|
e136573905 | ||
|
|
ae729aedc3 | ||
|
|
12b64c691f | ||
|
|
4d3a3ceb43 | ||
|
|
c76df8239f | ||
|
|
28a6be456a | ||
|
|
76e45ecb12 | ||
|
|
8fbbe34bdd | ||
|
|
3a84fd4f3f | ||
|
|
37bb6948a2 | ||
|
|
f129b9ffd7 | ||
|
|
6ce33b7b57 | ||
|
|
185541b9e4 | ||
|
|
e81d428d53 | ||
|
|
de92be39f2 | ||
|
|
3f85fa88c3 | ||
|
|
2ebbc30540 | ||
|
|
b8091928a0 | ||
|
|
cbd35a846a | ||
|
|
90e8253205 | ||
|
|
3f0bae1968 | ||
|
|
59b26d8427 | ||
|
|
cbc3747039 | ||
|
|
ed3a460bad | ||
|
|
ac742e3271 | ||
|
|
cd17099401 | ||
|
|
829c85631b | ||
|
|
1a740774e3 | ||
|
|
bb9f594cc8 | ||
|
|
d64e146ec9 | ||
|
|
0a0d7ba577 | ||
|
|
288b92d2be |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
*~
|
||||
coverage/*
|
||||
*.sqlite3
|
||||
.bundle
|
||||
rdoc/*
|
||||
pkg
|
||||
log
|
||||
|
||||
172
CHANGELOG.rdoc
172
CHANGELOG.rdoc
@@ -1,19 +1,167 @@
|
||||
== 1.1.pre
|
||||
== 1.1.9
|
||||
|
||||
* bugfix
|
||||
* double check if warden has not halted
|
||||
|
||||
== 1.1.8
|
||||
|
||||
* bugfix
|
||||
* Ensure you can't inject Mongoid queries using token authenticatable
|
||||
|
||||
== 1.1.7
|
||||
|
||||
* bugfix
|
||||
* Fix a backward incompatible change with versions prior to Rails 3.0.4
|
||||
|
||||
== 1.1.6
|
||||
|
||||
* bugfix
|
||||
* Use a more secure e-mail regexp
|
||||
* Implement Rails 3.0.4 handle unverified request
|
||||
* Use secure_compare to compare passwords
|
||||
|
||||
== 1.1.5
|
||||
|
||||
* bugfix
|
||||
* Ensure to convert keys on indifferent hash
|
||||
|
||||
* defaults
|
||||
* Set config.http_authenticatable to false to avoid confusion
|
||||
|
||||
== 1.1.4
|
||||
|
||||
* bugfix
|
||||
* Avoid session fixation attacks
|
||||
|
||||
== 1.1.3
|
||||
|
||||
* bugfix
|
||||
* Add reply-to to e-mail headers by default
|
||||
* Updated the views generator to respect the rails :template_engine option (by github.com/fredwu)
|
||||
* Check the type of HTTP Authentication before using Basic headers
|
||||
* Avoid invalid_salt errors by checking salt presence (by github.com/thibaudgg)
|
||||
* Forget user deletes the right cookie before logout, not remembering the user anymore (by github.com/emtrane)
|
||||
* Fix for failed first-ever logins on PostgreSQL where column default is nil (by github.com/bensie)
|
||||
* :default options is now honored in migrations
|
||||
|
||||
== 1.1.2
|
||||
|
||||
* bugfix
|
||||
* Compatibility with latest Rails routes schema
|
||||
|
||||
== 1.1.1
|
||||
|
||||
* bugfix
|
||||
* Fix a small bug where generated locale file was empty on devise:install
|
||||
|
||||
== 1.1.0
|
||||
|
||||
* enhancements
|
||||
* Rails 3 compatibility.
|
||||
* All controllers and views are namespaced, for example: Devise::SessionsController and "devise/sessions".
|
||||
* You can specify the controller in routes and have specific controllers for each role.
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
|
||||
* deprecations
|
||||
* Rails 3 compatible only
|
||||
* Removed support for MongoMapper
|
||||
* Scoped views are no longer "sessions/users/new". Now use "users/sessions/new"
|
||||
* Devise.orm is deprecated, just require "devise/orm/YOUR_ORM" instead
|
||||
* Devise.default_url_options is deprecated, just modify ApplicationController.default_url_options
|
||||
* All messages under devise.sessions, except :signed_in and :signed_out, should be moved to devise.failure
|
||||
* :as and :scope in routes is deprecated. Use :path and :singular instead
|
||||
|
||||
== 1.0.8
|
||||
|
||||
* enhancements
|
||||
* Support for latest MongoMapper
|
||||
* Added anybody_signed_in? helper (by github.com/SSDany)
|
||||
|
||||
* bug fix
|
||||
* confirmation_required? is properly honored on active? calls. (by github.com/paulrosania)
|
||||
|
||||
== 1.0.7
|
||||
|
||||
* bug fix
|
||||
* Ensure password confirmation is always required
|
||||
|
||||
* deprecations
|
||||
* authenticatable was deprecated and renamed to database_authenticatable
|
||||
* confirmable is not included by default on generation
|
||||
|
||||
== 1.0.6
|
||||
|
||||
* bug fix
|
||||
* Do not allow unlockable strategies based on time to access a controller.
|
||||
* Do not send unlockable email several times.
|
||||
* Allow controller to upstram custom! failures to Warden.
|
||||
|
||||
== 1.0.5
|
||||
|
||||
* bug fix
|
||||
* Use prepend_before_filter in require_no_authentication.
|
||||
* require_no_authentication on unlockable.
|
||||
* Fix a bug when giving an association proxy to devise.
|
||||
* Do not use lock! on lockable since it's part of ActiveRecord API.
|
||||
|
||||
== 1.0.4
|
||||
|
||||
* bug fix
|
||||
* Fixed a bug when deleting an account with rememberable
|
||||
* Fixed a bug with custom controllers
|
||||
|
||||
== 1.0.3
|
||||
|
||||
|
||||
35
Gemfile
35
Gemfile
@@ -1,18 +1,27 @@
|
||||
source "http://gemcutter.org"
|
||||
source "http://rubygems.org"
|
||||
|
||||
gem "rails", "3.0.0.beta"
|
||||
gem "warden", "0.9.4"
|
||||
gem "sqlite3-ruby", :require => "sqlite3"
|
||||
gem "webrat", "0.7"
|
||||
gem "mocha", :require => false
|
||||
gem "bcrypt-ruby", :require => "bcrypt"
|
||||
gemspec
|
||||
|
||||
if RUBY_VERSION < '1.9'
|
||||
gem "ruby-debug", ">= 0.10.3"
|
||||
gem "rails", "~> 3.0.4"
|
||||
|
||||
group :test do
|
||||
gem "webrat", "0.7.2", :require => false
|
||||
gem "mocha", :require => false
|
||||
end
|
||||
|
||||
group :mongo_mapper do
|
||||
gem "mongo", "0.18.3"
|
||||
gem "mongo_ext", "0.18.3", :require => false
|
||||
gem "mongo_mapper", :git => "git://github.com/merbjedi/mongomapper.git", :branch => "rails3"
|
||||
platforms :jruby do
|
||||
gem 'activerecord-jdbcsqlite3-adapter'
|
||||
end
|
||||
|
||||
platforms :ruby do
|
||||
group :test do
|
||||
gem "sqlite3-ruby"
|
||||
gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9'
|
||||
end
|
||||
|
||||
group :mongoid do
|
||||
gem "mongo", "1.1.2"
|
||||
gem "mongoid", "2.0.0.beta.20"
|
||||
gem "bson_ext", "1.1.2"
|
||||
end
|
||||
end
|
||||
|
||||
115
Gemfile.lock
Normal file
115
Gemfile.lock
Normal file
@@ -0,0 +1,115 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
devise (1.1.8)
|
||||
bcrypt-ruby (~> 2.1.2)
|
||||
warden (~> 1.0.2)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
abstract (1.0.0)
|
||||
actionmailer (3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
mail (~> 2.2.15)
|
||||
actionpack (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
builder (~> 2.1.2)
|
||||
erubis (~> 2.6.6)
|
||||
i18n (~> 0.4)
|
||||
rack (~> 1.2.1)
|
||||
rack-mount (~> 0.6.13)
|
||||
rack-test (~> 0.5.7)
|
||||
tzinfo (~> 0.3.23)
|
||||
activemodel (3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
builder (~> 2.1.2)
|
||||
i18n (~> 0.4)
|
||||
activerecord (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
arel (~> 2.0.2)
|
||||
tzinfo (~> 0.3.23)
|
||||
activeresource (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
activesupport (3.0.4)
|
||||
arel (2.0.8)
|
||||
bcrypt-ruby (2.1.4)
|
||||
bson (1.1.2)
|
||||
bson_ext (1.1.2)
|
||||
builder (2.1.2)
|
||||
columnize (0.3.2)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
i18n (0.5.0)
|
||||
linecache (0.43)
|
||||
mail (2.2.15)
|
||||
activesupport (>= 2.3.6)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.16)
|
||||
mocha (0.9.9)
|
||||
rake
|
||||
mongo (1.1.2)
|
||||
bson (>= 1.1.1)
|
||||
mongoid (2.0.0.beta.20)
|
||||
activemodel (~> 3.0)
|
||||
mongo (~> 1.1)
|
||||
tzinfo (~> 0.3.22)
|
||||
will_paginate (~> 3.0.pre)
|
||||
nokogiri (1.4.4)
|
||||
polyglot (0.3.1)
|
||||
rack (1.2.1)
|
||||
rack-mount (0.6.13)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (0.5.7)
|
||||
rack (>= 1.0)
|
||||
rails (3.0.4)
|
||||
actionmailer (= 3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
activerecord (= 3.0.4)
|
||||
activeresource (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.0.4)
|
||||
railties (3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
rake (>= 0.8.7)
|
||||
thor (~> 0.14.4)
|
||||
rake (0.8.7)
|
||||
ruby-debug (0.10.4)
|
||||
columnize (>= 0.1)
|
||||
ruby-debug-base (~> 0.10.4.0)
|
||||
ruby-debug-base (0.10.4)
|
||||
linecache (>= 0.3)
|
||||
sqlite3-ruby (1.3.2)
|
||||
thor (0.14.6)
|
||||
treetop (1.4.9)
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.24)
|
||||
warden (1.0.3)
|
||||
rack (>= 1.0.0)
|
||||
webrat (0.7.2)
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
will_paginate (3.0.pre2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activerecord-jdbcsqlite3-adapter
|
||||
bson_ext (= 1.1.2)
|
||||
devise!
|
||||
mocha
|
||||
mongo (= 1.1.2)
|
||||
mongoid (= 2.0.0.beta.20)
|
||||
rails (~> 3.0.4)
|
||||
ruby-debug (>= 0.10.3)
|
||||
sqlite3-ruby
|
||||
webrat (= 0.7.2)
|
||||
165
README.rdoc
165
README.rdoc
@@ -7,75 +7,85 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
|
||||
* Allows you to have multiple roles (or models/scopes) signed in at the same time;
|
||||
* Is based on a modularity concept: use just what you really need.
|
||||
|
||||
Right now it's composed of 12 modules:
|
||||
Right now it's composed of 11 modules:
|
||||
|
||||
* Authenticatable: encrypts a password and validates the authenticity of a user while signing in.
|
||||
* Token Authenticatable: validates the authenticity of a user while signing in using an authentication token (also known as "single access token").
|
||||
* HttpAuthenticatable: sign in users using basic HTTP authentication.
|
||||
* Database Authenticatable: encrypts and stores a password in the database to validate the authenticity of an user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
|
||||
* Token Authenticatable: signs in an user based on an authentication token (also known as "single access token"). The token can be given both through query string or HTTP Basic Authentication.
|
||||
* Confirmable: sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
|
||||
* Recoverable: resets the user password and sends reset instructions.
|
||||
* Registerable: handles signing up users through a registration process.
|
||||
* Registerable: handles signing up users through a registration process, also allowing them to edit and destroy their account.
|
||||
* Rememberable: manages generating and clearing a token for remembering the user from a saved cookie.
|
||||
* Trackable: tracks sign in count, timestamps and IP address.
|
||||
* Timeoutable: expires sessions that have no activity in a specified period of time.
|
||||
* Validatable: provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
|
||||
* Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
|
||||
* Activatable: use this module if you need to activate accounts by means other than confirmation.
|
||||
|
||||
== Examples
|
||||
|
||||
* Example application using Devise at http://github.com/plataformatec/devise_example
|
||||
* Example Rails 2.3 web app combining subdomains with Devise at http://github.com/fortuity/subdomain-authentication
|
||||
|
||||
== Dependencies
|
||||
|
||||
Devise is based on Warden (http://github.com/hassox/warden), a Rack Authentication Framework. You need to install Warden as a gem. Please ensure you have it installed in order to use Devise (see installation below).
|
||||
|
||||
== Installation
|
||||
|
||||
Devise master branch now supports Rails 3 and is NOT backward compatible. You can install it as:
|
||||
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.pre
|
||||
gem install devise --version=1.1.7
|
||||
|
||||
After installing the Warden and Devise gems, you need to configure the gems inside your gemfile:
|
||||
If you want to use Rails master (from git repository) you need to use Devise from git repository and vice-versa.
|
||||
|
||||
gem 'warden'
|
||||
gem 'devise'
|
||||
After you install Devise and add it to your Gemfile, you need to run the generator:
|
||||
|
||||
And run the generator:
|
||||
rails generate devise:install
|
||||
|
||||
rails generate devise_install
|
||||
The generator will install an initializer which describes ALL Devise's configuration options and you MUST take a look at it. When you are done, you are ready to add Devise to any of your models using the generator:
|
||||
|
||||
And you're ready to go. The generator will install an initializer which describes ALL Devise's configuration options, so be sure to take a look at it and at the documentation as well:
|
||||
rails generate devise MODEL
|
||||
|
||||
http://rdoc.info/projects/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.1
|
||||
gem install devise --version=1.0.10
|
||||
|
||||
Or checkout from the v1.0 branch:
|
||||
And please check the README at the v1.0 branch since this one is based on Rails 3:
|
||||
|
||||
http://github.com/plataformatec/devise/tree/v1.0
|
||||
|
||||
== Ecosystem
|
||||
|
||||
Devise ecosystem is growing solid day after day. If you just need a walkthrough about setting up Devise, this README will work great. But if you need more documentation and resources, please check both the wiki and rdoc:
|
||||
|
||||
* http://rdoc.info/projects/plataformatec/devise
|
||||
* http://wiki.github.com/plataformatec/devise
|
||||
|
||||
Both links above are for Devise with Rails 3. If you need to use Devise with Rails 2.3, you can always run `gem server` from the command line after you install the gem to access the old documentation.
|
||||
|
||||
Another great way to learn Devise are Ryan Bates' screencasts:
|
||||
|
||||
* http://railscasts.com/episodes/209-introducing-devise
|
||||
* http://railscasts.com/episodes/210-customizing-devise
|
||||
|
||||
And a few example applications:
|
||||
|
||||
* Rails 2.3 app using Devise at http://github.com/plataformatec/devise_example
|
||||
* Rails 2.3 app using Devise with subdomains at http://github.com/fortuity/subdomain-authentication
|
||||
* Rails 3.0 app with Mongoid at http://github.com/fortuity/rails3-mongoid-devise
|
||||
|
||||
Finally, Devise also has several extensions built by the community. Don't forget to check them at the end of this README. If you want to write an extension on your own, you should also check Warden (http://github.com/hassox/warden), a Rack Authentication Framework which Devise depends on.
|
||||
|
||||
== Basic Usage
|
||||
|
||||
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration. You MUST also check out the *Generators* section below to help you start.
|
||||
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration.
|
||||
|
||||
Devise must be set up within the model (or models) you want to use. Devise routes must be created inside your config/routes.rb file.
|
||||
|
||||
We're assuming here you want a User model with some Devise modules, as outlined below:
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
end
|
||||
|
||||
After you choose which modules to use, you need to set up your migrations. Luckily, Devise has some helpers to save you from this boring work:
|
||||
|
||||
create_table :users do |t|
|
||||
t.authenticatable
|
||||
t.database_authenticatable
|
||||
t.confirmable
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
@@ -91,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,16 +143,17 @@ Devise allows you to set up as many roles as you want. For example, you may have
|
||||
|
||||
# Create a migration with the required fields
|
||||
create_table :admins do |t|
|
||||
t.authenticatable
|
||||
t.database_authenticatable
|
||||
t.lockable
|
||||
t.trackable
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
# Inside your Admin model
|
||||
devise :authenticatable, :trackable, :timeoutable, :lockable
|
||||
devise :database_authenticatable, :trackable, :timeoutable, :lockable
|
||||
|
||||
# Inside your routes
|
||||
devise_for :admin
|
||||
devise_for :admins
|
||||
|
||||
# Inside your protected controller
|
||||
before_filter :authenticate_admin!
|
||||
@@ -152,52 +163,40 @@ Devise allows you to set up as many roles as you want. For example, you may have
|
||||
current_admin
|
||||
admin_session
|
||||
|
||||
== Generators
|
||||
|
||||
Devise has generators to help you get started:
|
||||
|
||||
rails generate devise_install
|
||||
|
||||
This will generate an initializer, with a description of all configuration values.
|
||||
|
||||
You can also generate models:
|
||||
|
||||
rails generate devise Model
|
||||
|
||||
This will create a model named "Model" configured with default Devise modules and attr_accessible set for default fields. The generator will also create the migration and configure your routes for Devise.
|
||||
|
||||
== Model configuration
|
||||
|
||||
The devise method in your models also accepts some options to configure its modules. For example, you can choose which encryptor to use in authenticatable:
|
||||
The devise method in your models also accepts some options to configure its modules. For example, you can choose which encryptor to use in database_authenticatable:
|
||||
|
||||
devise :authenticatable, :confirmable, :recoverable, :encryptor => :bcrypt
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :encryptor => :bcrypt
|
||||
|
||||
Besides :encryptor, you can define :pepper, :stretches, :confirm_within, :remember_for, :timeout_in, :unlock_in and other values. For details, see the initializer file that was created when you invoked the devise_install generator described above.
|
||||
Besides :encryptor, you can define :pepper, :stretches, :confirm_within, :remember_for, :timeout_in, :unlock_in and other values. For details, see the initializer file that was created when you invoked the "devise:install" generator described above.
|
||||
|
||||
== Configuring controllers and views
|
||||
== Configuring views
|
||||
|
||||
We built Devise to help you quickly develop an application that uses authentication. We don't want to be in your way when you need to customize it.
|
||||
We built Devise to help you quickly develop an application that uses authentication. However, we don't want to be in your way when you need to customize it.
|
||||
|
||||
Since Devise is an engine, all its default views are packaged inside the gem. The default views will get you started but you may want to customize them. Devise has a generator to copy the default views to your application. After they've been copied to your application, you can make changes as required:
|
||||
Since Devise is an engine, all its views are packaged inside the gem. These views will help you get started, but after sometime you may want to change them. If this is the case, you just need to invoke the following generator, and it will copy all views to your application:
|
||||
|
||||
rails generate devise_views
|
||||
rails generate devise:views
|
||||
|
||||
If you have more than one role in your application (such as "user" and "admin"), you will notice that Devise uses the same views for all roles. You may need different views for each role. Devise offers an easy way to customize views for each role. Just set config.scoped_views to "true" inside "config/initializers/devise.rb".
|
||||
However, if you have more than one role in your application (such as "User" and "Admin"), you will notice that Devise uses the same views for all roles. Fortunately, Devise offers an easy way to customize views. All you need to do is set "config.scoped_views = true" inside "config/initializers/devise.rb".
|
||||
|
||||
After doing so you will be able to have views based on the scope like "users/sessions/new" and "admins/sessions/new". If no view is found within the scope, Devise will use the default view at "devise/sessions/new".
|
||||
After doing so, you will be able to have views based on the role like "users/sessions/new" and "admins/sessions/new". If no view is found within the scope, Devise will use the default view at "devise/sessions/new".
|
||||
|
||||
Finally, if the customization at the views level is not enough, you can customize each controller by following these steps:
|
||||
== Configuring controllers
|
||||
|
||||
1) Create your custom controller, for example a Admins::SessionsController:
|
||||
If the customization at the views level is not enough, you can customize each controller by following these steps:
|
||||
|
||||
1) Create your custom controller, for example a Admins::SessionsController:
|
||||
|
||||
class Admins::SessionsController < Devise::SessionsController
|
||||
end
|
||||
|
||||
2) Tell the router to use this controller:
|
||||
2) Tell the router to use this controller:
|
||||
|
||||
devise_for :admins, :controllers => { :sessions = "admin/sessions" }
|
||||
devise_for :admins, :controllers => { :sessions => "admin/sessions" }
|
||||
|
||||
3) And finally, since we changed the controller, it won't use the "devise/sessions" views, so remember to copy "devise/sessions" to "admin/sessions".
|
||||
3) And since we changed the controller, it won't use the "devise/sessions" views, so remember to copy "devise/sessions" to "admin/sessions".
|
||||
|
||||
Remember that Devise uses flash messages to let users know if sign in was successful or failed. Devise expects your application to call "flash[:notice]" and "flash[:alert]" as appropriate.
|
||||
|
||||
@@ -256,12 +255,36 @@ Devise implements encryption strategies for Clearance, Authlogic and Restful-Aut
|
||||
|
||||
== Other ORMs
|
||||
|
||||
Devise supports ActiveRecord (by default) and MongoMapper. 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.
|
||||
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)
|
||||
@@ -269,13 +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:
|
||||
|
||||
== Related Applications
|
||||
|
||||
* 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/plataformatec/devise/contributors
|
||||
|
||||
== Bugs and Feedback
|
||||
|
||||
@@ -287,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
|
||||
|
||||
7
Rakefile
7
Rakefile
@@ -37,7 +37,7 @@ begin
|
||||
require 'jeweler'
|
||||
Jeweler::Tasks.new do |s|
|
||||
s.name = "devise"
|
||||
s.version = Devise::VERSION
|
||||
s.version = Devise::VERSION.dup
|
||||
s.summary = "Flexible authentication solution for Rails with Warden"
|
||||
s.email = "contact@plataformatec.com.br"
|
||||
s.homepage = "http://github.com/plataformatec/devise"
|
||||
@@ -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.9.4")
|
||||
s.add_dependency("warden", "~> 1.0.2")
|
||||
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
|
||||
|
||||
5
TODO
5
TODO
@@ -1,2 +1,3 @@
|
||||
* Make test run with DataMapper
|
||||
* Extract Activatable tests from Confirmable
|
||||
* Move integration tests to Capybara
|
||||
* Better ORM integration
|
||||
* Extract activatable models tests from confirmable
|
||||
|
||||
@@ -21,7 +21,7 @@ class Devise::ConfirmationsController < ApplicationController
|
||||
|
||||
# GET /resource/confirmation?confirmation_token=abcdef
|
||||
def show
|
||||
self.resource = resource_class.confirm!(:confirmation_token => params[:confirmation_token])
|
||||
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :confirmed
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
class Devise::PasswordsController < ApplicationController
|
||||
prepend_before_filter :require_no_authentication
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
before_filter :require_no_authentication
|
||||
|
||||
# GET /resource/password/new
|
||||
def new
|
||||
build_resource
|
||||
@@ -30,7 +29,7 @@ class Devise::PasswordsController < ApplicationController
|
||||
|
||||
# PUT /resource/password
|
||||
def update
|
||||
self.resource = resource_class.reset_password!(params[resource_name])
|
||||
self.resource = resource_class.reset_password_by_token(params[resource_name])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :updated
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
class Devise::RegistrationsController < ApplicationController
|
||||
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
|
||||
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
before_filter :require_no_authentication, :only => [ :new, :create ]
|
||||
before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
|
||||
|
||||
# GET /resource/sign_up
|
||||
def new
|
||||
build_resource
|
||||
build_resource({})
|
||||
render_with_scope :new
|
||||
end
|
||||
|
||||
# POST /resource/sign_up
|
||||
# POST /resource
|
||||
def create
|
||||
build_resource
|
||||
|
||||
if resource.save
|
||||
flash[:"#{resource_name}_signed_up"] = true
|
||||
set_flash_message :notice, :signed_up
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
render_with_scope :new
|
||||
end
|
||||
end
|
||||
@@ -32,8 +31,9 @@ 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
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,30 +1,18 @@
|
||||
class Devise::SessionsController < ApplicationController
|
||||
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
before_filter :require_no_authentication, :only => [ :new, :create ]
|
||||
|
||||
# GET /resource/sign_in
|
||||
def new
|
||||
unless resource_just_signed_up?
|
||||
Devise::FLASH_MESSAGES.each do |message|
|
||||
set_now_flash_message :alert, message if params.try(:[], message) == "true"
|
||||
end
|
||||
end
|
||||
|
||||
build_resource
|
||||
clean_up_passwords(build_resource)
|
||||
render_with_scope :new
|
||||
end
|
||||
|
||||
# POST /resource/sign_in
|
||||
def create
|
||||
if resource = authenticate(resource_name)
|
||||
set_flash_message :notice, :signed_in
|
||||
sign_in_and_redirect(resource_name, resource, true)
|
||||
else
|
||||
set_now_flash_message :alert, (warden.message || :invalid)
|
||||
clean_up_passwords(build_resource)
|
||||
render_with_scope :new
|
||||
end
|
||||
resource = warden.authenticate!(:scope => resource_name, :recall => "new")
|
||||
set_flash_message :notice, :signed_in
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
end
|
||||
|
||||
# GET /resource/sign_out
|
||||
@@ -32,14 +20,4 @@ class Devise::SessionsController < ApplicationController
|
||||
set_flash_message :notice, :signed_out if signed_in?(resource_name)
|
||||
sign_out_and_redirect(resource_name)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def resource_just_signed_up?
|
||||
flash[:"#{resource_name}_signed_up"]
|
||||
end
|
||||
|
||||
def clean_up_passwords(object)
|
||||
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class Devise::UnlocksController < ApplicationController
|
||||
prepend_before_filter :require_no_authentication
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
# GET /resource/unlock/new
|
||||
@@ -21,7 +22,7 @@ class Devise::UnlocksController < ApplicationController
|
||||
|
||||
# GET /resource/unlock?unlock_token=abcdef
|
||||
def show
|
||||
self.resource = resource_class.unlock!(:unlock_token => params[:unlock_token])
|
||||
self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :unlocked
|
||||
|
||||
17
app/helpers/devise_helper.rb
Normal file
17
app/helpers/devise_helper.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module DeviseHelper
|
||||
def devise_error_messages!
|
||||
return "" if resource.errors.empty?
|
||||
|
||||
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
|
||||
sentence = "#{pluralize(resource.errors.count, "error")} prohibited this #{resource_name} from being saved:"
|
||||
|
||||
html = <<-HTML
|
||||
<div id="error_explanation">
|
||||
<h2>#{sentence}</h2>
|
||||
<ul>#{messages}</ul>
|
||||
</div>
|
||||
HTML
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
71
app/mailers/devise/mailer.rb
Normal file
71
app/mailers/devise/mailer.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
attr_reader :devise_mapping, :resource
|
||||
|
||||
def confirmation_instructions(record)
|
||||
setup_mail(record, :confirmation_instructions)
|
||||
end
|
||||
|
||||
def reset_password_instructions(record)
|
||||
setup_mail(record, :reset_password_instructions)
|
||||
end
|
||||
|
||||
def unlock_instructions(record)
|
||||
setup_mail(record, :unlock_instructions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Configure default email options
|
||||
def setup_mail(record, action)
|
||||
@scope_name = Devise::Mapping.find_scope!(record)
|
||||
@devise_mapping = Devise.mappings[@scope_name]
|
||||
@resource = instance_variable_set("@#{@devise_mapping.name}", record)
|
||||
|
||||
headers = {
|
||||
:subject => translate(@devise_mapping, action),
|
||||
:from => mailer_sender(@devise_mapping),
|
||||
:to => record.email,
|
||||
:template_path => template_paths
|
||||
}
|
||||
|
||||
headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
|
||||
mail(headers)
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
def template_paths
|
||||
template_path = [self.class.mailer_name]
|
||||
template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
|
||||
template_path
|
||||
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,55 +0,0 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
|
||||
attr_reader :devise_mapping, :resource
|
||||
|
||||
def confirmation_instructions(record)
|
||||
setup_mail(record, :confirmation_instructions)
|
||||
end
|
||||
|
||||
def reset_password_instructions(record)
|
||||
setup_mail(record, :reset_password_instructions)
|
||||
end
|
||||
|
||||
def unlock_instructions(record)
|
||||
setup_mail(record, :unlock_instructions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Configure default email options
|
||||
def setup_mail(record, action)
|
||||
@devise_mapping = Devise::Mapping.find_by_class(record.class)
|
||||
|
||||
raise "Invalid devise resource #{record}" unless @devise_mapping
|
||||
@resource = instance_variable_set("@#{@devise_mapping.name}", record)
|
||||
|
||||
mail(:subject => translate(@devise_mapping, action),
|
||||
:from => mailer_sender(@devise_mapping), :to => record.email) do |format|
|
||||
format.html { render_with_scope(action, :controller => "mailer") }
|
||||
end
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
block_args = mapping.name if Devise.mailer_sender.arity > 0
|
||||
Devise.mailer_sender.call(block_args)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
# Setup subject namespaced by model. It means you're able to setup your
|
||||
# messages using specific resource scope, or provide a default one.
|
||||
# Example (i18n locale file):
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions: '...'
|
||||
# user:
|
||||
# confirmation_instructions: '...'
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}.#{key}", :scope => [:devise, :mailer], :default => key)
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => confirmation_path(resource_name) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :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 %>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => password_path(resource_name), :html => { :method => :put } do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.submit "Change my password" %></p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => password_path(resource_name) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :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 %>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => registration_path(resource_name), :html => { :method => :put } do |f| -%>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i></p>
|
||||
<p><%= f.password_field :current_password %></p>
|
||||
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password %></p>
|
||||
|
||||
<p><%= f.submit "Update" %></p>
|
||||
<% end -%>
|
||||
<% end %>
|
||||
|
||||
<h3>Cancel my account</h3>
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<h2>Sign up</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => registration_path(resource_name) do |f| -%>
|
||||
<%= f.error_messages %>
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %></p>
|
||||
<p><%= f.password_field :password_confirmation %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
|
||||
<p><%= f.submit "Sign up" %></p>
|
||||
<% end -%>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<h2>Sign in</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => session_path(resource_name) do |f| -%>
|
||||
<p><%= f.label :email %></p>
|
||||
<p><%= f.text_field :email %></p>
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.text_field :email %></p>
|
||||
|
||||
<p><%= f.label :password %></p>
|
||||
<p><%= f.password_field :password %></p>
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p>
|
||||
<% end -%>
|
||||
|
||||
<p><%= f.submit "Sign in" %></p>
|
||||
<% end -%>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -1,19 +1,19 @@
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to t('devise.sessions.link'), new_session_path(resource_name) %><br />
|
||||
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to t('devise.registrations.link'), new_registration_path(resource_name) %><br />
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
|
||||
<%= link_to t('devise.passwords.link'), new_password_path(resource_name) %><br />
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to t('devise.confirmations.link'), new_confirmation_path(resource_name) %><br />
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.lockable? && controller_name != 'unlocks' %>
|
||||
<%= link_to t('devise.unlocks.link'), new_unlock_path(resource_name) %><br />
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end -%>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<% form_for resource_name, resource, :url => unlock_path(resource_name) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :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 %>
|
||||
|
||||
@@ -6,10 +6,7 @@ en:
|
||||
not_locked: "was not locked"
|
||||
|
||||
devise:
|
||||
sessions:
|
||||
link: 'Sign in'
|
||||
signed_in: 'Signed in successfully.'
|
||||
signed_out: 'Signed out successfully.'
|
||||
failure:
|
||||
unauthenticated: 'You need to sign in or sign up before continuing.'
|
||||
unconfirmed: 'You have to confirm your account before continuing.'
|
||||
locked: 'Your account is locked.'
|
||||
@@ -17,25 +14,26 @@ en:
|
||||
invalid_token: 'Invalid authentication token.'
|
||||
timeout: 'Your session expired, please sign in again to continue.'
|
||||
inactive: 'Your account was not activated yet.'
|
||||
sessions:
|
||||
signed_in: 'Signed in successfully.'
|
||||
signed_out: 'Signed out successfully.'
|
||||
passwords:
|
||||
link: 'Forgot password?'
|
||||
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
|
||||
updated: 'Your password was changed successfully. You are now signed in.'
|
||||
confirmations:
|
||||
link: "Didn't receive confirmation instructions?"
|
||||
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:
|
||||
link: 'Sign up'
|
||||
signed_up: 'You have signed up successfully.'
|
||||
signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
|
||||
updated: 'You updated your account successfully.'
|
||||
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
|
||||
unlocks:
|
||||
link: "Didn't receive unlock instructions?"
|
||||
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'
|
||||
|
||||
317
devise.gemspec
317
devise.gemspec
@@ -1,183 +1,198 @@
|
||||
# Generated by jeweler
|
||||
# DO NOT EDIT THIS FILE DIRECTLY
|
||||
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
||||
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{devise}
|
||||
s.version = "1.1.pre4"
|
||||
s.version = "1.1.9"
|
||||
|
||||
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-03-03}
|
||||
s.date = %q{2011-03-25}
|
||||
s.description = %q{Flexible authentication solution for Rails with Warden}
|
||||
s.email = %q{contact@plataformatec.com.br}
|
||||
s.extra_rdoc_files = [
|
||||
"CHANGELOG.rdoc",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"TODO"
|
||||
"Gemfile.lock",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"TODO"
|
||||
]
|
||||
s.files = [
|
||||
"CHANGELOG.rdoc",
|
||||
"Gemfile",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"Rakefile",
|
||||
"TODO",
|
||||
"app/controllers/devise/confirmations_controller.rb",
|
||||
"app/controllers/devise/passwords_controller.rb",
|
||||
"app/controllers/devise/registrations_controller.rb",
|
||||
"app/controllers/devise/sessions_controller.rb",
|
||||
"app/controllers/devise/unlocks_controller.rb",
|
||||
"app/models/devise/mailer.rb",
|
||||
"app/views/devise/confirmations/new.html.erb",
|
||||
"app/views/devise/mailer/confirmation_instructions.html.erb",
|
||||
"app/views/devise/mailer/reset_password_instructions.html.erb",
|
||||
"app/views/devise/mailer/unlock_instructions.html.erb",
|
||||
"app/views/devise/passwords/edit.html.erb",
|
||||
"app/views/devise/passwords/new.html.erb",
|
||||
"app/views/devise/registrations/edit.html.erb",
|
||||
"app/views/devise/registrations/new.html.erb",
|
||||
"app/views/devise/sessions/new.html.erb",
|
||||
"app/views/devise/shared/_links.erb",
|
||||
"app/views/devise/unlocks/new.html.erb",
|
||||
"config/locales/en.yml",
|
||||
"lib/devise.rb",
|
||||
"lib/devise/controllers/helpers.rb",
|
||||
"lib/devise/controllers/internal_helpers.rb",
|
||||
"lib/devise/controllers/scoped_views.rb",
|
||||
"lib/devise/controllers/url_helpers.rb",
|
||||
"lib/devise/encryptors/authlogic_sha512.rb",
|
||||
"lib/devise/encryptors/base.rb",
|
||||
"lib/devise/encryptors/bcrypt.rb",
|
||||
"lib/devise/encryptors/clearance_sha1.rb",
|
||||
"lib/devise/encryptors/restful_authentication_sha1.rb",
|
||||
"lib/devise/encryptors/sha1.rb",
|
||||
"lib/devise/encryptors/sha512.rb",
|
||||
"lib/devise/failure_app.rb",
|
||||
"lib/devise/hooks/activatable.rb",
|
||||
"lib/devise/hooks/rememberable.rb",
|
||||
"lib/devise/hooks/timeoutable.rb",
|
||||
"lib/devise/hooks/trackable.rb",
|
||||
"lib/devise/mapping.rb",
|
||||
"lib/devise/models.rb",
|
||||
"lib/devise/models/activatable.rb",
|
||||
"lib/devise/models/authenticatable.rb",
|
||||
"lib/devise/models/confirmable.rb",
|
||||
"lib/devise/models/http_authenticatable.rb",
|
||||
"lib/devise/models/lockable.rb",
|
||||
"lib/devise/models/recoverable.rb",
|
||||
"lib/devise/models/registerable.rb",
|
||||
"lib/devise/models/rememberable.rb",
|
||||
"lib/devise/models/timeoutable.rb",
|
||||
"lib/devise/models/token_authenticatable.rb",
|
||||
"lib/devise/models/trackable.rb",
|
||||
"lib/devise/models/validatable.rb",
|
||||
"lib/devise/modules.rb",
|
||||
"lib/devise/orm/active_record.rb",
|
||||
"lib/devise/orm/data_mapper.rb",
|
||||
"lib/devise/orm/mongo_mapper.rb",
|
||||
"lib/devise/rails.rb",
|
||||
"lib/devise/rails/routes.rb",
|
||||
"lib/devise/rails/warden_compat.rb",
|
||||
"lib/devise/schema.rb",
|
||||
"lib/devise/strategies/authenticatable.rb",
|
||||
"lib/devise/strategies/base.rb",
|
||||
"lib/devise/strategies/http_authenticatable.rb",
|
||||
"lib/devise/strategies/rememberable.rb",
|
||||
"lib/devise/strategies/token_authenticatable.rb",
|
||||
"lib/devise/test_helpers.rb",
|
||||
"lib/devise/version.rb",
|
||||
"lib/generators/devise/devise_generator.rb",
|
||||
"lib/generators/devise/templates/migration.rb",
|
||||
"lib/generators/devise_install/devise_install_generator.rb",
|
||||
"lib/generators/devise_install/templates/README",
|
||||
"lib/generators/devise_install/templates/devise.rb",
|
||||
"lib/generators/devise_views/devise_views_generator.rb"
|
||||
"Gemfile",
|
||||
"Gemfile.lock",
|
||||
"MIT-LICENSE",
|
||||
"README.rdoc",
|
||||
"Rakefile",
|
||||
"TODO",
|
||||
"app/controllers/devise/confirmations_controller.rb",
|
||||
"app/controllers/devise/passwords_controller.rb",
|
||||
"app/controllers/devise/registrations_controller.rb",
|
||||
"app/controllers/devise/sessions_controller.rb",
|
||||
"app/controllers/devise/unlocks_controller.rb",
|
||||
"app/helpers/devise_helper.rb",
|
||||
"app/mailers/devise/mailer.rb",
|
||||
"app/views/devise/confirmations/new.html.erb",
|
||||
"app/views/devise/mailer/confirmation_instructions.html.erb",
|
||||
"app/views/devise/mailer/reset_password_instructions.html.erb",
|
||||
"app/views/devise/mailer/unlock_instructions.html.erb",
|
||||
"app/views/devise/passwords/edit.html.erb",
|
||||
"app/views/devise/passwords/new.html.erb",
|
||||
"app/views/devise/registrations/edit.html.erb",
|
||||
"app/views/devise/registrations/new.html.erb",
|
||||
"app/views/devise/sessions/new.html.erb",
|
||||
"app/views/devise/shared/_links.erb",
|
||||
"app/views/devise/unlocks/new.html.erb",
|
||||
"config/locales/en.yml",
|
||||
"lib/devise.rb",
|
||||
"lib/devise/controllers/helpers.rb",
|
||||
"lib/devise/controllers/internal_helpers.rb",
|
||||
"lib/devise/controllers/scoped_views.rb",
|
||||
"lib/devise/controllers/url_helpers.rb",
|
||||
"lib/devise/encryptors/authlogic_sha512.rb",
|
||||
"lib/devise/encryptors/base.rb",
|
||||
"lib/devise/encryptors/bcrypt.rb",
|
||||
"lib/devise/encryptors/clearance_sha1.rb",
|
||||
"lib/devise/encryptors/restful_authentication_sha1.rb",
|
||||
"lib/devise/encryptors/sha1.rb",
|
||||
"lib/devise/encryptors/sha512.rb",
|
||||
"lib/devise/failure_app.rb",
|
||||
"lib/devise/hooks/activatable.rb",
|
||||
"lib/devise/hooks/forgetable.rb",
|
||||
"lib/devise/hooks/rememberable.rb",
|
||||
"lib/devise/hooks/timeoutable.rb",
|
||||
"lib/devise/hooks/trackable.rb",
|
||||
"lib/devise/mapping.rb",
|
||||
"lib/devise/models.rb",
|
||||
"lib/devise/models/authenticatable.rb",
|
||||
"lib/devise/models/confirmable.rb",
|
||||
"lib/devise/models/database_authenticatable.rb",
|
||||
"lib/devise/models/lockable.rb",
|
||||
"lib/devise/models/recoverable.rb",
|
||||
"lib/devise/models/registerable.rb",
|
||||
"lib/devise/models/rememberable.rb",
|
||||
"lib/devise/models/timeoutable.rb",
|
||||
"lib/devise/models/token_authenticatable.rb",
|
||||
"lib/devise/models/trackable.rb",
|
||||
"lib/devise/models/validatable.rb",
|
||||
"lib/devise/modules.rb",
|
||||
"lib/devise/orm/active_record.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",
|
||||
"lib/devise/schema.rb",
|
||||
"lib/devise/strategies/authenticatable.rb",
|
||||
"lib/devise/strategies/base.rb",
|
||||
"lib/devise/strategies/database_authenticatable.rb",
|
||||
"lib/devise/strategies/rememberable.rb",
|
||||
"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/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.5}
|
||||
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",
|
||||
"test/controllers/internal_helpers_test.rb",
|
||||
"test/controllers/url_helpers_test.rb",
|
||||
"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/http_authenticatable_test.rb",
|
||||
"test/integration/lockable_test.rb",
|
||||
"test/integration/recoverable_test.rb",
|
||||
"test/integration/registerable_test.rb",
|
||||
"test/integration/rememberable_test.rb",
|
||||
"test/integration/timeoutable_test.rb",
|
||||
"test/integration/token_authenticatable_test.rb",
|
||||
"test/integration/trackable_test.rb",
|
||||
"test/mailers/confirmation_instructions_test.rb",
|
||||
"test/mailers/reset_password_instructions_test.rb",
|
||||
"test/mailers/unlock_instructions_test.rb",
|
||||
"test/mapping_test.rb",
|
||||
"test/models/authenticatable_test.rb",
|
||||
"test/models/confirmable_test.rb",
|
||||
"test/models/http_authenticatable_test.rb",
|
||||
"test/models/lockable_test.rb",
|
||||
"test/models/recoverable_test.rb",
|
||||
"test/models/rememberable_test.rb",
|
||||
"test/models/timeoutable_test.rb",
|
||||
"test/models/token_authenticatable_test.rb",
|
||||
"test/models/trackable_test.rb",
|
||||
"test/models/validatable_test.rb",
|
||||
"test/models_test.rb",
|
||||
"test/orm/active_record.rb",
|
||||
"test/orm/mongo_mapper.rb",
|
||||
"test/rails_app/app/active_record/admin.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/sessions_controller.rb",
|
||||
"test/rails_app/app/controllers/users_controller.rb",
|
||||
"test/rails_app/app/helpers/application_helper.rb",
|
||||
"test/rails_app/app/mongo_mapper/admin.rb",
|
||||
"test/rails_app/app/mongo_mapper/user.rb",
|
||||
"test/rails_app/config/application.rb",
|
||||
"test/rails_app/config/boot.rb",
|
||||
"test/rails_app/config/environment.rb",
|
||||
"test/rails_app/config/environments/development.rb",
|
||||
"test/rails_app/config/environments/production.rb",
|
||||
"test/rails_app/config/environments/test.rb",
|
||||
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
||||
"test/rails_app/config/initializers/cookie_verification_secret.rb",
|
||||
"test/rails_app/config/initializers/devise.rb",
|
||||
"test/rails_app/config/initializers/inflections.rb",
|
||||
"test/rails_app/config/initializers/session_store.rb",
|
||||
"test/rails_app/config/routes.rb",
|
||||
"test/routes_test.rb",
|
||||
"test/support/assertions.rb",
|
||||
"test/support/helpers.rb",
|
||||
"test/support/integration.rb",
|
||||
"test/support/test_silencer.rb",
|
||||
"test/support/webrat/integrations/rails.rb",
|
||||
"test/test_helper.rb",
|
||||
"test/test_helpers_test.rb"
|
||||
"test/controllers/internal_helpers_test.rb",
|
||||
"test/controllers/url_helpers_test.rb",
|
||||
"test/devise_test.rb",
|
||||
"test/encryptors_test.rb",
|
||||
"test/failure_app_test.rb",
|
||||
"test/indifferent_hash.rb",
|
||||
"test/integration/authenticatable_test.rb",
|
||||
"test/integration/confirmable_test.rb",
|
||||
"test/integration/database_authenticatable_test.rb",
|
||||
"test/integration/http_authenticatable_test.rb",
|
||||
"test/integration/lockable_test.rb",
|
||||
"test/integration/recoverable_test.rb",
|
||||
"test/integration/registerable_test.rb",
|
||||
"test/integration/rememberable_test.rb",
|
||||
"test/integration/timeoutable_test.rb",
|
||||
"test/integration/token_authenticatable_test.rb",
|
||||
"test/integration/trackable_test.rb",
|
||||
"test/mailers/confirmation_instructions_test.rb",
|
||||
"test/mailers/reset_password_instructions_test.rb",
|
||||
"test/mailers/unlock_instructions_test.rb",
|
||||
"test/mapping_test.rb",
|
||||
"test/models/confirmable_test.rb",
|
||||
"test/models/database_authenticatable_test.rb",
|
||||
"test/models/lockable_test.rb",
|
||||
"test/models/recoverable_test.rb",
|
||||
"test/models/rememberable_test.rb",
|
||||
"test/models/timeoutable_test.rb",
|
||||
"test/models/token_authenticatable_test.rb",
|
||||
"test/models/trackable_test.rb",
|
||||
"test/models/validatable_test.rb",
|
||||
"test/models_test.rb",
|
||||
"test/orm/active_record.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/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",
|
||||
"test/rails_app/config/environment.rb",
|
||||
"test/rails_app/config/environments/development.rb",
|
||||
"test/rails_app/config/environments/production.rb",
|
||||
"test/rails_app/config/environments/test.rb",
|
||||
"test/rails_app/config/initializers/backtrace_silencers.rb",
|
||||
"test/rails_app/config/initializers/devise.rb",
|
||||
"test/rails_app/config/initializers/inflections.rb",
|
||||
"test/rails_app/config/initializers/secret_token.rb",
|
||||
"test/rails_app/config/routes.rb",
|
||||
"test/rails_app/db/migrate/20100401102949_create_tables.rb",
|
||||
"test/rails_app/db/schema.rb",
|
||||
"test/routes_test.rb",
|
||||
"test/support/assertions.rb",
|
||||
"test/support/helpers.rb",
|
||||
"test/support/integration.rb",
|
||||
"test/support/test_silencer.rb",
|
||||
"test/support/webrat/integrations/rails.rb",
|
||||
"test/test_helper.rb",
|
||||
"test/test_helpers_test.rb"
|
||||
]
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
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.9.4"])
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_runtime_dependency(%q<warden>, ["~> 1.0.2"])
|
||||
s.add_runtime_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.9.4"])
|
||||
s.add_dependency(%q<warden>, ["~> 1.0.2"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<warden>, ["~> 0.9.4"])
|
||||
s.add_dependency(%q<warden>, ["~> 1.0.2"])
|
||||
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
194
lib/devise.rb
194
lib/devise.rb
@@ -1,5 +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'
|
||||
|
||||
@@ -20,13 +24,17 @@ module Devise
|
||||
autoload :Sha1, 'devise/encryptors/sha1'
|
||||
end
|
||||
|
||||
module Strategies
|
||||
autoload :Base, 'devise/strategies/base'
|
||||
autoload :Authenticatable, 'devise/strategies/authenticatable'
|
||||
end
|
||||
|
||||
# Constants which holds devise configuration for extensions. Those should
|
||||
# not be modified by the "end user".
|
||||
ALL = []
|
||||
CONTROLLERS = {}
|
||||
ROUTES = []
|
||||
STRATEGIES = []
|
||||
FLASH_MESSAGES = [:unauthenticated]
|
||||
ALL = []
|
||||
CONTROLLERS = ActiveSupport::OrderedHash.new
|
||||
ROUTES = ActiveSupport::OrderedHash.new
|
||||
STRATEGIES = ActiveSupport::OrderedHash.new
|
||||
|
||||
# True values used to check params
|
||||
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
|
||||
@@ -41,8 +49,9 @@ module Devise
|
||||
:bcrypt => 60
|
||||
}
|
||||
|
||||
# Email regex used to validate email formats. Adapted from authlogic.
|
||||
EMAIL_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
|
||||
# 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
|
||||
@@ -56,10 +65,42 @@ module Devise
|
||||
mattr_accessor :authentication_keys
|
||||
@@authentication_keys = [ :email ]
|
||||
|
||||
# Time interval where the remember me token is valid.
|
||||
# If http authentication is enabled by default.
|
||||
mattr_accessor :http_authenticatable
|
||||
@@http_authenticatable = false
|
||||
|
||||
# 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
|
||||
|
||||
# The realm used in Http Basic Authentication.
|
||||
mattr_accessor :http_authentication_realm
|
||||
@@http_authentication_realm = "Application"
|
||||
|
||||
# Email regex used to validate email formats. Adapted from authlogic.
|
||||
mattr_accessor :email_regexp
|
||||
@@email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
|
||||
|
||||
# Range validation for password length
|
||||
mattr_accessor :password_length
|
||||
@@password_length = 6..20
|
||||
|
||||
# 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
|
||||
@@ -70,14 +111,14 @@ module Devise
|
||||
|
||||
# Used to define the password encryption algorithm.
|
||||
mattr_accessor :encryptor
|
||||
@@encryptor = :sha1
|
||||
@@encryptor = nil
|
||||
|
||||
# Store scopes mappings.
|
||||
mattr_accessor :mappings
|
||||
@@mappings = ActiveSupport::OrderedHash.new
|
||||
|
||||
# Tells if devise should apply the schema in ORMs where devise declaration
|
||||
# and schema belongs to the same class (as Datamapper and MongoMapper).
|
||||
# and schema belongs to the same class (as Datamapper and Mongoid).
|
||||
mattr_accessor :apply_schema
|
||||
@@apply_schema = true
|
||||
|
||||
@@ -86,23 +127,24 @@ module Devise
|
||||
mattr_accessor :scoped_views
|
||||
@@scoped_views = false
|
||||
|
||||
# Number of authentication tries before locking an account
|
||||
mattr_accessor :maximum_attempts
|
||||
@@maximum_attempts = 20
|
||||
# Defines which strategy can be used to lock an account.
|
||||
# Values: :failed_attempts, :none
|
||||
mattr_accessor :lock_strategy
|
||||
@@lock_strategy = :failed_attempts
|
||||
|
||||
# Defines which strategy can be used to unlock an account.
|
||||
# Values: :email, :time, :both
|
||||
mattr_accessor :unlock_strategy
|
||||
@@unlock_strategy = :both
|
||||
|
||||
# Number of authentication tries before locking an account
|
||||
mattr_accessor :maximum_attempts
|
||||
@@maximum_attempts = 20
|
||||
|
||||
# Time interval to unlock the account if :time is defined as unlock_strategy.
|
||||
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
|
||||
@@ -115,9 +157,25 @@ module Devise
|
||||
mattr_accessor :token_authentication_key
|
||||
@@token_authentication_key = :auth_token
|
||||
|
||||
# The realm used in Http Basic Authentication
|
||||
mattr_accessor :http_authentication_realm
|
||||
@@http_authentication_realm = "Application"
|
||||
# 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.
|
||||
@@ -125,39 +183,63 @@ module Devise
|
||||
yield self
|
||||
end
|
||||
|
||||
# Get the mailer class from the mailer reference object.
|
||||
def self.mailer
|
||||
@@mailer_ref.get
|
||||
end
|
||||
|
||||
# Set the mailer reference object to access the mailer.
|
||||
def self.mailer=(class_name)
|
||||
@@mailer_ref = ActiveSupport::Dependencies.ref(class_name)
|
||||
end
|
||||
self.mailer = "Devise::Mailer"
|
||||
|
||||
# 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
|
||||
mapping
|
||||
end
|
||||
|
||||
# Make Devise aware of an 3rd party Devise-module. For convenience.
|
||||
#
|
||||
# == Options:
|
||||
#
|
||||
# +strategy+ - Boolean value representing if this module got a custom *strategy*.
|
||||
# Default is +false+. Note: Devise will auto-detect this in such case if this is true.
|
||||
# +model+ - String representing the load path to a custom *model* for this module (to autoload.)
|
||||
# Default is +nil+ (i.e. +false+).
|
||||
# +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
|
||||
# Default is +nil+ (i.e. +false+).
|
||||
# +route+ - Symbol representing the named *router* helper for this module.
|
||||
# Default is +nil+ (i.e. +false+).
|
||||
# +flash+ - Symbol representing the *flash messages* used by this helper.
|
||||
# Default is +nil+ (i.e. +false+).
|
||||
# +model+ - String representing the load path to a custom *model* for this module (to autoload.)
|
||||
# +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
|
||||
# +route+ - Symbol representing the named *route* helper for this module.
|
||||
# +flash+ - Symbol representing the *flash messages* used by this helper.
|
||||
# +strategy+ - Symbol representing if this module got a custom *strategy*.
|
||||
#
|
||||
# All values, except :model, accept also a boolean and will have the same name as the given module
|
||||
# name.
|
||||
#
|
||||
# == Examples:
|
||||
#
|
||||
# Devise.add_module(:party_module)
|
||||
# Devise.add_module(:party_module, :strategy => true, :controller => :sessions)
|
||||
# Devise.add_module(:party_module, :autoload => 'party_module/model')
|
||||
# Devise.add_module(:party_module, :model => 'party_module/model')
|
||||
#
|
||||
def self.add_module(module_name, options = {})
|
||||
ALL << module_name
|
||||
options.assert_valid_keys(:strategy, :model, :controller, :route, :flash)
|
||||
options.assert_valid_keys(:strategy, :model, :controller, :route)
|
||||
|
||||
{ :strategy => STRATEGIES, :flash => FLASH_MESSAGES, :route => ROUTES }.each do |key, value|
|
||||
config = {
|
||||
:strategy => STRATEGIES,
|
||||
:route => ROUTES,
|
||||
:controller => CONTROLLERS
|
||||
}
|
||||
|
||||
config.each do |key, value|
|
||||
next unless options[key]
|
||||
name = (options[key] == true ? module_name : options[key])
|
||||
value.unshift(name) unless value.include?(name)
|
||||
end
|
||||
|
||||
if options[:controller]
|
||||
Devise::CONTROLLERS[module_name] = options[:controller].to_sym
|
||||
if value.is_a?(Hash)
|
||||
value[module_name] = name
|
||||
else
|
||||
value << name unless value.include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
if options[:model]
|
||||
@@ -165,7 +247,7 @@ module Devise
|
||||
Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path)
|
||||
end
|
||||
|
||||
Devise::Mapping.register module_name
|
||||
Devise::Mapping.add_module module_name
|
||||
end
|
||||
|
||||
# Sets warden configuration using a block that will be invoked on warden
|
||||
@@ -180,25 +262,45 @@ module Devise
|
||||
# end
|
||||
# end
|
||||
def self.warden(&block)
|
||||
@warden_config = block
|
||||
@@warden_config_block = block
|
||||
end
|
||||
|
||||
# Returns true if Rails version is bigger than 3.0.x
|
||||
def self.rack_session?
|
||||
Rails::VERSION::STRING[0,3] != "3.0"
|
||||
end
|
||||
|
||||
# A method used internally to setup warden manager from the Rails initialize
|
||||
# block.
|
||||
def self.configure_warden(config) #:nodoc:
|
||||
config.default_strategies *Devise::STRATEGIES
|
||||
config.failure_app = Devise::FailureApp
|
||||
config.silence_missing_strategies!
|
||||
config.default_scope = Devise.default_scope
|
||||
def self.configure_warden! #:nodoc:
|
||||
@@warden_configured ||= begin
|
||||
warden_config.failure_app = Devise::FailureApp
|
||||
warden_config.default_scope = Devise.default_scope
|
||||
|
||||
# If the user provided a warden hook, call it now.
|
||||
@warden_config.try :call, config
|
||||
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.
|
||||
def self.friendly_token
|
||||
ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
|
||||
end
|
||||
|
||||
# constant-time comparison algorithm to prevent timing attacks
|
||||
def self.secure_compare(a, b)
|
||||
return false unless a.present? && b.present?
|
||||
return false unless a.bytesize == b.bytesize
|
||||
l = a.unpack "C#{a.bytesize}"
|
||||
|
||||
res = 0
|
||||
b.each_byte { |byte| res |= byte ^ l.shift }
|
||||
res == 0
|
||||
end
|
||||
end
|
||||
|
||||
require 'warden'
|
||||
|
||||
@@ -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
|
||||
@@ -23,24 +23,18 @@ module Devise
|
||||
false
|
||||
end
|
||||
|
||||
# Attempts to authenticate the given scope by running authentication hooks,
|
||||
# but does not redirect in case of failures.
|
||||
def authenticate(scope)
|
||||
warden.authenticate(:scope => scope)
|
||||
end
|
||||
|
||||
# Attempts to authenticate the given scope by running authentication hooks,
|
||||
# redirecting in case of failures.
|
||||
def authenticate!(scope)
|
||||
warden.authenticate!(:scope => scope)
|
||||
end
|
||||
|
||||
# Check if the given scope is signed in session, without running
|
||||
# authentication hooks.
|
||||
def signed_in?(scope)
|
||||
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.
|
||||
#
|
||||
@@ -70,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:
|
||||
#
|
||||
@@ -79,7 +83,7 @@ module Devise
|
||||
#
|
||||
def stored_location_for(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
session.delete(:"#{scope}.return_to")
|
||||
session.delete("#{scope}_return_to")
|
||||
end
|
||||
|
||||
# The default url to be used after signing in. This is used by all Devise
|
||||
@@ -92,6 +96,38 @@ module Devise
|
||||
#
|
||||
# map.user_root '/users', :controller => 'users' # creates user_root_path
|
||||
#
|
||||
# map.namespace :user do |user|
|
||||
# user.root :controller => 'users' # creates user_root_path
|
||||
# end
|
||||
#
|
||||
#
|
||||
# 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?
|
||||
# publisher_url
|
||||
# else
|
||||
# super
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def after_sign_in_path_for(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
home_path = "#{scope}_root_path"
|
||||
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
|
||||
@@ -100,7 +136,7 @@ module Devise
|
||||
# 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_sign_in_path_for(resource)
|
||||
# def after_update_path_for(resource)
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
# publisher_url
|
||||
# else
|
||||
@@ -108,10 +144,8 @@ module Devise
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def after_sign_in_path_for(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
home_path = :"#{scope}_root_path"
|
||||
respond_to?(home_path, true) ? send(home_path) : root_path
|
||||
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
|
||||
@@ -129,10 +163,10 @@ module Devise
|
||||
#
|
||||
# If just a symbol is given, consider that the user was already signed in
|
||||
# through other means and just perform the redirection.
|
||||
def sign_in_and_redirect(resource_or_scope, resource=nil, skip=false)
|
||||
def sign_in_and_redirect(resource_or_scope, resource=nil)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
resource ||= resource_or_scope
|
||||
sign_in(scope, resource) unless skip
|
||||
sign_in(scope, resource) unless warden.user(scope) == resource
|
||||
redirect_to stored_location_for(scope) || after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
@@ -140,19 +174,29 @@ 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
|
||||
|
||||
# Override Rails' handle unverified request to sign out all scopes.
|
||||
def handle_unverified_request
|
||||
sign_out_all_scopes
|
||||
super # call the default behaviour which resets the session
|
||||
end
|
||||
|
||||
# Define authentication filters and accessor helpers based on mappings.
|
||||
# These filters should be used inside the controllers as before_filters,
|
||||
# so you can control the scope of the user who should be signed in to
|
||||
# access that specific controller/action.
|
||||
# Example:
|
||||
#
|
||||
# Maps:
|
||||
# User => :authenticatable
|
||||
# Admin => :authenticatable
|
||||
# Roles:
|
||||
# User
|
||||
# Admin
|
||||
#
|
||||
# Generated methods:
|
||||
# authenticate_user! # Signs user in or redirect
|
||||
|
||||
@@ -8,13 +8,14 @@ module Devise
|
||||
include Devise::Controllers::ScopedViews
|
||||
|
||||
included do
|
||||
helpers = [:resource, :scope_name, :resource_name,
|
||||
:resource_class, :devise_mapping, :devise_controller?]
|
||||
helper DeviseHelper
|
||||
|
||||
helpers = %w(resource scope_name resource_name
|
||||
resource_class devise_mapping devise_controller?)
|
||||
hide_action *helpers
|
||||
helper_method *helpers
|
||||
|
||||
before_filter :is_devise_resource?
|
||||
prepend_before_filter :is_devise_resource?
|
||||
skip_before_filter *Devise.mappings.keys.map { |m| :"authenticate_#{m}!" }
|
||||
end
|
||||
|
||||
@@ -36,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
|
||||
@@ -52,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
|
||||
@@ -62,8 +58,9 @@ module Devise
|
||||
end
|
||||
|
||||
# Build a devise resource.
|
||||
def build_resource
|
||||
self.resource = resource_class.new(params[resource_name] || {})
|
||||
def build_resource(hash=nil)
|
||||
hash ||= params[resource_name] || {}
|
||||
self.resource = resource_class.new(hash)
|
||||
end
|
||||
|
||||
# Helper for use in before_filters where no authentication is required.
|
||||
@@ -88,17 +85,14 @@ module Devise
|
||||
#
|
||||
# Please refer to README or en.yml locale file to check what messages are
|
||||
# available.
|
||||
def set_flash_message(key, kind, now=false)
|
||||
flash_hash = now ? flash.now : flash
|
||||
flash_hash[key] = I18n.t(:"#{resource_name}.#{kind}",
|
||||
def set_flash_message(key, kind)
|
||||
flash[key] = I18n.t(:"#{resource_name}.#{kind}", :resource_name => resource_name,
|
||||
:scope => [:devise, controller_name.to_sym], :default => kind)
|
||||
end
|
||||
|
||||
# Shortcut to set flash.now message. Same rules applied from set_flash_message
|
||||
def set_now_flash_message(key, kind)
|
||||
set_flash_message(key, kind, true)
|
||||
def clean_up_passwords(object)
|
||||
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module Devise
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def scoped_views
|
||||
def scoped_views?
|
||||
defined?(@scoped_views) ? @scoped_views : Devise.scoped_views
|
||||
end
|
||||
|
||||
@@ -20,9 +20,9 @@ module Devise
|
||||
def render_with_scope(action, options={})
|
||||
controller_name = options.delete(:controller) || self.controller_name
|
||||
|
||||
if self.class.scoped_views
|
||||
if self.class.scoped_views?
|
||||
begin
|
||||
render :template => "#{devise_mapping.as}/#{controller_name}/#{action}"
|
||||
render :template => "#{devise_mapping.plural}/#{controller_name}/#{action}"
|
||||
rescue ActionView::MissingTemplate
|
||||
render :template => "#{controller_path}/#{action}"
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ module Devise
|
||||
# Those helpers are added to your ApplicationController.
|
||||
module UrlHelpers
|
||||
|
||||
Devise::ROUTES.each do |module_name|
|
||||
Devise::ROUTES.values.uniq.each do |module_name|
|
||||
[:path, :url].each do |path_or_url|
|
||||
actions = [ nil, :new_ ]
|
||||
actions << :edit_ if [:password, :registration].include?(module_name)
|
||||
|
||||
@@ -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,9 +9,9 @@ module Devise
|
||||
include ActionController::RackDelegation
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirecting
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
mattr_accessor :default_message
|
||||
self.default_message = :unauthenticated
|
||||
delegate :flash, :to => :request
|
||||
|
||||
def self.call(env)
|
||||
action(:respond).call(env)
|
||||
@@ -22,27 +22,64 @@ module Devise
|
||||
end
|
||||
|
||||
def respond
|
||||
scope = warden_options[:scope]
|
||||
store_location!(scope)
|
||||
redirect_to send(:"new_#{scope}_session_path", query_string_params)
|
||||
if http_auth?
|
||||
http_auth
|
||||
elsif warden_options[:recall]
|
||||
recall
|
||||
else
|
||||
redirect
|
||||
end
|
||||
end
|
||||
|
||||
def http_auth
|
||||
self.status = 401
|
||||
self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect})
|
||||
self.content_type = request.format.to_s
|
||||
self.response_body = http_auth_body
|
||||
end
|
||||
|
||||
def recall
|
||||
env["PATH_INFO"] = attempted_path
|
||||
flash.now[:alert] = i18n_message(:invalid)
|
||||
self.response = recall_controller.action(warden_options[:recall]).call(env)
|
||||
end
|
||||
|
||||
def redirect
|
||||
store_location!
|
||||
flash[:alert] = i18n_message unless flash[:notice]
|
||||
redirect_to redirect_url
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Build the proper query string based on the given message.
|
||||
def query_string_params
|
||||
message = warden.try(:message) || warden_options[:message] || self.class.default_message
|
||||
def i18n_message(default = nil)
|
||||
message = warden.message || warden_options[:message] || default || :unauthenticated
|
||||
|
||||
case message
|
||||
when Symbol
|
||||
{ message => true }
|
||||
when String
|
||||
{ :message => message }
|
||||
if message.is_a?(Symbol)
|
||||
I18n.t(:"#{scope}.#{message}", :resource_name => scope,
|
||||
:scope => "devise.failure", :default => [message, message.to_s])
|
||||
else
|
||||
{}
|
||||
message.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_url
|
||||
send(:"new_#{scope}_session_path")
|
||||
end
|
||||
|
||||
def http_auth?
|
||||
!Devise.navigational_formats.include?(request_format) || (request.xhr? && Devise.http_authenticatable_on_xhr)
|
||||
end
|
||||
|
||||
def http_auth_body
|
||||
method = :"to_#{request_format}"
|
||||
{}.respond_to?(method) ? { :error => i18n_message }.send(method) : i18n_message
|
||||
end
|
||||
|
||||
def recall_controller
|
||||
"#{params[:controller].camelize}Controller".constantize
|
||||
end
|
||||
|
||||
def warden
|
||||
env['warden']
|
||||
end
|
||||
@@ -51,12 +88,32 @@ module Devise
|
||||
env['warden.options']
|
||||
end
|
||||
|
||||
def scope
|
||||
@scope ||= warden_options[:scope]
|
||||
end
|
||||
|
||||
def attempted_path
|
||||
warden_options[:attempted_path]
|
||||
end
|
||||
|
||||
# Stores requested uri to redirect the user after signing in. We cannot use
|
||||
# scoped session provided by warden here, since the user is not authenticated
|
||||
# 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!(scope)
|
||||
session[:"#{scope}.return_to"] = request.request_uri if request && request.get?
|
||||
def store_location!
|
||||
session[:"#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
|
||||
end
|
||||
|
||||
MIME_REFERENCES = Mime::HTML.respond_to?(:ref)
|
||||
|
||||
def request_format
|
||||
@request_format ||= if request.format.respond_to?(:ref)
|
||||
request.format.ref
|
||||
elsif MIME_REFERENCES
|
||||
request.format
|
||||
else # Rails < 3.0.4
|
||||
request.format.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
# Deny user access whenever his account is not active yet.
|
||||
# Deny user access whenever his account is not active yet. All strategies that inherits from
|
||||
# Devise::Strategies::Authenticatable and uses the validate already check if the user is active?
|
||||
# before actively signing him in. However, we need this as hook to validate the user activity
|
||||
# in each request and in case the user is using other strategies beside Devise ones.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record && record.respond_to?(:active?) && !record.active?
|
||||
scope = options[:scope]
|
||||
warden.logout(scope)
|
||||
|
||||
# If winning strategy was set, this is being called after authenticate and
|
||||
# there is no need to force a redirect.
|
||||
if warden.winning_strategy
|
||||
warden.winning_strategy.fail!(record.inactive_message)
|
||||
else
|
||||
throw :warden, :scope => scope, :message => record.inactive_message
|
||||
end
|
||||
throw :warden, :scope => scope, :message => record.inactive_message
|
||||
end
|
||||
end
|
||||
end
|
||||
11
lib/devise/hooks/forgetable.rb
Normal file
11
lib/devise/hooks/forgetable.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, options|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
cookie_options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
|
||||
warden.cookies.delete("remember_#{options[:scope]}_token", cookie_options)
|
||||
end
|
||||
end
|
||||
@@ -1,32 +1,43 @@
|
||||
# After authenticate hook to verify if the user in the given scope asked to be
|
||||
# remembered while he does not sign out. Generates a new remember token for
|
||||
# that specific user and adds a cookie with this user info to sign in this user
|
||||
# automatically without asking for credentials. Refer to rememberable strategy
|
||||
# for more info.
|
||||
Warden::Manager.prepend_after_authentication do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
|
||||
module Devise
|
||||
module Hooks
|
||||
# Overwrite success! in authentication strategies allowing users to be remembered.
|
||||
# We choose to implement this as an strategy hook instead of a warden hook to allow a specific
|
||||
# strategy (like token authenticatable or facebook authenticatable) to turn off remember_me?
|
||||
# cookies.
|
||||
module Rememberable #:nodoc:
|
||||
def success!(resource)
|
||||
super
|
||||
|
||||
if Devise::TRUE_VALUES.include?(remember_me) &&
|
||||
warden.authenticated?(scope) && record.respond_to?(:remember_me!)
|
||||
record.remember_me!
|
||||
if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
|
||||
resource.remember_me!(extend_remember_period?)
|
||||
|
||||
warden.response.set_cookie "remember_#{scope}_token", {
|
||||
:value => record.class.serialize_into_cookie(record),
|
||||
:expires => record.remember_expires_at,
|
||||
:path => "/"
|
||||
}
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Before logout hook to forget the user in the given scope, only if rememberable
|
||||
# is activated for this scope. Also clear remember token to ensure the user
|
||||
# won't be remembered again.
|
||||
# Notice that we forget the user if the record is frozen. This usually means the
|
||||
# user was just deleted.
|
||||
Warden::Manager.before_logout do |record, warden, scope|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
warden.response.delete_cookie "remember_#{scope}_token"
|
||||
end
|
||||
end
|
||||
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
# Each time a record is set we check whether it's session has already timed out
|
||||
# Each time a record is set we check whether its session has already timed out
|
||||
# or not, based on last request time. If so, the record is logged out and
|
||||
# redirected to the sign in page. Also, each time the request comes and the
|
||||
# record is set, we set the last request time inside it's scoped session to
|
||||
# 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
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# After each sign in, update sign in time, sign in count and sign in IP.
|
||||
# This is only triggered when the user is explicitly set (with set_user)
|
||||
# and on authentication. Retrieving the user from session (:fetch) does
|
||||
# not trigger it.
|
||||
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(scope)
|
||||
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope])
|
||||
record.update_tracked_fields!(warden.request)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,86 +22,67 @@ module Devise
|
||||
# # is the modules included in the class
|
||||
#
|
||||
class Mapping #:nodoc:
|
||||
attr_reader :name, :as, :controllers, :path_names, :path_prefix
|
||||
|
||||
# Loop through all mappings looking for a map that matches with the requested
|
||||
# path (ie /users/sign_in). If a path prefix is given, it's taken into account.
|
||||
def self.find_by_path(path)
|
||||
Devise.mappings.each_value do |mapping|
|
||||
route = path.split("/")[mapping.as_position]
|
||||
return mapping if route && mapping.as == route.to_sym
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Find a mapping by a given class. It takes into account single table inheritance as well.
|
||||
def self.find_by_class(klass)
|
||||
Devise.mappings.each_value do |mapping|
|
||||
return mapping if klass <= mapping.to
|
||||
end
|
||||
nil
|
||||
end
|
||||
attr_reader :singular, :plural, :path, :controllers, :path_names, :class_name
|
||||
alias :name :singular
|
||||
|
||||
# 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)
|
||||
case duck
|
||||
when String, Symbol
|
||||
duck
|
||||
return duck
|
||||
when Class
|
||||
Devise.mappings.each_value { |m| return m.name if duck <= m.to }
|
||||
else
|
||||
klass = duck.is_a?(Class) ? duck : duck.class
|
||||
mapping = Devise::Mapping.find_by_class(klass)
|
||||
raise "Could not find a valid mapping for #{duck}" unless mapping
|
||||
mapping.name
|
||||
Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
|
||||
end
|
||||
|
||||
raise "Could not find a valid mapping for #{duck}"
|
||||
end
|
||||
|
||||
def initialize(name, options) #:nodoc:
|
||||
@as = (options.delete(:as) || name).to_sym
|
||||
@klass = (options.delete(:class_name) || name.to_s.classify).to_s
|
||||
@name = (options.delete(:scope) || name.to_s.singularize).to_sym
|
||||
@plural = (options[:as] ? "#{options[:as]}_#{name}" : name).to_sym
|
||||
@singular = (options[:singular] || @plural.to_s.singularize).to_sym
|
||||
|
||||
@path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
|
||||
@class_name = (options[:class_name] || name.to_s.classify).to_s
|
||||
@ref = ActiveSupport::Dependencies.ref(@class_name)
|
||||
|
||||
@controllers = Hash.new { |h,k| h[k] = "devise/#{k}" }
|
||||
@controllers.merge!(options.delete(:controllers) || {})
|
||||
@path = (options[:path] || name).to_s
|
||||
@path_prefix = options[:path_prefix]
|
||||
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names.merge!(options.delete(:path_names) || {})
|
||||
mod = options[:module] || "devise"
|
||||
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
||||
@controllers.merge!(options[:controllers] || {})
|
||||
|
||||
@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
|
||||
|
||||
# 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
|
||||
def strategies
|
||||
@strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
|
||||
end
|
||||
|
||||
# Return in which position in the path prefix devise should find the as mapping.
|
||||
def as_position
|
||||
self.path_prefix.count("/")
|
||||
def routes
|
||||
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
|
||||
end
|
||||
|
||||
# Returns the raw path using path_prefix and as.
|
||||
def path
|
||||
path_prefix + as.to_s
|
||||
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.
|
||||
@@ -111,7 +92,7 @@ module Devise
|
||||
# self.modules.include?(:confirmable)
|
||||
# end
|
||||
#
|
||||
def self.register(m)
|
||||
def self.add_module(m)
|
||||
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
||||
def #{m}?
|
||||
self.modules.include?(:#{m})
|
||||
|
||||
@@ -38,17 +38,30 @@ module Devise
|
||||
|
||||
# Include the chosen devise modules in your model:
|
||||
#
|
||||
# devise :authenticatable, :confirmable, :recoverable
|
||||
# devise :database_authenticatable, :confirmable, :recoverable
|
||||
#
|
||||
# You can also give any of the devise configuration values in form of a hash,
|
||||
# with specific values for this model. Please check your Devise initializer
|
||||
# for a complete description on those values.
|
||||
#
|
||||
def devise(*modules)
|
||||
raise "You need to give at least one Devise module" if modules.empty?
|
||||
|
||||
include Devise::Models::Authenticatable
|
||||
options = modules.extract_options!
|
||||
@devise_modules = Devise::ALL & modules.map(&:to_sym).uniq
|
||||
|
||||
if modules.delete(:authenticatable)
|
||||
ActiveSupport::Deprecation.warn ":authenticatable as module is deprecated. Please give :database_authenticatable instead.", caller
|
||||
modules << :database_authenticatable
|
||||
end
|
||||
|
||||
if modules.delete(:activatable)
|
||||
ActiveSupport::Deprecation.warn ":activatable as module is deprecated. It's included in your model by default.", caller
|
||||
end
|
||||
|
||||
if modules.delete(:http_authenticatable)
|
||||
ActiveSupport::Deprecation.warn ":http_authenticatable as module is deprecated and is on by default. Revert by setting :http_authenticatable => false.", caller
|
||||
end
|
||||
|
||||
self.devise_modules += Devise::ALL & modules.map(&:to_sym).uniq
|
||||
|
||||
devise_modules_hook! do
|
||||
devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
||||
@@ -56,38 +69,12 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# Stores all modules included inside the model, so we are able to verify
|
||||
# which routes are needed.
|
||||
def devise_modules
|
||||
@devise_modules ||= []
|
||||
end
|
||||
|
||||
# The hook which is called inside devise. So your ORM can include devise
|
||||
# compatibility stuff.
|
||||
def devise_modules_hook!
|
||||
yield
|
||||
end
|
||||
|
||||
# Find an initialize a record setting an error if it can't be found.
|
||||
def find_or_initialize_with_error_by(attribute, value, error=:invalid)
|
||||
if value.present?
|
||||
conditions = { attribute => value }
|
||||
record = find(:first, :conditions => conditions)
|
||||
end
|
||||
|
||||
unless record
|
||||
record = new
|
||||
|
||||
if value.present?
|
||||
record.send(:"#{attribute}=", value)
|
||||
else
|
||||
error = :blank
|
||||
end
|
||||
|
||||
record.errors.add(attribute, error)
|
||||
end
|
||||
|
||||
record
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'devise/models/authenticatable'
|
||||
@@ -1,16 +0,0 @@
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# This module implements the default API required in activatable hook.
|
||||
module Activatable
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,118 +1,84 @@
|
||||
require 'devise/strategies/authenticatable'
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Authenticable Module, responsible for encrypting password and validating
|
||||
# authenticity of a user while signing in.
|
||||
# Authenticable module. Holds common settings for authentication.
|
||||
#
|
||||
# Configuration:
|
||||
# == Configuration:
|
||||
#
|
||||
# You can overwrite configuration values by setting in globally in Devise,
|
||||
# using devise method or overwriting the respective instance method.
|
||||
#
|
||||
# pepper: encryption key used for creating encrypted password. Each time
|
||||
# password changes, it's gonna be encrypted again, and this key
|
||||
# is added to the password and salt to create a secure hash.
|
||||
# Always use `rake secret' to generate a new key.
|
||||
# authentication_keys: parameters used for authentication. By default [:email].
|
||||
#
|
||||
# stretches: defines how many times the password will be encrypted.
|
||||
# http_authenticatable: if this model allows http authentication. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow http.
|
||||
#
|
||||
# encryptor: the encryptor going to be used. By default :sha1.
|
||||
# params_authenticatable: if this model allows authentication through request params. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow params authentication.
|
||||
#
|
||||
# authentication_keys: parameters used for authentication. By default [:email]
|
||||
# == Active?
|
||||
#
|
||||
# Examples:
|
||||
# Before authenticating an user and in each request, Devise checks if your model is active by
|
||||
# calling model.active?. This method is overwriten by other devise modules. For instance,
|
||||
# :confirmable overwrites .active? to only return true if your model was confirmed.
|
||||
#
|
||||
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
|
||||
# User.find(1).valid_password?('password123') # returns true/false
|
||||
# You overwrite this method yourself, but if you do, don't forget to call super:
|
||||
#
|
||||
# def active?
|
||||
# super && special_condition_is_valid?
|
||||
# end
|
||||
#
|
||||
# Whenever active? returns false, Devise asks the reason why your model is inactive using
|
||||
# the inactive_message method. You can overwrite it as well:
|
||||
#
|
||||
# def inactive_message
|
||||
# special_condition_is_valid? ? super : :special_condition_is_not_valid
|
||||
# end
|
||||
#
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
attr_reader :password, :current_password
|
||||
attr_accessor :password_confirmation
|
||||
class_attribute :devise_modules, :instance_writer => false
|
||||
self.devise_modules ||= []
|
||||
end
|
||||
|
||||
# Regenerates password salt and encrypted password each time password is set,
|
||||
# and then trigger any "after_changed_password"-callbacks.
|
||||
def password=(new_password)
|
||||
@password = new_password
|
||||
|
||||
if @password.present?
|
||||
self.password_salt = self.class.encryptor_class.salt
|
||||
self.encrypted_password = password_digest(@password)
|
||||
end
|
||||
end
|
||||
|
||||
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
||||
def valid_password?(incoming_password)
|
||||
password_digest(incoming_password) == self.encrypted_password
|
||||
end
|
||||
|
||||
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
|
||||
# is the user authentication token.
|
||||
def valid_authentication_token?(incoming_auth_token)
|
||||
incoming_auth_token == self.authentication_token
|
||||
end
|
||||
|
||||
# Checks if a resource is valid upon authentication.
|
||||
def valid_for_authentication?(attributes)
|
||||
valid_password?(attributes[:password])
|
||||
end
|
||||
|
||||
# Set password and password confirmation to nil
|
||||
def clean_up_passwords
|
||||
self.password = self.password_confirmation = nil
|
||||
end
|
||||
|
||||
# Update record attributes when :current_password matches, otherwise returns
|
||||
# error on :current_password. It also automatically rejects :password and
|
||||
# :password_confirmation if they are blank.
|
||||
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?
|
||||
|
||||
result = if valid_password?(current_password)
|
||||
update_attributes(params)
|
||||
# Check if the current object is valid for authentication. This method and
|
||||
# find_for_authentication are the methods used in a Warden::Strategy to check
|
||||
# if a model should be signed in or not.
|
||||
#
|
||||
# However, you should not overwrite this method, you should overwrite active? and
|
||||
# inactive_message instead.
|
||||
def valid_for_authentication?
|
||||
if active?
|
||||
block_given? ? yield : true
|
||||
else
|
||||
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
||||
self.attributes = params
|
||||
false
|
||||
inactive_message
|
||||
end
|
||||
|
||||
clean_up_passwords unless result
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
# Digests the password using the configured encryptor.
|
||||
def password_digest(password)
|
||||
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
||||
end
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
|
||||
Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
|
||||
|
||||
# Authenticate a user based on configured attribute keys. Returns the
|
||||
# authenticated user if it's valid or nil.
|
||||
def authenticate(attributes={})
|
||||
return unless authentication_keys.all? { |k| attributes[k].present? }
|
||||
conditions = attributes.slice(*authentication_keys)
|
||||
resource = find_for_authentication(conditions)
|
||||
resource if resource.try(:valid_for_authentication?, attributes)
|
||||
def params_authenticatable?(strategy)
|
||||
params_authenticatable.is_a?(Array) ?
|
||||
params_authenticatable.include?(strategy) : params_authenticatable
|
||||
end
|
||||
|
||||
# Returns the class for the configured encryptor.
|
||||
def encryptor_class
|
||||
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
||||
def http_authenticatable?(strategy)
|
||||
http_authenticatable.is_a?(Array) ?
|
||||
http_authenticatable.include?(strategy) : http_authenticatable
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Find first record based on conditions given (ie by the sign in form).
|
||||
# Overwrite to add customized conditions, create a join, or maybe use a
|
||||
# namedscope to filter records while authenticating.
|
||||
@@ -120,13 +86,51 @@ module Devise
|
||||
#
|
||||
# def self.find_for_authentication(conditions={})
|
||||
# conditions[:active] = true
|
||||
# find(:first, :conditions => conditions)
|
||||
# super
|
||||
# end
|
||||
#
|
||||
def find_for_authentication(conditions)
|
||||
filter_auth_params(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
|
||||
|
||||
protected
|
||||
|
||||
# Force keys to be string to avoid injection on mongoid related database.
|
||||
def filter_auth_params(conditions)
|
||||
conditions.each do |k, v|
|
||||
conditions[k] = v.to_s
|
||||
end
|
||||
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
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Confirmable is responsible to verify if an account is already confirmed to
|
||||
# sign in, and to send emails with confirmation instructions.
|
||||
# Confirmation instructions are sent to the user email after creating a
|
||||
@@ -30,7 +27,6 @@ module Devise
|
||||
# User.find(1).resend_confirmation! # generates a new token and resent it
|
||||
module Confirmable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
|
||||
included do
|
||||
before_create :generate_confirmation_token, :if => :confirmation_required?
|
||||
@@ -49,23 +45,18 @@ module Devise
|
||||
|
||||
# Verifies whether a user is confirmed or not
|
||||
def confirmed?
|
||||
!new_record? && !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
|
||||
|
||||
# Remove confirmation date and send confirmation instructions, to ensure
|
||||
# after sending these instructions the user won't be able to sign in without
|
||||
# confirming it's account
|
||||
def resend_confirmation!
|
||||
unless_confirmed do
|
||||
generate_confirmation_token
|
||||
save(:validate => false)
|
||||
send_confirmation_instructions
|
||||
end
|
||||
# Resend confirmation token. This method does not need to generate a new token.
|
||||
def resend_confirmation_token
|
||||
unless_confirmed { send_confirmation_instructions }
|
||||
end
|
||||
|
||||
# Overwrites active? from Devise::Models::Activatable for confirmation
|
||||
@@ -73,30 +64,25 @@ 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.
|
||||
def inactive_message
|
||||
if !confirmed?
|
||||
:unconfirmed
|
||||
else
|
||||
super
|
||||
end
|
||||
!confirmed? ? :unconfirmed : super
|
||||
end
|
||||
|
||||
# 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.
|
||||
@@ -137,10 +123,14 @@ module Devise
|
||||
# this token is being generated
|
||||
def generate_confirmation_token
|
||||
self.confirmed_at = nil
|
||||
self.confirmation_token = Devise.friendly_token
|
||||
self.confirmation_token = self.class.confirmation_token
|
||||
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,7 +138,7 @@ module Devise
|
||||
# Options must contain the user email
|
||||
def send_confirmation_instructions(attributes={})
|
||||
confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
||||
confirmable.resend_confirmation! unless confirmable.new_record?
|
||||
confirmable.resend_confirmation_token if confirmable.persisted?
|
||||
confirmable
|
||||
end
|
||||
|
||||
@@ -156,12 +146,17 @@ module Devise
|
||||
# If no user is found, returns a new user with an error.
|
||||
# If the user is already confirmed, create an error for the user
|
||||
# Options must have the confirmation_token
|
||||
def confirm!(attributes={})
|
||||
confirmable = find_or_initialize_with_error_by(:confirmation_token, attributes[:confirmation_token])
|
||||
confirmable.confirm! unless confirmable.new_record?
|
||||
def confirm_by_token(confirmation_token)
|
||||
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
||||
confirmable.confirm! if confirmable.persisted?
|
||||
confirmable
|
||||
end
|
||||
|
||||
# Generate a token checking if one does not already exist in the database.
|
||||
def confirmation_token
|
||||
generate_token(:confirmation_token)
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :confirm_within)
|
||||
end
|
||||
end
|
||||
|
||||
112
lib/devise/models/database_authenticatable.rb
Normal file
112
lib/devise/models/database_authenticatable.rb
Normal file
@@ -0,0 +1,112 @@
|
||||
require 'devise/strategies/database_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Authenticable Module, responsible for encrypting password and validating
|
||||
# authenticity of a user while signing in.
|
||||
#
|
||||
# Configuration:
|
||||
#
|
||||
# You can overwrite configuration values by setting in globally in Devise,
|
||||
# using devise method or overwriting the respective instance method.
|
||||
#
|
||||
# pepper: encryption key used for creating encrypted password. Each time
|
||||
# password changes, it's gonna be encrypted again, and this key
|
||||
# is added to the password and salt to create a secure hash.
|
||||
# Always use `rake secret' to generate a new key.
|
||||
#
|
||||
# stretches: defines how many times the password will be encrypted.
|
||||
#
|
||||
# encryptor: the encryptor going to be used. By default :sha1.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# User.find(1).valid_password?('password123') # returns true/false
|
||||
#
|
||||
module DatabaseAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
attr_reader :password, :current_password
|
||||
attr_accessor :password_confirmation
|
||||
end
|
||||
|
||||
# Regenerates password salt and encrypted password each time password is set,
|
||||
# and then trigger any "after_changed_password"-callbacks.
|
||||
def password=(new_password)
|
||||
@password = new_password
|
||||
|
||||
if @password.present?
|
||||
self.password_salt = self.class.password_salt
|
||||
self.encrypted_password = password_digest(@password)
|
||||
end
|
||||
end
|
||||
|
||||
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
||||
def valid_password?(incoming_password)
|
||||
Devise.secure_compare(password_digest(incoming_password), self.encrypted_password)
|
||||
end
|
||||
|
||||
# Set password and password confirmation to nil
|
||||
def clean_up_passwords
|
||||
self.password = self.password_confirmation = nil
|
||||
end
|
||||
|
||||
# Update record attributes when :current_password matches, otherwise returns
|
||||
# error on :current_password. It also automatically rejects :password and
|
||||
# :password_confirmation if they are blank.
|
||||
def update_with_password(params={})
|
||||
current_password = params.delete(:current_password)
|
||||
|
||||
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)
|
||||
else
|
||||
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
||||
self.attributes = params
|
||||
false
|
||||
end
|
||||
|
||||
clean_up_passwords
|
||||
result
|
||||
end
|
||||
|
||||
def after_database_authentication
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Digests the password using the configured encryptor.
|
||||
def password_digest(password)
|
||||
if self.password_salt.present?
|
||||
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :pepper, :stretches, :encryptor)
|
||||
|
||||
# Returns the class for the configured encryptor.
|
||||
def encryptor_class
|
||||
@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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
require 'devise/strategies/http_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Adds HttpAuthenticatable behavior to your model. It expects that your
|
||||
# model class responds to authenticate and authentication_keys methods
|
||||
# (which for example are defined in authenticatable).
|
||||
module HttpAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# Authenticate an user using http.
|
||||
def authenticate_with_http(username, password)
|
||||
authenticate(authentication_keys.first => username, :password => password)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Handles blocking a user access after a certain number of attempts.
|
||||
# Lockable accepts two different strategies to unlock a user after it's
|
||||
# blocked: email and time. The former will send an email to the user when
|
||||
@@ -13,93 +10,99 @@ module Devise
|
||||
# Configuration:
|
||||
#
|
||||
# maximum_attempts: how many attempts should be accepted before blocking the user.
|
||||
# unlock_strategy: unlock the user account by :time, :email or :both.
|
||||
# lock_strategy: lock the user account by :failed_attempts or :none.
|
||||
# unlock_strategy: unlock the user account by :time, :email, :both or :none.
|
||||
# unlock_in: the time you want to lock the user after to lock happens. Only
|
||||
# available when unlock_strategy is :time or :both.
|
||||
#
|
||||
module Lockable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
||||
|
||||
# Lock an user setting it's locked_at to actual time.
|
||||
def lock
|
||||
def lock_access!
|
||||
self.locked_at = Time.now
|
||||
|
||||
if unlock_strategy_enabled?(:email)
|
||||
generate_unlock_token
|
||||
send_unlock_instructions
|
||||
end
|
||||
end
|
||||
|
||||
# Lock an user also saving the record.
|
||||
def lock!
|
||||
lock
|
||||
save(:validate => false)
|
||||
end
|
||||
|
||||
# Unlock an user by cleaning locket_at and failed_attempts.
|
||||
def unlock!
|
||||
if_locked do
|
||||
def unlock_access!
|
||||
if_access_locked do
|
||||
self.locked_at = nil
|
||||
self.failed_attempts = 0
|
||||
self.unlock_token = nil
|
||||
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
|
||||
self.unlock_token = nil if respond_to?(:unlock_token=)
|
||||
save(:validate => false)
|
||||
end
|
||||
end
|
||||
|
||||
# Verifies whether a user is locked or not.
|
||||
def locked?
|
||||
def access_locked?
|
||||
locked_at && !lock_expired?
|
||||
end
|
||||
|
||||
# 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.
|
||||
def resend_unlock!
|
||||
if_locked do
|
||||
generate_unlock_token unless unlock_token.present?
|
||||
save(:validate => false)
|
||||
send_unlock_instructions
|
||||
end
|
||||
def resend_unlock_token
|
||||
if_access_locked { send_unlock_instructions }
|
||||
end
|
||||
|
||||
# Overwrites active? from Devise::Models::Activatable for locking purposes
|
||||
# by verifying whether an user is active to sign in or not based on locked?
|
||||
def active?
|
||||
super && !locked?
|
||||
super && !access_locked?
|
||||
end
|
||||
|
||||
# Overwrites invalid_message from Devise::Models::Authenticatable to define
|
||||
# the correct reason for blocking the sign in.
|
||||
def inactive_message
|
||||
if locked?
|
||||
:locked
|
||||
else
|
||||
super
|
||||
end
|
||||
access_locked? ? :locked : super
|
||||
end
|
||||
|
||||
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
|
||||
# for verifying whether an user is allowed to sign in or not. If the user
|
||||
# is locked, it should never be allowed.
|
||||
def valid_for_authentication?(attributes)
|
||||
if result = super
|
||||
def valid_for_authentication?
|
||||
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
||||
|
||||
case (result = super)
|
||||
when Symbol
|
||||
return result
|
||||
when TrueClass
|
||||
self.failed_attempts = 0
|
||||
else
|
||||
when FalseClass
|
||||
# PostgreSQL uses nil as the default value for integer columns set to 0
|
||||
self.failed_attempts ||= 0
|
||||
self.failed_attempts += 1
|
||||
lock if failed_attempts > self.class.maximum_attempts
|
||||
if attempts_exceeded?
|
||||
lock_access!
|
||||
return :locked
|
||||
end
|
||||
end
|
||||
|
||||
save(:validate => false) if changed?
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def attempts_exceeded?
|
||||
self.failed_attempts > self.class.maximum_attempts
|
||||
end
|
||||
|
||||
# Generates unlock token
|
||||
def generate_unlock_token
|
||||
self.unlock_token = Devise.friendly_token
|
||||
self.unlock_token = self.class.unlock_token
|
||||
end
|
||||
|
||||
# Tells if the lock is expired if :time unlock strategy is active
|
||||
@@ -113,8 +116,8 @@ module Devise
|
||||
|
||||
# Checks whether the record is locked or not, yielding to the block
|
||||
# if it's locked, otherwise adds an error to email.
|
||||
def if_locked
|
||||
if locked?
|
||||
def if_access_locked
|
||||
if access_locked?
|
||||
yield
|
||||
else
|
||||
self.errors.add(:email, :not_locked)
|
||||
@@ -122,11 +125,6 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# Is the unlock enabled for the given unlock strategy?
|
||||
def unlock_strategy_enabled?(strategy)
|
||||
[:both, strategy].include?(self.class.unlock_strategy)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attempt to find a user by it's email. If a record is found, send new
|
||||
# unlock instructions to it. If not user is found, returns a new user
|
||||
@@ -134,7 +132,7 @@ module Devise
|
||||
# Options must contain the user email
|
||||
def send_unlock_instructions(attributes={})
|
||||
lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
||||
lockable.resend_unlock! unless lockable.new_record?
|
||||
lockable.resend_unlock_token if lockable.persisted?
|
||||
lockable
|
||||
end
|
||||
|
||||
@@ -142,13 +140,27 @@ module Devise
|
||||
# If no user is found, returns a new user with an error.
|
||||
# If the user is not locked, creates an error for the user
|
||||
# Options must have the unlock_token
|
||||
def unlock!(attributes={})
|
||||
lockable = find_or_initialize_with_error_by(:unlock_token, attributes[:unlock_token])
|
||||
lockable.unlock! unless lockable.new_record?
|
||||
def unlock_access_by_token(unlock_token)
|
||||
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
|
||||
lockable.unlock_access! if lockable.persisted?
|
||||
lockable
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
|
||||
# Is the unlock enabled for the given unlock strategy?
|
||||
def unlock_strategy_enabled?(strategy)
|
||||
[:both, strategy].include?(self.unlock_strategy)
|
||||
end
|
||||
|
||||
# Is the lock enabled for the given lock strategy?
|
||||
def lock_strategy_enabled?(strategy)
|
||||
self.lock_strategy == strategy
|
||||
end
|
||||
|
||||
def unlock_token
|
||||
Devise.friendly_token
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -56,18 +56,23 @@ module Devise
|
||||
# Attributes must contain the user email
|
||||
def send_reset_password_instructions(attributes={})
|
||||
recoverable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
||||
recoverable.send_reset_password_instructions unless recoverable.new_record?
|
||||
recoverable.send_reset_password_instructions if recoverable.persisted?
|
||||
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
|
||||
# containing an error in reset_password_token attribute.
|
||||
# Attributes must contain reset_password_token, password and confirmation
|
||||
def reset_password!(attributes={})
|
||||
def reset_password_by_token(attributes={})
|
||||
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
|
||||
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) unless recoverable.new_record?
|
||||
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) if recoverable.persisted?
|
||||
recoverable
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'devise/strategies/rememberable'
|
||||
require 'devise/hooks/rememberable'
|
||||
require 'devise/hooks/forgetable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
@@ -17,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:
|
||||
#
|
||||
@@ -37,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
|
||||
|
||||
@@ -54,14 +64,9 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# Checks whether the incoming token matches or not with the record token.
|
||||
def valid_remember_token?(token)
|
||||
remember_token && !remember_expired? && remember_token == token
|
||||
end
|
||||
|
||||
# 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
|
||||
@@ -69,20 +74,48 @@ 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)
|
||||
"#{record.id}::#{record.remember_token}"
|
||||
[record.id, record.remember_token]
|
||||
end
|
||||
|
||||
# Recreate the user based on the stored cookie
|
||||
def serialize_from_cookie(cookie)
|
||||
record_id, record_token = cookie.split('::')
|
||||
record = find(:first, :conditions => { :id => record_id }) if record_id
|
||||
record if record.try(:valid_remember_token?, record_token)
|
||||
def serialize_from_cookie(id, remember_token)
|
||||
conditions = { :id => id, :remember_token => remember_token }
|
||||
record = find(:first, :conditions => conditions)
|
||||
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
|
||||
|
||||
@@ -2,8 +2,11 @@ require 'devise/strategies/token_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Token Authenticatable Module, responsible for generate authentication token and validating
|
||||
# authenticity of a user while signing in using an authentication token (say follows an URL).
|
||||
# The TokenAuthenticatable module is responsible for generating an authentication token and
|
||||
# validating the authenticity of the same while signing in.
|
||||
#
|
||||
# This module only provides a few helpers to help you manage the token. Creating and resetting
|
||||
# the token is your responsibility.
|
||||
#
|
||||
# == Configuration:
|
||||
#
|
||||
@@ -12,18 +15,9 @@ module Devise
|
||||
#
|
||||
# +token_authentication_key+ - Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
||||
#
|
||||
# == Examples:
|
||||
#
|
||||
# User.authenticate_with_token(:auth_token => '123456789') # returns authenticated user or nil
|
||||
# User.find(1).valid_authentication_token?('rI1t6PKQ8yP7VetgwdybB') # returns true/false
|
||||
#
|
||||
module TokenAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_save :ensure_authentication_token
|
||||
end
|
||||
|
||||
# Generate new authentication token (a.k.a. "single access token").
|
||||
def reset_authentication_token
|
||||
self.authentication_token = self.class.authentication_token
|
||||
@@ -32,7 +26,7 @@ module Devise
|
||||
# Generate new authentication token and save the record.
|
||||
def reset_authentication_token!
|
||||
reset_authentication_token
|
||||
self.save
|
||||
self.save(:validate => false)
|
||||
end
|
||||
|
||||
# Generate authentication token unless already exists.
|
||||
@@ -45,43 +39,21 @@ module Devise
|
||||
self.reset_authentication_token! if self.authentication_token.blank?
|
||||
end
|
||||
|
||||
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
|
||||
# is the user authentication token.
|
||||
def valid_authentication_token?(incoming_auth_token)
|
||||
incoming_auth_token.present? && incoming_auth_token == self.authentication_token
|
||||
# Hook called after token authentication.
|
||||
def after_token_authentication
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
::Devise::Models.config(self, :token_authentication_key)
|
||||
|
||||
# Authenticate a user based on authentication token.
|
||||
def authenticate_with_token(attributes)
|
||||
token = attributes[self.token_authentication_key]
|
||||
resource = self.find_for_token_authentication(token)
|
||||
resource if resource.try(:valid_authentication_token?, token)
|
||||
def find_for_token_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
|
||||
|
||||
protected
|
||||
|
||||
# Find first record based on conditions given (ie by the sign in form).
|
||||
# Overwrite to add customized conditions, create a join, or maybe use a
|
||||
# namedscope to filter records while authenticating.
|
||||
#
|
||||
# == Example:
|
||||
#
|
||||
# def self.find_for_token_authentication(token, conditions = {})
|
||||
# conditions = {:active => true}
|
||||
# self.find_by_authentication_token(token, :conditions => conditions)
|
||||
# end
|
||||
#
|
||||
def find_for_token_authentication(token)
|
||||
self.find(:first, :conditions => { :authentication_token => token})
|
||||
end
|
||||
|
||||
::Devise::Models.config(self, :token_authentication_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,17 +11,18 @@ module Devise
|
||||
:validates_confirmation_of, :validates_length_of ].freeze
|
||||
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
assert_validations_api!(base)
|
||||
|
||||
base.class_eval do
|
||||
validates_presence_of :email
|
||||
validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :allow_blank => true
|
||||
validates_format_of :email, :with => EMAIL_REGEX, :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|
|
||||
v.validates_presence_of :password
|
||||
v.validates_confirmation_of :password
|
||||
v.validates_length_of :password, :within => 6..20, :allow_blank => true
|
||||
v.validates_length_of :password, :within => password_length, :allow_blank => true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -35,14 +36,18 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
# Checks whether a password is needed or not. For validations only.
|
||||
# Passwords are always required if it's a new record, or if the password
|
||||
# or confirmation are being set somewhere.
|
||||
def password_required?
|
||||
new_record? || !password.nil? || !password_confirmation.nil?
|
||||
end
|
||||
# Checks whether a password is needed or not. For validations only.
|
||||
# Passwords are always required if it's a new record, or if the password
|
||||
# or confirmation are being set somewhere.
|
||||
def password_required?
|
||||
!persisted? || !password.nil? || !password_confirmation.nil?
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :email_regexp, :password_length)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,10 +2,9 @@ require 'active_support/core_ext/object/with_options'
|
||||
|
||||
Devise.with_options :model => true do |d|
|
||||
# Strategies first
|
||||
d.with_options :strategy => true do |s|
|
||||
s.add_module :authenticatable, :controller => :sessions, :flash => :invalid, :route => :session
|
||||
s.add_module :http_authenticatable
|
||||
s.add_module :token_authenticatable, :controller => :sessions, :flash => :invalid_token, :route => :session
|
||||
d.with_options :strategy => true do |s|
|
||||
s.add_module :database_authenticatable, :controller => :sessions, :route => :session
|
||||
s.add_module :token_authenticatable, :controller => :sessions, :route => :session
|
||||
s.add_module :rememberable
|
||||
end
|
||||
|
||||
@@ -15,10 +14,9 @@ Devise.with_options :model => true do |d|
|
||||
d.add_module :validatable
|
||||
|
||||
# The ones which can sign out after
|
||||
d.add_module :activatable, :flash => :inactive
|
||||
d.add_module :confirmable, :controller => :confirmations, :flash => :unconfirmed, :route => :confirmation
|
||||
d.add_module :lockable, :controller => :unlocks, :flash => :locked, :route => :unlock
|
||||
d.add_module :timeoutable, :flash => :timeout
|
||||
d.add_module :confirmable, :controller => :confirmations, :route => :confirmation
|
||||
d.add_module :lockable, :controller => :unlocks, :route => :unlock
|
||||
d.add_module :timeoutable
|
||||
|
||||
# Stats for last, so we make sure the user is really signed in
|
||||
d.add_module :trackable
|
||||
|
||||
@@ -3,7 +3,7 @@ module Devise
|
||||
# This module contains some helpers and handle schema (migrations):
|
||||
#
|
||||
# create_table :accounts do |t|
|
||||
# t.authenticatable
|
||||
# t.database_authenticatable
|
||||
# t.confirmable
|
||||
# t.recoverable
|
||||
# t.rememberable
|
||||
@@ -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,86 +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
|
||||
|
||||
property name, type, options
|
||||
end
|
||||
end
|
||||
|
||||
module Compatibility
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# Hooks for confirmable
|
||||
def before_create(*args)
|
||||
wrap_hook(:before, *args)
|
||||
end
|
||||
|
||||
def after_create(*args)
|
||||
wrap_hook(:after, *args)
|
||||
end
|
||||
|
||||
def wrap_hook(action, *args)
|
||||
options = args.extract_options!
|
||||
|
||||
args.each do |callback|
|
||||
send action, :create, 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 save(options=nil)
|
||||
if options.is_a?(Hash) && options[:validate] == false
|
||||
save!
|
||||
else
|
||||
super()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DataMapper::Model.class_eval do
|
||||
extend Devise::ORM::DataMapper::Hook
|
||||
include Devise::Models
|
||||
end
|
||||
@@ -1,49 +0,0 @@
|
||||
module Devise
|
||||
module Orm
|
||||
module MongoMapper
|
||||
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
|
||||
|
||||
# Tell how to apply schema methods. This automatically converts DateTime
|
||||
# to Time, since MongoMapper does not recognize the former.
|
||||
def apply_schema(name, type, options={})
|
||||
type = Time if type == DateTime
|
||||
key name, type, options
|
||||
end
|
||||
end
|
||||
|
||||
module Compatibility
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
def find(*args)
|
||||
case args.first
|
||||
when :first, :all
|
||||
send(args.shift, *args)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[MongoMapper::Document, MongoMapper::EmbeddedDocument].each do |mod|
|
||||
mod::ClassMethods.class_eval do
|
||||
include Devise::Models
|
||||
include Devise::Orm::MongoMapper::Hook
|
||||
end
|
||||
end
|
||||
29
lib/devise/orm/mongoid.rb
Normal file
29
lib/devise/orm/mongoid.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
module Devise
|
||||
module Orm
|
||||
module Mongoid
|
||||
module Hook
|
||||
def devise_modules_hook!
|
||||
extend Schema
|
||||
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_devise_schema(name, type, options={})
|
||||
type = Time if type == DateTime
|
||||
field name, { :type => type }.merge(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Mongoid::Document::ClassMethods.class_eval do
|
||||
include Devise::Models
|
||||
include Devise::Orm::Mongoid::Hook
|
||||
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,12 +1,69 @@
|
||||
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
|
||||
engine_name :devise
|
||||
config.devise = Devise
|
||||
|
||||
config.middleware.use Warden::Manager do |config|
|
||||
Devise.configure_warden(config)
|
||||
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_filters" do |app|
|
||||
app.config.filter_parameters += [:password, :password_confirmation]
|
||||
app.config.filter_parameters.uniq
|
||||
end
|
||||
|
||||
unless Rails.env.production?
|
||||
config.after_initialize do
|
||||
actions = [:confirmation_instructions, :reset_password_instructions, :unlock_instructions]
|
||||
|
||||
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' " \
|
||||
"are deprecated: #{keys.to_sentence}. Please move them to 'devise.failure' instead."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,12 +4,8 @@ module ActionDispatch::Routing
|
||||
# need devise_for mappings already declared to create filters and helpers.
|
||||
def finalize_with_devise!
|
||||
finalize_without_devise!
|
||||
return if Devise.mappings.empty?
|
||||
|
||||
Devise.configure_warden!
|
||||
ActionController::Base.send :include, Devise::Controllers::Helpers
|
||||
ActionController::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
|
||||
ActionView::Base.send :include, Devise::Controllers::UrlHelpers
|
||||
end
|
||||
alias_method_chain :finalize!, :devise
|
||||
end
|
||||
@@ -18,126 +14,235 @@ module ActionDispatch::Routing
|
||||
# Includes devise_for method for routes. This method is responsible to
|
||||
# generate all needed routes for devise, based on what modules you have
|
||||
# defined in your model.
|
||||
# Examples: Let's say you have an User model configured to use
|
||||
# authenticatable, confirmable and recoverable modules. After creating this
|
||||
# inside your routes:
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# Let's say you have an User model configured to use authenticatable,
|
||||
# confirmable and recoverable modules. After creating this inside your routes:
|
||||
#
|
||||
# devise_for :users
|
||||
#
|
||||
# this method is going to look inside your User model and create the
|
||||
# This method is going to look inside your User model and create the
|
||||
# needed routes:
|
||||
#
|
||||
# # Session routes for Authenticatable (default)
|
||||
# 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:
|
||||
#
|
||||
# * :class_name => setup a different class to be looked up by devise,
|
||||
# if it cannot be correctly find by the route name.
|
||||
#
|
||||
# devise_for :users, :class_name => 'Account'
|
||||
# devise_for :users, :class_name => 'Account'
|
||||
#
|
||||
# * :as => allows you to setup path name that will be used, as rails routes does.
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
# * :path => allows you to setup path name that will be used, as rails routes does.
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
#
|
||||
# devise_for :users, :as => 'accounts'
|
||||
# devise_for :users, :path => 'accounts'
|
||||
#
|
||||
# * :scope => setup the scope name. This is used as the instance variable name in controller,
|
||||
# as the name in routes and the scope given to warden. Defaults to the singular of the given name:
|
||||
# * :singular => setup the singular name for the given resource. This is used as the instance variable name in
|
||||
# controller, as the name in routes and the scope given to warden.
|
||||
#
|
||||
# devise_for :users, :scope => :account
|
||||
# devise_for :users, :singular => :user
|
||||
#
|
||||
# * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up,
|
||||
# :password, :confirmation, :unlock.
|
||||
#
|
||||
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
|
||||
#
|
||||
# * :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
|
||||
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
|
||||
#
|
||||
# * :controllers => the controller which should be used. All routes by default points to Devise controllers.
|
||||
# However, if you want them to point to custom controller, you should do:
|
||||
#
|
||||
# devise_for :users, :controllers => { :sessions => "users/sessions" }
|
||||
# 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::Mapping.new(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 to 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
|
||||
|
||||
Devise.default_scope ||= mapping.name
|
||||
Devise.mappings[mapping.name] = mapping
|
||||
routes = mapping.routes
|
||||
routes -= Array(options.delete(:skip)).map { |s| s.to_s.singularize.to_sym }
|
||||
|
||||
mapping.modules.each do |mod|
|
||||
send(mod, mapping, mapping.controllers) if self.respond_to?(mod, true)
|
||||
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 authenticatable(mapping, controllers)
|
||||
scope mapping.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:
|
||||
resource :session, :only => [], :controller => controllers[:sessions], :path => "" do
|
||||
get :new, :path => mapping.path_names[:sign_in], :as => "new"
|
||||
post :create, :path => mapping.path_names[:sign_in]
|
||||
get :destroy, :path => mapping.path_names[:sign_out], :as => "destroy"
|
||||
end
|
||||
end
|
||||
|
||||
def recoverable(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :password, :only => [:new, :create, :edit, :update], :as => mapping.path_names[:password], :controller => controllers[:passwords]
|
||||
end
|
||||
def devise_password(mapping, controllers) #:nodoc:
|
||||
resource :password, :only => [:new, :create, :edit, :update],
|
||||
:path => mapping.path_names[:password], :controller => controllers[:passwords]
|
||||
end
|
||||
|
||||
def confirmable(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :confirmation, :only => [:new, :create, :show], :as => 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 lockable(mapping, controllers)
|
||||
scope mapping.path, :name_prefix => mapping.name do
|
||||
resource :unlock, :only => [:new, :create, :show], :as => 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 registerable(mapping, controllers)
|
||||
scope :name_prefix => mapping.name do
|
||||
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :as => mapping.path[1..-1],
|
||||
: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
|
||||
|
||||
@@ -8,18 +8,115 @@ module Warden::Mixins::Common
|
||||
raw_session.clear
|
||||
end
|
||||
|
||||
def response
|
||||
@response ||= env['action_controller.instance'].response
|
||||
def cookies
|
||||
request.cookie_jar
|
||||
end
|
||||
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
|
||||
|
||||
unless Devise.rack_session?
|
||||
# We cannot use Rails Indifferent Hash because it messes up the flash object.
|
||||
class Devise::IndifferentHash < Hash
|
||||
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
||||
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
||||
|
||||
def [](key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
regular_writer(convert_key(key), value)
|
||||
end
|
||||
|
||||
alias_method :store, :[]=
|
||||
|
||||
def update(other_hash)
|
||||
other_hash.each_pair { |key, value| regular_writer(convert_key(key), value) }
|
||||
self
|
||||
end
|
||||
|
||||
alias_method :merge!, :update
|
||||
|
||||
def key?(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
alias_method :include?, :key?
|
||||
alias_method :has_key?, :key?
|
||||
alias_method :member?, :key?
|
||||
|
||||
def fetch(key, *extras)
|
||||
super(convert_key(key), *extras)
|
||||
end
|
||||
|
||||
def values_at(*indices)
|
||||
indices.collect {|key| self[convert_key(key)]}
|
||||
end
|
||||
|
||||
def merge(hash)
|
||||
self.dup.update(hash)
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def stringify_keys!; self end
|
||||
def stringify_keys; dup end
|
||||
|
||||
undef :symbolize_keys!
|
||||
def symbolize_keys; to_hash.symbolize_keys end
|
||||
|
||||
def to_options!; self end
|
||||
def to_hash; Hash.new.update(self) end
|
||||
|
||||
protected
|
||||
|
||||
def convert_key(key)
|
||||
key.kind_of?(Symbol) ? key.to_s : key
|
||||
end
|
||||
end
|
||||
|
||||
class ActionDispatch::Request
|
||||
def reset_session
|
||||
session.destroy if session && session.respond_to?(:destroy)
|
||||
self.session = {}
|
||||
@env['action_dispatch.request.flash_hash'] = nil
|
||||
end
|
||||
end
|
||||
|
||||
Warden::Manager.after_set_user :event => [:set_user, :authentication] do |record, warden, options|
|
||||
if options[:scope] && warden.authenticated?(options[:scope])
|
||||
request, flash = warden.request, warden.env['action_dispatch.request.flash_hash']
|
||||
backup = request.session.to_hash
|
||||
backup.delete("session_id")
|
||||
request.reset_session
|
||||
warden.env['action_dispatch.request.flash_hash'] = flash
|
||||
request.session = Devise::IndifferentHash.new.update(backup)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,63 +3,94 @@ module Devise
|
||||
# and overwrite the apply_schema method.
|
||||
module Schema
|
||||
|
||||
def authenticatable(*args)
|
||||
ActiveSupport::Deprecation.warn "t.authenticatable in migrations is deprecated. Please use t.database_authenticatable instead.", caller
|
||||
database_authenticatable(*args)
|
||||
end
|
||||
|
||||
# Creates email, encrypted_password and password_salt.
|
||||
#
|
||||
# == Options
|
||||
# * :null - When true, allow columns to be null.
|
||||
# * :encryptor - The encryptor going to be used, necessary for setting the proper encrypter password length.
|
||||
def authenticatable(options={})
|
||||
null = options[:null] || false
|
||||
default = options[:default]
|
||||
encryptor = options[:encryptor] || (respond_to?(:encryptor) ? self.encryptor : :sha1)
|
||||
# * :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.key?(:default) ? options[:default] : ("" if null == false)
|
||||
|
||||
apply_schema :email, String, :null => null, :default => default
|
||||
apply_schema :encrypted_password, String, :null => null, :default => default, :limit => Devise::ENCRYPTORS_LENGTH[encryptor]
|
||||
apply_schema :password_salt, String, :null => null, :default => default
|
||||
end
|
||||
if options.delete(:encryptor)
|
||||
ActiveSupport::Deprecation.warn ":encryptor as option is deprecated, simply remove it."
|
||||
end
|
||||
|
||||
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
|
||||
apply_schema :authentication_token, String, :limit => 20
|
||||
def token_authenticatable(options={})
|
||||
apply_devise_schema :authentication_token, String
|
||||
end
|
||||
|
||||
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
|
||||
def confirmable
|
||||
apply_schema :confirmation_token, String, :limit => 20
|
||||
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, :limit => 20
|
||||
apply_devise_schema :reset_password_token, String
|
||||
end
|
||||
|
||||
# Creates remember_token and remember_created_at.
|
||||
def rememberable
|
||||
apply_schema :remember_token, String, :limit => 20
|
||||
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
|
||||
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
|
||||
def lockable
|
||||
apply_schema :failed_attempts, Integer, :default => 0
|
||||
apply_schema :unlock_token, String, :limit => 20
|
||||
apply_schema :locked_at, DateTime
|
||||
# Creates failed_attempts, unlock_token and locked_at depending on the options given.
|
||||
#
|
||||
# == Options
|
||||
# * :unlock_strategy - The strategy used for unlock. Can be :time, :email, :both (default), :none.
|
||||
# If :email or :both, creates a unlock_token field.
|
||||
# * :lock_strategy - The strategy used for locking. Can be :failed_attempts (default) or :none.
|
||||
def lockable(options={})
|
||||
unlock_strategy = options[:unlock_strategy]
|
||||
unlock_strategy ||= self.unlock_strategy if respond_to?(:unlock_strategy)
|
||||
unlock_strategy ||= :both
|
||||
|
||||
lock_strategy = options[:lock_strategy]
|
||||
lock_strategy ||= self.lock_strategy if respond_to?(:lock_strategy)
|
||||
lock_strategy ||= :failed_attempts
|
||||
|
||||
if lock_strategy == :failed_attempts
|
||||
apply_devise_schema :failed_attempts, Integer, :default => 0
|
||||
end
|
||||
|
||||
if [:both, :email].include?(unlock_strategy)
|
||||
apply_devise_schema :unlock_token, String
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
@@ -2,35 +2,123 @@ require 'devise/strategies/base'
|
||||
|
||||
module Devise
|
||||
module Strategies
|
||||
# Default strategy for signing in a user, based on his email and password.
|
||||
# Redirects to sign_in page if it's not authenticated
|
||||
# This strategy should be used as basis for authentication strategies. It retrieves
|
||||
# parameters both from params or from http authorization headers. See database_authenticatable
|
||||
# for an example.
|
||||
class Authenticatable < Base
|
||||
attr_accessor :authentication_hash, :password
|
||||
|
||||
def valid?
|
||||
valid_controller? && valid_params? && mapping.to.respond_to?(:authenticate)
|
||||
valid_for_http_auth? || valid_for_params_auth?
|
||||
end
|
||||
|
||||
# Authenticate a user based on email and password params, returning to warden
|
||||
# success and the authenticated user if everything is okay. Otherwise redirect
|
||||
# to sign in page.
|
||||
def authenticate!
|
||||
if resource = mapping.to.authenticate(params[scope])
|
||||
success!(resource)
|
||||
private
|
||||
|
||||
# Simply invokes valid_for_authentication? with the given block and deal with the result.
|
||||
def validate(resource, &block)
|
||||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
case result
|
||||
when Symbol, String
|
||||
fail!(result)
|
||||
false
|
||||
else
|
||||
fail!(:invalid)
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
# 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
|
||||
|
||||
def valid_controller?
|
||||
mapping.controllers[:sessions] == params[:controller]
|
||||
end
|
||||
# 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)
|
||||
end
|
||||
|
||||
def valid_params?
|
||||
params[scope] && params[scope][:password].present?
|
||||
end
|
||||
# Check if the model accepts this strategy as http authenticatable.
|
||||
def http_authenticatable?
|
||||
mapping.to.http_authenticatable?(authenticatable_name)
|
||||
end
|
||||
|
||||
# Check if the model accepts this strategy as params authenticatable.
|
||||
def params_authenticatable?
|
||||
mapping.to.params_authenticatable?(authenticatable_name)
|
||||
end
|
||||
|
||||
# Extract the appropriate subhash for authentication from params.
|
||||
def params_auth_hash
|
||||
params[scope]
|
||||
end
|
||||
|
||||
# Extract a hash with attributes:values from the http params.
|
||||
def http_auth_hash
|
||||
keys = [authentication_keys.first, :password]
|
||||
Hash[*keys.zip(decode_credentials).flatten]
|
||||
end
|
||||
|
||||
# By default, a request is valid if the controller is allowed and the VERB is POST.
|
||||
def valid_request?
|
||||
valid_controller? && valid_verb?
|
||||
end
|
||||
|
||||
# Check if the controller is the one registered for authentication.
|
||||
def valid_controller?
|
||||
mapping.controllers[:sessions] == params[:controller]
|
||||
end
|
||||
|
||||
# Check if it was a POST request.
|
||||
def valid_verb?
|
||||
request.post?
|
||||
end
|
||||
|
||||
# If the request is valid, finally check if params_auth_hash returns a hash.
|
||||
def valid_params?
|
||||
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
|
||||
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/
|
||||
ActiveSupport::Base64.decode64($1).split(/:/, 2)
|
||||
end
|
||||
|
||||
# Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
|
||||
def with_authentication_hash(hash)
|
||||
self.authentication_hash = hash.slice(*authentication_keys)
|
||||
self.password = hash[:password]
|
||||
authentication_keys.all?{ |k| authentication_hash[k].present? }
|
||||
end
|
||||
|
||||
# Holds the authentication keys.
|
||||
def authentication_keys
|
||||
@authentication_keys ||= mapping.to.authentication_keys
|
||||
end
|
||||
|
||||
# Holds the authenticatable name for this class. Devise::Strategies::DatabaseAuthenticatable
|
||||
# becomes simply :database.
|
||||
def authenticatable_name
|
||||
@authenticatable_name ||=
|
||||
self.class.name.split("::").last.underscore.sub("_authenticatable", "").to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Warden::Strategies.add(:authenticatable, Devise::Strategies::Authenticatable)
|
||||
end
|
||||
@@ -2,8 +2,7 @@ module Devise
|
||||
module Strategies
|
||||
# Base strategy for Devise. Responsible for verifying correct scope and mapping.
|
||||
class Base < ::Warden::Strategies::Base
|
||||
# Checks if a valid scope was given for devise and find mapping based on
|
||||
# this scope.
|
||||
# Checks if a valid scope was given for devise and find mapping based on this scope.
|
||||
def mapping
|
||||
@mapping ||= begin
|
||||
mapping = Devise.mappings[scope]
|
||||
@@ -13,4 +12,4 @@ module Devise
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
lib/devise/strategies/database_authenticatable.rb
Normal file
21
lib/devise/strategies/database_authenticatable.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
require 'devise/strategies/authenticatable'
|
||||
|
||||
module Devise
|
||||
module Strategies
|
||||
# Default strategy for signing in a user, based on his email and password in the database.
|
||||
class DatabaseAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
|
||||
|
||||
if validate(resource){ resource.valid_password?(password) }
|
||||
resource.after_database_authentication
|
||||
success!(resource)
|
||||
elsif !halted?
|
||||
fail(:invalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Warden::Strategies.add(:database_authenticatable, Devise::Strategies::DatabaseAuthenticatable)
|
||||
@@ -1,47 +0,0 @@
|
||||
require 'devise/strategies/base'
|
||||
|
||||
module Devise
|
||||
module Strategies
|
||||
# Sign in an user using HTTP authentication.
|
||||
class HttpAuthenticatable < Base
|
||||
def valid?
|
||||
request.authorization && mapping.to.respond_to?(:authenticate_with_http)
|
||||
end
|
||||
|
||||
def authenticate!
|
||||
username, password = username_and_password
|
||||
|
||||
if resource = mapping.to.authenticate_with_http(username, password)
|
||||
success!(resource)
|
||||
else
|
||||
custom!([401, custom_headers, [response_body]])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def username_and_password
|
||||
decode_credentials(request).split(/:/, 2)
|
||||
end
|
||||
|
||||
def decode_credentials(request)
|
||||
ActiveSupport::Base64.decode64(request.authorization.split(' ', 2).last || '')
|
||||
end
|
||||
|
||||
def response_body
|
||||
body = "HTTP Basic: Access denied."
|
||||
method = :"to_#{request.format.to_sym}"
|
||||
{}.respond_to?(method) ? { :error => body }.send(method) : body
|
||||
end
|
||||
|
||||
def custom_headers
|
||||
{
|
||||
"Content-Type" => request.format.to_s,
|
||||
"WWW-Authenticate" => %(Basic realm="#{Devise.http_authentication_realm.gsub(/"/, "")}")
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Warden::Strategies.add(:http_authenticatable, Devise::Strategies::HttpAuthenticatable)
|
||||
@@ -4,31 +4,45 @@ module Devise
|
||||
module Strategies
|
||||
# Remember the user through the remember token. This strategy is responsible
|
||||
# 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*
|
||||
# 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_me_cookie.present? && mapping.to.respond_to?(:serialize_from_cookie)
|
||||
remember_cookie.present?
|
||||
end
|
||||
|
||||
# To authenticate a user we deserialize the cookie and attempt finding
|
||||
# the record in the database. If the attempt fails, we pass to another
|
||||
# strategy handle the authentication.
|
||||
def authenticate!
|
||||
if resource = mapping.to.serialize_from_cookie(remember_me_cookie)
|
||||
resource = mapping.to.serialize_from_cookie(*remember_cookie)
|
||||
|
||||
if validate(resource)
|
||||
success!(resource)
|
||||
else
|
||||
elsif !halted?
|
||||
cookies.delete(remember_key)
|
||||
pass
|
||||
end
|
||||
end
|
||||
|
||||
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_me_cookie
|
||||
@remember_me_cookie ||= request.cookies["remember_#{mapping.name}_token"]
|
||||
def remember_cookie
|
||||
@remember_cookie ||= cookies.signed[remember_key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,33 +2,45 @@ require 'devise/strategies/base'
|
||||
|
||||
module Devise
|
||||
module Strategies
|
||||
# Strategy for signing in a user, based on a authenticatable token.
|
||||
# Redirects to sign_in page if it's not authenticated.
|
||||
class TokenAuthenticatable < Base
|
||||
def valid?
|
||||
mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present?
|
||||
end
|
||||
|
||||
# Authenticate a user based on authenticatable token params, returning to warden
|
||||
# success and the authenticated user if everything is okay. Otherwise redirect
|
||||
# to sign in page.
|
||||
# Strategy for signing in a user, based on a authenticatable token. This works for both params
|
||||
# and http. For the former, all you need to do is to pass the params in the URL:
|
||||
#
|
||||
# http://myapp.example.com/?user_token=SECRET
|
||||
#
|
||||
# For HTTP, you can pass the token as username and blank password. Since some clients may require
|
||||
# a password, you can pass "X" as password and it will simply be ignored.
|
||||
class TokenAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
if resource = mapping.to.authenticate_with_token(params[scope] || params)
|
||||
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
||||
|
||||
if validate(resource)
|
||||
resource.after_token_authentication
|
||||
success!(resource)
|
||||
else
|
||||
fail!(:invalid_token)
|
||||
elsif !halted?
|
||||
fail(:invalid_token)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Detect authentication token in params: scoped or not.
|
||||
def authentication_token(scope)
|
||||
if params[scope]
|
||||
params[scope][mapping.to.token_authentication_key]
|
||||
else
|
||||
params[mapping.to.token_authentication_key]
|
||||
end
|
||||
# TokenAuthenticatable request is valid for any controller and any verb.
|
||||
def valid_request?
|
||||
true
|
||||
end
|
||||
|
||||
# Do not use remember_me behavir with token.
|
||||
def remember_me?
|
||||
false
|
||||
end
|
||||
|
||||
# Try both scoped and non scoped keys.
|
||||
def params_auth_hash
|
||||
params[scope] || params
|
||||
end
|
||||
|
||||
# Overwrite authentication keys to use token_authentication_key.
|
||||
def authentication_keys
|
||||
@authentication_keys ||= [mapping.to.token_authentication_key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ module Devise
|
||||
def initialize(controller)
|
||||
@controller = controller
|
||||
manager = Warden::Manager.new(nil) do |config|
|
||||
Devise.configure_warden(config)
|
||||
config.merge! Devise.warden_config
|
||||
end
|
||||
super(controller.request.env, manager)
|
||||
end
|
||||
@@ -24,6 +24,10 @@ module Devise
|
||||
catch_with_redirect { super }
|
||||
end
|
||||
|
||||
def user(*args)
|
||||
catch_with_redirect { super }
|
||||
end
|
||||
|
||||
def catch_with_redirect(&block)
|
||||
result = catch(:warden, &block)
|
||||
|
||||
@@ -36,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.pre4".freeze
|
||||
VERSION = "1.1.9".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
|
||||
@@ -1,19 +1,25 @@
|
||||
class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table(:<%= table_name %>) do |t|
|
||||
t.authenticatable :encryptor => :sha1, :null => false
|
||||
t.confirmable
|
||||
t.database_authenticatable :null => false
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
t.trackable
|
||||
# t.lockable
|
||||
|
||||
# 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,57 +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 :migration, :type => :boolean, :default => orm_has_migration?
|
||||
|
||||
def invoke_orm_model
|
||||
if File.exists?(File.join(destination_root, model_path))
|
||||
say "* Model already exists. Adding Devise behavior."
|
||||
else
|
||||
invoke "model", [name], :migration => false
|
||||
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:
|
||||
# :http_authenticatable, :token_authenticatable, :lockable, :timeoutable and :activatable
|
||||
devise :registerable, :authenticatable, :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_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",
|
||||
: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
|
||||
@@ -1,95 +0,0 @@
|
||||
# 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|
|
||||
# Configure the e-mail address which will be shown in DeviseMailer.
|
||||
config.mailer_sender = "please-change-me@config-initializers-devise.com"
|
||||
|
||||
# ==> Configuration for :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"
|
||||
|
||||
# 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
|
||||
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
|
||||
# config.encryptor = :sha1
|
||||
|
||||
# Configure which keys are used when authenticating an user. By default is
|
||||
# just :email. You can configure it to use [:username, :subdomain], so for
|
||||
# authenticating an user, both parameters are required. Remember that those
|
||||
# parameters are used only when authenticating and not when retrieving from
|
||||
# session. If you need permissions, you should implement that in a before filter.
|
||||
# config.authentication_keys = [ :email ]
|
||||
|
||||
# The realm used in Http Basic Authentication
|
||||
# config.http_authentication_realm = "Application"
|
||||
|
||||
# ==> Configuration for :confirmable
|
||||
# The time you want give to your user to confirm his account. During this time
|
||||
# he will be able to access your application without confirming. Default is nil.
|
||||
# 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
|
||||
|
||||
# ==> Configuration for :timeoutable
|
||||
# The time you want to timeout the user session without activity. After this
|
||||
# time the user will be asked for credentials again.
|
||||
# config.timeout_in = 10.minutes
|
||||
|
||||
# ==> Configuration for :lockable
|
||||
# Number of authentication tries before locking an account.
|
||||
# config.maximum_attempts = 20
|
||||
|
||||
# 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)
|
||||
# :both = enables both strategies
|
||||
# config.unlock_strategy = :both
|
||||
|
||||
# Time interval to unlock the account if :time is enabled as unlock_strategy.
|
||||
# config.unlock_in = 1.hour
|
||||
|
||||
# ==> Configuration for :token_authenticatable
|
||||
# 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), :mongo_mapper
|
||||
# (requires mongo_ext installed) and :data_mapper (experimental).
|
||||
require 'devise/orm/active_record'
|
||||
|
||||
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
||||
# "sessions/users/new". It's turned off by default because it's slower if you
|
||||
# are using only default views.
|
||||
# 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.
|
||||
# config.default_scope = :user
|
||||
|
||||
# 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
|
||||
#
|
||||
# config.warden do |manager|
|
||||
# manager.oauth(:twitter) do |twitter|
|
||||
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
|
||||
# twitter.consumer_key = <YOUR CONSUMER KEY>
|
||||
# twitter.options :site => 'http://twitter.com'
|
||||
# end
|
||||
# manager.default_strategies.unshift :twitter_oauth
|
||||
# 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,15 +0,0 @@
|
||||
class DeviseViewsGenerator < Rails::Generators::Base
|
||||
desc "Copies all Devise views to your application."
|
||||
|
||||
def self.source_root
|
||||
@_devise_source_root ||= File.expand_path("../../../../app/views", __FILE__)
|
||||
end
|
||||
|
||||
def copy_views
|
||||
directory "devise"
|
||||
end
|
||||
|
||||
def say_restart_server
|
||||
say "Views copied. Please restart your server."
|
||||
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.
|
||||
@@ -16,4 +16,10 @@ Some setup you must do manually if you haven't yet:
|
||||
|
||||
root :to => "home#index"
|
||||
|
||||
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
|
||||
For example:
|
||||
|
||||
<p class="notice"><%= notice %></p>
|
||||
<p class="alert"><%= alert %></p>
|
||||
|
||||
===============================================================================
|
||||
142
lib/generators/templates/devise.rb
Normal file
142
lib/generators/templates/devise.rb
Normal file
@@ -0,0 +1,142 @@
|
||||
# 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
|
||||
# authenticating an user, both parameters are required. Remember that those
|
||||
# parameters are used only when authenticating and not when retrieving from
|
||||
# session. If you need permissions, you should implement that in a before filter.
|
||||
# config.authentication_keys = [ :email ]
|
||||
|
||||
# Tell if authentication through request.params is enabled. True by default.
|
||||
# config.params_authenticatable = true
|
||||
|
||||
# Tell if authentication through HTTP Basic Auth is enabled. False by default.
|
||||
# config.http_authenticatable = false
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
# 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 = :bcrypt
|
||||
|
||||
# Setup a pepper to generate the encrypted password.
|
||||
config.pepper = <%= ActiveSupport::SecureRandom.hex(64).inspect %>
|
||||
|
||||
# ==> Configuration for :confirmable
|
||||
# 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
|
||||
|
||||
# Regex to use to validate the email address
|
||||
# config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
|
||||
|
||||
# ==> Configuration for :timeoutable
|
||||
# The time you want to timeout the user session without activity. After this
|
||||
# time the user will be asked for credentials again.
|
||||
# config.timeout_in = 10.minutes
|
||||
|
||||
# ==> Configuration for :lockable
|
||||
# Defines which strategy will be used to lock an account.
|
||||
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
|
||||
# :none = No lock strategy. You should handle locking by yourself.
|
||||
# config.lock_strategy = :failed_attempts
|
||||
|
||||
# Defines which strategy will be used to unlock an account.
|
||||
# :email = Sends an unlock link to the user email
|
||||
# :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
|
||||
|
||||
# Number of authentication tries before locking an account if lock_strategy
|
||||
# is failed attempts.
|
||||
# config.maximum_attempts = 20
|
||||
|
||||
# Time interval to unlock the account if :time is enabled as unlock_strategy.
|
||||
# config.unlock_in = 1.hour
|
||||
|
||||
# ==> Configuration for :token_authenticatable
|
||||
# Defines name of the authentication token params key
|
||||
# config.token_authentication_key = :auth_token
|
||||
|
||||
# ==> Scopes configuration
|
||||
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
||||
# "users/sessions/new". It's turned off by default because it's slower if you
|
||||
# are using only default views.
|
||||
# config.scoped_views = true
|
||||
|
||||
# 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
|
||||
#
|
||||
# config.warden do |manager|
|
||||
# manager.oauth(:twitter) do |twitter|
|
||||
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
|
||||
# twitter.consumer_key = <YOUR CONSUMER KEY>
|
||||
# twitter.options :site => 'http://twitter.com'
|
||||
# end
|
||||
# manager.default_strategies(:scope => :user).unshift :twitter_oauth
|
||||
# end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
require 'ostruct'
|
||||
|
||||
class MockController < ApplicationController
|
||||
@@ -23,6 +23,10 @@ class MockController < ApplicationController
|
||||
"http"
|
||||
end
|
||||
|
||||
def script_name
|
||||
""
|
||||
end
|
||||
|
||||
def symbolized_path_parameters
|
||||
{}
|
||||
end
|
||||
@@ -49,9 +53,11 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.signed_in?(:my_scope)
|
||||
end
|
||||
|
||||
test 'proxy current_admin to authenticate with admin scope' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :admin)
|
||||
@controller.current_admin
|
||||
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_user to authenticate with user scope' do
|
||||
@@ -59,16 +65,31 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.current_user
|
||||
end
|
||||
|
||||
test 'proxy user_authenticate! to authenticate with user scope' do
|
||||
test 'proxy current_admin to authenticate with admin scope' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :admin)
|
||||
@controller.current_admin
|
||||
end
|
||||
|
||||
test 'proxy current_publisher_account to authenticate with namespaced publisher account scope' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :publisher_account)
|
||||
@controller.current_publisher_account
|
||||
end
|
||||
|
||||
test 'proxy authenticate_user! to authenticate with user scope' do
|
||||
@mock_warden.expects(:authenticate!).with(:scope => :user)
|
||||
@controller.authenticate_user!
|
||||
end
|
||||
|
||||
test 'proxy admin_authenticate! to authenticate with admin scope' do
|
||||
test 'proxy authenticate_admin! to authenticate with admin scope' do
|
||||
@mock_warden.expects(:authenticate!).with(:scope => :admin)
|
||||
@controller.authenticate_admin!
|
||||
end
|
||||
|
||||
test 'proxy authenticate_publisher_account! to authenticate with namespaced publisher account scope' do
|
||||
@mock_warden.expects(:authenticate!).with(:scope => :publisher_account)
|
||||
@controller.authenticate_publisher_account!
|
||||
end
|
||||
|
||||
test 'proxy user_signed_in? to authenticate? with user scope' do
|
||||
@mock_warden.expects(:authenticate?).with(:scope => :user)
|
||||
@controller.user_signed_in?
|
||||
@@ -79,6 +100,11 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.admin_signed_in?
|
||||
end
|
||||
|
||||
test 'proxy publisher_account_signed_in? to authenticate? with namespaced publisher account scope' do
|
||||
@mock_warden.expects(:authenticate?).with(:scope => :publisher_account)
|
||||
@controller.publisher_account_signed_in?
|
||||
end
|
||||
|
||||
test 'proxy user_session to session scope in warden' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :user).returns(true)
|
||||
@mock_warden.expects(:session).with(:user).returns({})
|
||||
@@ -91,6 +117,12 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
@controller.admin_session
|
||||
end
|
||||
|
||||
test 'proxy publisher_account_session from namespaced scope to session scope in warden' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :publisher_account).returns(true)
|
||||
@mock_warden.expects(:session).with(:publisher_account).returns({})
|
||||
@controller.publisher_account_session
|
||||
end
|
||||
|
||||
test 'sign in proxy to set_user on warden' do
|
||||
user = User.new
|
||||
@mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
|
||||
@@ -115,22 +147,31 @@ 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"
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
assert_equal "/foo.bar", @controller.stored_location_for(:user)
|
||||
end
|
||||
|
||||
test 'stored location for accepts a resource as argument' do
|
||||
assert_nil @controller.stored_location_for(:user)
|
||||
@controller.session[:"user.return_to"] = "/foo.bar"
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
assert_equal "/foo.bar", @controller.stored_location_for(User.new)
|
||||
end
|
||||
|
||||
test 'stored location cleans information after reading' do
|
||||
@controller.session[:"user.return_to"] = "/foo.bar"
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
assert_equal "/foo.bar", @controller.stored_location_for(:user)
|
||||
assert_nil @controller.session[:"user.return_to"]
|
||||
assert_nil @controller.session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'after sign in path defaults to root path if none by was specified for the given scope' do
|
||||
@@ -141,6 +182,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)
|
||||
@@ -148,7 +197,8 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
|
||||
test 'sign in and redirect uses the stored location' do
|
||||
user = User.new
|
||||
@controller.session[:"user.return_to"] = "/foo.bar"
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
@mock_warden.expects(:user).with(:user).returns(nil)
|
||||
@mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
|
||||
@controller.expects(:redirect_to).with("/foo.bar")
|
||||
@controller.sign_in_and_redirect(user)
|
||||
@@ -156,15 +206,18 @@ class ControllerAuthenticableTest < ActionController::TestCase
|
||||
|
||||
test 'sign in and redirect uses the configured after sign in path' do
|
||||
admin = Admin.new
|
||||
@mock_warden.expects(:user).with(:admin).returns(nil)
|
||||
@mock_warden.expects(:set_user).with(admin, :scope => :admin).returns(true)
|
||||
@controller.expects(:redirect_to).with(admin_root_path)
|
||||
@controller.sign_in_and_redirect(admin)
|
||||
end
|
||||
|
||||
test 'only redirect if skip is given' do
|
||||
test 'sign in and redirect does not sign in again if user is already signed' do
|
||||
admin = Admin.new
|
||||
@mock_warden.expects(:user).with(:admin).returns(admin)
|
||||
@mock_warden.expects(:set_user).never
|
||||
@controller.expects(:redirect_to).with(admin_root_path)
|
||||
@controller.sign_in_and_redirect(:admin, admin, true)
|
||||
@controller.sign_in_and_redirect(admin)
|
||||
end
|
||||
|
||||
test 'sign out and redirect uses the configured after sign out path' do
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class MyController < ApplicationController
|
||||
include Devise::Controllers::InternalHelpers
|
||||
@@ -7,35 +7,31 @@ end
|
||||
class HelpersTest < ActionController::TestCase
|
||||
tests MyController
|
||||
|
||||
test 'get resource name from request path' do
|
||||
@request.path = '/users/session'
|
||||
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 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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class RoutesTest < ActionController::TestCase
|
||||
tests ApplicationController
|
||||
|
||||
def test_path_and_url(name, prepend_path=nil)
|
||||
def assert_path_and_url(name, prepend_path=nil)
|
||||
@request.path = '/users/session'
|
||||
prepend_path = "#{prepend_path}_" if prepend_path
|
||||
|
||||
@@ -29,19 +29,30 @@ class RoutesTest < ActionController::TestCase
|
||||
|
||||
|
||||
test 'should alias session to mapped user session' do
|
||||
test_path_and_url :session
|
||||
test_path_and_url :session, :new
|
||||
test_path_and_url :session, :destroy
|
||||
assert_path_and_url :session
|
||||
assert_path_and_url :session, :new
|
||||
assert_path_and_url :session, :destroy
|
||||
end
|
||||
|
||||
test 'should alias password to mapped user password' do
|
||||
test_path_and_url :password
|
||||
test_path_and_url :password, :new
|
||||
test_path_and_url :password, :edit
|
||||
assert_path_and_url :password
|
||||
assert_path_and_url :password, :new
|
||||
assert_path_and_url :password, :edit
|
||||
end
|
||||
|
||||
test 'should alias confirmation to mapped user confirmation' do
|
||||
test_path_and_url :confirmation
|
||||
test_path_and_url :confirmation, :new
|
||||
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
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
module Devise
|
||||
def self.clean_warden_config!
|
||||
@warden_config = nil
|
||||
def self.yield_and_restore
|
||||
@@warden_configured = nil
|
||||
c, b = @@warden_config, @@warden_config_block
|
||||
yield
|
||||
ensure
|
||||
@@warden_config, @@warden_config_block = c, b
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,28 +24,21 @@ class DeviseTest < ActiveSupport::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
test 'warden manager configuration' do
|
||||
config = Warden::Config.new
|
||||
Devise.configure_warden(config)
|
||||
|
||||
assert_equal Devise::FailureApp, config.failure_app
|
||||
assert_equal [:rememberable, :token_authenticatable, :http_authenticatable, :authenticatable], config.default_strategies
|
||||
assert_equal :user, config.default_scope
|
||||
assert config.silence_missing_strategies?
|
||||
test 'stores warden configuration' do
|
||||
assert_equal Devise::FailureApp, Devise.warden_config.failure_app
|
||||
assert_equal :user, Devise.warden_config.default_scope
|
||||
end
|
||||
|
||||
test 'warden manager user configuration through a block' do
|
||||
begin
|
||||
Devise.yield_and_restore do
|
||||
@executed = false
|
||||
Devise.warden do |config|
|
||||
@executed = true
|
||||
assert_kind_of Warden::Config, config
|
||||
end
|
||||
|
||||
Devise.configure_warden(Warden::Config.new)
|
||||
Devise.configure_warden!
|
||||
assert @executed
|
||||
ensure
|
||||
Devise.clean_warden_config!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,8 +49,8 @@ class DeviseTest < ActiveSupport::TestCase
|
||||
assert_not defined?(Devise::Models::Coconut)
|
||||
Devise::ALL.delete(:coconut)
|
||||
|
||||
assert_nothing_raised(Exception) { Devise.add_module(:banana, :strategy => true) }
|
||||
assert_equal 1, Devise::STRATEGIES.select { |v| v == :banana }.size
|
||||
assert_nothing_raised(Exception) { Devise.add_module(:banana, :strategy => :fruits) }
|
||||
assert_equal :fruits, Devise::STRATEGIES[:banana]
|
||||
Devise::ALL.delete(:banana)
|
||||
Devise::STRATEGIES.delete(:banana)
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Encryptors < ActiveSupport::TestCase
|
||||
test 'should match a password created by authlogic' do
|
||||
authlogic = "b623c3bc9c775b0eb8edb218a382453396fec4146422853e66ecc4b6bc32d7162ee42074dcb5f180a770dc38b5df15812f09bbf497a4a1b95fe5e7d2b8eb7eb4"
|
||||
@@ -21,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
|
||||
|
||||
@@ -1,46 +1,123 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
require 'ostruct'
|
||||
|
||||
class FailureTest < ActiveSupport::TestCase
|
||||
def self.context(name, &block)
|
||||
instance_eval(&block)
|
||||
end
|
||||
|
||||
def call_failure(env_params={})
|
||||
env = {
|
||||
'warden.options' => { :scope => :user },
|
||||
'REQUEST_URI' => 'http://test.host/',
|
||||
'HTTP_HOST' => 'test.host',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'rack.session' => {}
|
||||
'warden.options' => { :scope => :user },
|
||||
'rack.session' => {},
|
||||
'action_dispatch.request.formats' => Array(env_params.delete('formats') || Mime::HTML),
|
||||
'rack.input' => "",
|
||||
'warden' => OpenStruct.new(:message => nil)
|
||||
}.merge!(env_params)
|
||||
Devise::FailureApp.call(env)
|
||||
|
||||
@response = Devise::FailureApp.call(env).to_a
|
||||
@request = ActionDispatch::Request.new(env)
|
||||
end
|
||||
|
||||
test 'return 302 status' do
|
||||
assert_equal 302, call_failure.first
|
||||
context 'When redirecting' do
|
||||
test 'return 302 status' do
|
||||
call_failure
|
||||
assert_equal 302, @response.first
|
||||
end
|
||||
|
||||
test 'return to the default redirect location' do
|
||||
call_failure
|
||||
assert_equal 'You need to sign in or sign up before continuing.', @request.flash[:alert]
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second['Location']
|
||||
end
|
||||
|
||||
test 'uses the proxy failure message as symbol' do
|
||||
call_failure('warden' => OpenStruct.new(:message => :test))
|
||||
assert_equal 'test', @request.flash[:alert]
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
|
||||
end
|
||||
|
||||
test 'uses the proxy failure message as string' do
|
||||
call_failure('warden' => OpenStruct.new(:message => 'Hello world'))
|
||||
assert_equal 'Hello world', @request.flash[:alert]
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second["Location"]
|
||||
end
|
||||
|
||||
test 'set content type to default text/html' do
|
||||
call_failure
|
||||
assert_equal 'text/html; charset=utf-8', @response.second['Content-Type']
|
||||
end
|
||||
|
||||
test 'setup a default message' do
|
||||
call_failure
|
||||
assert_match /You are being/, @response.last.body
|
||||
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
|
||||
|
||||
test 'return to the default redirect location' do
|
||||
assert_equal 'http://test.host/users/sign_in?unauthenticated=true', call_failure.second['Location']
|
||||
context 'For HTTP request' do
|
||||
test 'return 401 status' do
|
||||
call_failure('formats' => :xml)
|
||||
assert_equal 401, @response.first
|
||||
end
|
||||
|
||||
test 'return WWW-authenticate headers' do
|
||||
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('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
|
||||
|
||||
test 'uses the proxy failure message' do
|
||||
warden = OpenStruct.new(:message => :test)
|
||||
location = call_failure('warden' => warden).second['Location']
|
||||
assert_equal 'http://test.host/users/sign_in?test=true', location
|
||||
end
|
||||
|
||||
test 'uses the given message' do
|
||||
warden = OpenStruct.new(:message => 'Hello world')
|
||||
location = call_failure('warden' => warden).second['Location']
|
||||
assert_equal 'http://test.host/users/sign_in?message=Hello+world', location
|
||||
end
|
||||
|
||||
test 'set content type to default text/html' do
|
||||
assert_equal 'text/html; charset=utf-8', call_failure.second['Content-Type']
|
||||
end
|
||||
|
||||
test 'setup a default message' do
|
||||
assert_match /You are being/, call_failure.last.body
|
||||
assert_match /redirected/, call_failure.last.body
|
||||
assert_match /\?unauthenticated=true/, call_failure.last.body
|
||||
context 'With recall' do
|
||||
test 'calls the original controller' do
|
||||
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)
|
||||
assert @response.third.body.include?('<h2>Sign in</h2>')
|
||||
assert @response.third.body.include?('Invalid email or password.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
33
test/indifferent_hash.rb
Normal file
33
test/indifferent_hash.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
require 'test_helper'
|
||||
|
||||
class IndifferentHashTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@hash = Devise::IndifferentHash.new
|
||||
end
|
||||
|
||||
test "it overwrites getter and setter" do
|
||||
@hash[:foo] = "bar"
|
||||
assert_equal "bar", @hash["foo"]
|
||||
assert_equal "bar", @hash[:foo]
|
||||
|
||||
@hash["foo"] = "baz"
|
||||
assert_equal "baz", @hash["foo"]
|
||||
assert_equal "baz", @hash[:foo]
|
||||
end
|
||||
|
||||
test "it overwrites update" do
|
||||
@hash.update :foo => "bar"
|
||||
assert_equal "bar", @hash["foo"]
|
||||
assert_equal "bar", @hash[:foo]
|
||||
|
||||
@hash.update "foo" => "baz"
|
||||
assert_equal "baz", @hash["foo"]
|
||||
assert_equal "baz", @hash[:foo]
|
||||
end
|
||||
|
||||
test "it returns a Hash on to_hash" do
|
||||
@hash[:foo] = "bar"
|
||||
assert_equal Hash["foo", "bar"], @hash.to_hash
|
||||
assert_kind_of Hash, @hash.to_hash
|
||||
end
|
||||
end if defined?(Devise::IndifferentHash)
|
||||
@@ -1,6 +1,15 @@
|
||||
require 'test/test_helper'
|
||||
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
|
||||
@@ -29,7 +38,7 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as user should not touch admin authentication' do
|
||||
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
|
||||
|
||||
@@ -38,7 +47,7 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
assert warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign out as admin should not touch user authentication' do
|
||||
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
|
||||
|
||||
@@ -47,20 +56,68 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
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(:unauthenticated => true)
|
||||
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(:unauthenticated => true)
|
||||
assert_redirected_to new_admin_session_path
|
||||
end
|
||||
|
||||
test 'signed in as admin should be able to access admin actions' do
|
||||
@@ -107,46 +164,11 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationTest < 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
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'sign in with invalid email should return to sign in form with error message' do
|
||||
sign_in_as_admin do
|
||||
fill_in 'email', :with => 'wrongemail@test.com'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid email or password'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign in with invalid pasword should return to sign in form with error message' do
|
||||
sign_in_as_admin do
|
||||
fill_in 'password', :with => 'abcdef'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid email or password'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'error message is configurable by resource name' do
|
||||
store_translations :en, :devise => { :sessions => { :admin => { :invalid => "Invalid credentials" } } } do
|
||||
sign_in_as_admin do
|
||||
fill_in 'password', :with => 'abcdef'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid credentials'
|
||||
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(:unauthenticated => true)
|
||||
warden_path = new_admin_session_path
|
||||
assert_redirected_to warden_path
|
||||
|
||||
get warden_path
|
||||
@@ -155,60 +177,79 @@ class AuthenticationTest < ActionController::IntegrationTest
|
||||
|
||||
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"]
|
||||
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(:unauthenticated => true)
|
||||
assert_equal users_path, session[:"user.return_to"]
|
||||
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"]
|
||||
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(:unauthenticated => true)
|
||||
assert_equal expire_user_path(create_user), session[:"user.return_to"]
|
||||
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(:unauthenticated => true)
|
||||
assert_equal users_path, session[:"user.return_to"]
|
||||
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"]
|
||||
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 '/users/sign_in?unauthenticated=true'
|
||||
assert_redirected_to new_user_session_path
|
||||
end
|
||||
|
||||
test 'allows session to be set by a given scope' do
|
||||
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
|
||||
|
||||
# Scoped views
|
||||
test 'session id is changed on sign in' do
|
||||
get '/users'
|
||||
session_id = request.session["session_id"]
|
||||
|
||||
get '/users'
|
||||
assert_equal session_id, request.session["session_id"]
|
||||
|
||||
sign_in_as_user
|
||||
assert_not_equal session_id, request.session["session_id"]
|
||||
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
|
||||
@@ -226,7 +267,7 @@ class AuthenticationTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
assert_match /Special user view/, response.body
|
||||
assert !Devise::PasswordsController.scoped_views
|
||||
assert !Devise::PasswordsController.scoped_views?
|
||||
ensure
|
||||
Devise::SessionsController.send :remove_instance_variable, :@scoped_views
|
||||
end
|
||||
@@ -248,16 +289,20 @@ class AuthenticationTest < ActionController::IntegrationTest
|
||||
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
|
||||
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
|
||||
|
||||
# Custom controller
|
||||
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'
|
||||
@@ -265,16 +310,46 @@ class AuthenticationTest < ActionController::IntegrationTest
|
||||
assert_contain 'Welcome to "sessions/new" view!'
|
||||
end
|
||||
|
||||
# Access
|
||||
test 'render 404 on roles without permission' do
|
||||
get '/admin_area/password/new', {}, "action_dispatch.show_exceptions" => true
|
||||
assert_response :not_found
|
||||
assert_not_contain 'Send me reset password instructions'
|
||||
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
|
||||
get '/sign_in', {}, "action_dispatch.show_exceptions" => true
|
||||
assert_response :not_found
|
||||
assert_not_contain 'Sign in'
|
||||
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", :with => "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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class ConfirmationTest < ActionController::IntegrationTest
|
||||
|
||||
@@ -11,45 +11,52 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
visit new_user_session_path
|
||||
click_link 'Didn\'t receive confirmation instructions?'
|
||||
click_link "Didn't receive confirmation instructions?"
|
||||
|
||||
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 '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Confirmation token(.*)invalid/
|
||||
end
|
||||
|
||||
test 'user with valid confirmation token should be able to confirm an account' do
|
||||
user = create_user(:confirm => false)
|
||||
assert_not user.confirmed?
|
||||
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
assert_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 '#errorExplanation'
|
||||
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
|
||||
|
||||
@@ -88,9 +95,9 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
|
||||
test 'error message is configurable by resource name' do
|
||||
store_translations :en, :devise => {
|
||||
:sessions => { :admin => { :unconfirmed => "Not confirmed user" } }
|
||||
:failure => { :user => { :unconfirmed => "Not confirmed user" } }
|
||||
} do
|
||||
get new_admin_session_path(:unconfirmed => true)
|
||||
sign_in_as_user(:confirm => false)
|
||||
assert_contain 'Not confirmed user'
|
||||
end
|
||||
end
|
||||
|
||||
38
test/integration/database_authenticatable_test.rb
Normal file
38
test/integration/database_authenticatable_test.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require 'test_helper'
|
||||
|
||||
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
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'sign in with invalid email should return to sign in form with error message' do
|
||||
sign_in_as_admin do
|
||||
fill_in 'email', :with => 'wrongemail@test.com'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid email or password'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign in with invalid pasword should return to sign in form with error message' do
|
||||
sign_in_as_admin do
|
||||
fill_in 'password', :with => 'abcdef'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid email or password'
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'error message is configurable by resource name' do
|
||||
store_translations :en, :devise => { :failure => { :admin => { :invalid => "Invalid credentials" } } } do
|
||||
sign_in_as_admin do
|
||||
fill_in 'password', :with => 'abcdef'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid credentials'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,12 +1,11 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
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", headers["Content-Type"]
|
||||
assert response.body.include?("<error>HTTP Basic: Access denied.</error>")
|
||||
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
|
||||
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,33 @@ 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
|
||||
|
||||
test 'test request with oauth2 header doesnt get mistaken for basic authentication' do
|
||||
swap Devise, :http_authenticatable => true do
|
||||
add_oauth2_header
|
||||
assert_equal 401, status
|
||||
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
|
||||
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
|
||||
|
||||
# Sign in with oauth2 token. This is just to test that it isn't misinterpreted as basic authentication
|
||||
def add_oauth2_header
|
||||
user = create_user
|
||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => "OAuth #{ActiveSupport::Base64.encode64("#{user.email}:123456")}"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class LockTest < ActionController::IntegrationTest
|
||||
|
||||
@@ -11,7 +11,7 @@ class LockTest < ActionController::IntegrationTest
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
visit new_user_session_path
|
||||
click_link 'Didn\'t receive unlock instructions?'
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend unlock instructions'
|
||||
@@ -26,7 +26,7 @@ class LockTest < ActionController::IntegrationTest
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
visit new_user_session_path
|
||||
click_link 'Didn\'t receive unlock instructions?'
|
||||
click_link "Didn't receive unlock instructions?"
|
||||
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend unlock instructions'
|
||||
@@ -36,31 +36,45 @@ class LockTest < ActionController::IntegrationTest
|
||||
assert_equal 0, ActionMailer::Base.deliveries.size
|
||||
end
|
||||
|
||||
test 'unlocked pages should not be available if email strategy is disabled' do
|
||||
visit "/admins/sign_in"
|
||||
|
||||
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_have_selector '#errorExplanation'
|
||||
assert_current_url '/users/unlock?unlock_token=invalid_token'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Unlock token(.*)invalid/
|
||||
end
|
||||
|
||||
test "locked user should be able to unlock account" do
|
||||
user = create_user(:locked => true)
|
||||
assert user.locked?
|
||||
assert user.access_locked?
|
||||
|
||||
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.locked?
|
||||
assert_not user.reload.access_locked?
|
||||
end
|
||||
|
||||
test "sign in user automatically after unlocking it's account" do
|
||||
user = create_user(:locked => true)
|
||||
visit_user_unlock_with_token(user.unlock_token)
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
@@ -71,11 +85,23 @@ class LockTest < ActionController::IntegrationTest
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test "user should not send a new e-mail if already locked" do
|
||||
user = create_user(:locked => true)
|
||||
user.failed_attempts = User.maximum_attempts + 1
|
||||
user.save!
|
||||
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
sign_in_as_user(:password => "invalid")
|
||||
assert_contain 'Your account is locked.'
|
||||
assert ActionMailer::Base.deliveries.empty?
|
||||
end
|
||||
|
||||
test 'error message is configurable by resource name' do
|
||||
store_translations :en, :devise => {
|
||||
:sessions => { :admin => { :locked => "You are locked!" } }
|
||||
:failure => { :user => { :locked => "You are locked!" } }
|
||||
} do
|
||||
get new_admin_session_path(:locked => true)
|
||||
user = sign_in_as_user(:locked => true)
|
||||
assert_contain 'You are locked!'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class PasswordTest < ActionController::IntegrationTest
|
||||
|
||||
def visit_new_password_path
|
||||
visit new_user_session_path
|
||||
click_link 'Forgot password?'
|
||||
click_link 'Forgot your password?'
|
||||
end
|
||||
|
||||
def request_forgot_password(&block)
|
||||
@@ -77,7 +77,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'passwords/edit'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain /Reset password token(.*)invalid/
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
end
|
||||
@@ -91,7 +91,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
|
||||
assert_response :success
|
||||
assert_template 'passwords/edit'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain 'Password doesn\'t match confirmation'
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
end
|
||||
@@ -113,7 +113,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
fill_in 'Password confirmation', :with => 'other_password'
|
||||
end
|
||||
assert_response :success
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_not user.reload.valid_password?('987654321')
|
||||
|
||||
reset_password :reset_password_token => user.reload.reset_password_token, :visit => false
|
||||
@@ -134,7 +134,7 @@ class PasswordTest < ActionController::IntegrationTest
|
||||
request_forgot_password
|
||||
reset_password :reset_password_token => user.reload.reset_password_token
|
||||
|
||||
assert_current_path new_user_session_path(:unconfirmed => true)
|
||||
assert_equal new_user_session_path, @request.path
|
||||
assert !warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'test/test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class RegistrationTest < ActionController::IntegrationTest
|
||||
|
||||
@@ -28,9 +28,9 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
fill_in 'password confirmation', :with => 'new_user123'
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_contain 'You have signed up successfully.'
|
||||
assert_contain 'You have signed up successfully'
|
||||
assert_contain 'Sign in'
|
||||
assert_not_contain 'Confirm your account'
|
||||
assert_not_contain 'You have to confirm your account before continuing'
|
||||
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
@@ -48,7 +48,7 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_template 'registrations/new'
|
||||
assert_have_selector '#errorExplanation'
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain "Email is invalid"
|
||||
assert_contain "Password doesn't match confirmation"
|
||||
assert_nil User.first
|
||||
@@ -65,15 +65,17 @@ 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
|
||||
|
||||
test 'a guest should not be able to change account' do
|
||||
get edit_user_registration_path
|
||||
assert_redirected_to new_user_session_path(:unauthenticated => true)
|
||||
assert_redirected_to new_user_session_path
|
||||
follow_redirect!
|
||||
assert_contain 'You need to sign in or sign up before continuing.'
|
||||
end
|
||||
|
||||
test 'a signed in user should not be able to access sign up' do
|
||||
@@ -90,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
|
||||
@@ -111,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
|
||||
@@ -121,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
|
||||
@@ -136,4 +150,4 @@ class RegistrationTest < ActionController::IntegrationTest
|
||||
|
||||
assert User.all.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user