Compare commits

...

95 Commits

Author SHA1 Message Date
José Valim
36906a03f3 Update gemspec with 1.1.4 release. 2010-11-26 13:21:57 +01:00
Carlos Antonio da Silva
d6af3d7dc6 Make sure to load test gems only in Devise test env 2010-11-26 00:29:33 -02:00
Carlos Antonio da Silva
767331657b Use UTC for Mongoid timestamps, so it conforms with AR. 2010-11-26 00:02:50 -02:00
Carlos Antonio da Silva
55860675c2 Bring Gemfile config from master, adding mongo configs. Also bump mongo related and webrat gem versions 2010-11-25 23:38:37 -02:00
Carlos Antonio da Silva
da3af3f341 Configure Gemfile to use Rails 3.0.x 2010-11-25 22:56:54 -02:00
José Valim
0f46ed3a33 Fix indifferent access on session issue. 2010-11-25 00:04:47 +01:00
José Valim
8d33e8f313 Prepare for 1.1.4 2010-11-20 23:51:27 +01:00
José Valim
fb1e9bc8a7 Avoid session fixation attacks. 2010-11-20 23:51:09 +01:00
Carlos Antonio da Silva
4310ad798c Bump webrat to 0.7.1
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-11-20 23:48:23 +01:00
José Valim
8def06e1a6 Update the README to point to the proper version. 2010-09-24 09:40:21 +02:00
José Valim
3b0aaaaae8 Release a new Devise version with several bug fixes. 2010-09-24 09:38:56 +02:00
Fred Wu
cb83c66139 Updated the views generator to respect the rails :template_engine option.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:32:38 +02:00
José Valim
2104397bee :default options is used, closes #452
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:31:19 +02:00
James Miller
374948cf4b Fix for failed first-ever logins on PostgreSQL where column default is nil
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:30:33 +02:00
Pelle Braendgaard
7c51ec0742 Improved test thanks to Jose Valim.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:30:18 +02:00
Pelle Braendgaard
ed05225dd5 The http authentication code was not checking for the type of authentication in the Authentication header.
This caused issues with OAuth header authentication.
Please note I have added a test but I'm not sure it works right as it doesn't fails without the change :-)
But it does fix failures in the oauth-plugin provider specs using devise.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:30:11 +02:00
Thibaud Guillaume-Gentil
c32cb3da6c Avoid BCrypt::Errors::InvalidSalt: invalid salt
when password_salt is nil.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 09:29:35 +02:00
Martin Davidsson
70c32e48fc Incorporate feedback from carlosantoniodasilva and update rememberable
tests
2010-09-24 00:15:25 -03:00
Martin Davidsson
522219e5db Merge options hash instead of overwriting it
The forgetable hook will delete cookies based on the :scope in an
options hash but it was overwriting the options and setting them to
either an empty hash or a hash with a single :domain key. Because the
:scope was lost, the hook was trying to delete the 'remember__token'
instead of the more typical 'remember_user_token' cookie.
2010-09-24 00:15:25 -03:00
takahashim
a843b74c86 fix TypeError in test_sign_in_with_script_name(AuthenticationOthersTest) 2010-09-16 12:08:50 -03:00
Carlos Antonio da Silva
56834284bd Update Gemfile to use Rails 3.0 final, all tests green 2010-08-29 23:27:06 -03:00
José Valim
5b762ff85a Release 1.1.2. 2010-08-25 08:48:02 -03:00
José Valim
73822fe109 Update Gemfile. 2010-08-25 08:48:02 -03:00
José Valim
85a4aa2afa Ensure routes works for all rails 3 versions. 2010-08-25 08:48:02 -03:00
José Valim
c49fe8c6d7 Release v1.1.1. 2010-08-25 08:48:01 -03:00
Carlos Antonio da Silva
a59e20e3bb Add some tests to helper creation using namespaces, to better show how it works. 2010-08-02 08:50:48 -03:00
José Valim
5ef88a8fe6 Fix generators bug. 2010-07-27 16:19:11 +02:00
José Valim
9ab64c53f4 Release 1.1.0. 2010-07-26 20:25:28 +02:00
José Valim
c5999c8f61 Tests green on mongoid as well. 2010-07-26 20:25:02 +02:00
José Valim
680f2612f4 Update CHANGELOG. 2010-07-26 11:52:05 +02:00
José Valim
81620fecab More about extend remember period feature. 2010-07-23 23:57:31 +02:00
Trevor Turk
2939a61a49 documentation tweaks for extend_remember_period 2010-07-24 01:06:10 +08:00
José Valim
058d433f28 Add extend_remember_period, closes #340. 2010-07-23 16:32:22 +02:00
Stefan Huber
5aeb8cf1cf small documentation fix 2010-07-23 01:33:08 +08:00
José Valim
abfd7e5a4b Warn in case you are using the previous session schema, closes #386 2010-07-19 00:11:51 +02:00
José Valim
869c658e3b Always loop before generating a token. 2010-07-18 23:32:56 +02:00
José Valim
5e64699a5f Add filters as convenient default. 2010-07-18 12:17:04 +02:00
Jinzhu
aecc014d33 Attributes for devise generator 2010-07-17 15:09:01 +08:00
José Valim
55fd7e3b0a Consider ApplicationController url_options in for PathChecker. 2010-07-16 08:40:21 +02:00
José Valim
b4794e041b Save confirmation token to the database, if one does not exist but was requested, closes #377 2010-07-14 18:03:34 +02:00
Carlos Antonio da Silva
4f6113ab68 Fix docs about after_sign_in_path_for and routes 2010-07-13 22:22:26 -03:00
José Valim
05d23f1a00 Do not check the constant, otherwise class renaming will trigger errors as well. 2010-07-12 10:42:02 +02:00
José Valim
e567c00dd8 Store classes as string in session, to avoid serialization and stale data issues, closes #356 2010-07-12 07:48:19 +02:00
José Valim
ebe3e791d6 Email should be case insensitive, closes #372 2010-07-12 07:29:45 +02:00
José Valim
2602ef41cf Do not add unlock routes unless unlock strategy is email or both, closes #373 2010-07-12 07:24:21 +02:00
José Valim
a87bc4a861 Also pass stretches to salt generation. 2010-07-12 06:59:49 +02:00
José Valim
eca511a8f2 Use confirmed_at as flag. 2010-07-08 08:21:14 +02:00
José Valim
9c5ff02ff1 Update CHANGELOG and tidy up tests. 2010-07-07 21:32:13 +02:00
James Pellow
9f29ca480b Add http_authenticatable_on_xhr option
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-07 21:26:29 +02:00
James Pellow
b9df42c350 Add tests for http_authenticatable_on_xhr option 2010-07-08 03:21:13 +08:00
José Valim
bd0e2a3180 devise_for now accepts a block. All routes inside the block uses the scope defined by devise_for.
You are now allowed to do:

  devise_for :users do
    # Non conventional sign_in route
    get "/sign_in" => "devise/sessions#new"
  end

And it should work as expected.
2010-07-07 10:51:14 +02:00
José Valim
750560ae87 Ensure method is always POST on new.html.erb forms, closes #365. Also, start to remove usage of assert_template. 2010-07-06 16:01:22 +02:00
José Valim
e2a4ebce4a Consider script name in PathChecker. 2010-07-06 16:01:22 +02:00
Carlos Antonio da Silva
77b7692b57 Regenerate devise initializar and get rid of some deprecation warnings from Devise and Rails. 2010-07-06 08:40:32 -03:00
José Valim
ae6322efb5 No longer retrieve the user from paths, but use the env hash. This change deprecates use_default_scope.
If you have non conventional routes and want to specify the scope for a controller, you can do that at the router level:

  as :user do
    get "/sign_in", :to => "devise/session#new"
  end

This is saying: when accessing "/sign_in", devise should use the user scope. Meaning that users signed through that form will be signed to the user scope.
2010-07-06 01:33:32 +02:00
Carlos Antonio da Silva
238226e33a Adding a small note about security and issues 2010-07-05 14:26:58 -03:00
José Valim
96a9c88420 Improve docs on finders after taking a look at the wiki. 2010-07-05 19:11:37 +02:00
José Valim
dd612753f9 Extract redirect_url from failure app to its own method. 2010-07-05 15:22:44 +02:00
José Valim
35923c9c69 Move template_paths to its own module. 2010-07-05 13:27:15 +02:00
José Valim
f54013a181 Do not hardcode to devise/mailer in order to allow inheritance to work. 2010-07-05 10:05:08 +02:00
José Valim
1cf77028c1 Bump version to 1.1.0 but do not release yet. We are only using this as flag for those using Devise as git with bundler due to the latest changes. 2010-07-04 17:34:33 +02:00
José Valim
7774accb6c Remove data_mapper support.
Devise 1.1.0 will be released soon. This new version will support activerecord and mongoid as default ORMs. From now on, Devise will prefer ORM extensions as gems since this is the best way to handle dependencies.

For example, to allow Devise to work with Datamapper, it requires at least activemodel, dm-rails and dm-timestamps. If the ORM support comes from Devise gem, we cannot add dm-rails and dm-timestamps as dependencies, relying on the developer and documentation to find these out and install them.

Other ORMs may still be added to Devise, as long as they are supported by the community, extend Devise test suite to have all tests passing and they necessarily use ActiveModel::Validations.
2010-07-04 17:22:57 +02:00
José Valim
6c49b428b3 Add flexibility to devise generators by using ORM hooks. 2010-07-04 17:15:24 +02:00
José Valim
7113dfe93a Ensure to convert template engine to string to properly match haml, closes #359 2010-07-04 13:13:00 +02:00
José Valim
4083d679d4 Add documentation to the new :module method. 2010-07-04 13:11:04 +02:00
José Valim
7a1adbb61e Improve integration of devise with new router scope. 2010-07-04 11:53:12 +02:00
José Valim
18cccae82f Update bundler, Rails and improve tests for previous commit. 2010-07-02 08:12:00 +02:00
klacointe
e9fbb3d7ef fix AbstractController::ActionNotFound when use
route with specific format (ie xml, json...)
2010-07-02 13:25:33 +08:00
José Valim
04c25539c2 Add remember_me to attr_accessible on generation. 2010-07-01 12:38:48 -07:00
José Valim
55bc0ace5a Update CHANGELOG. 2010-07-01 13:58:08 +02:00
José Valim
421256d294 Devise should respect script_name and path_info contracts. This closes #331, a long standing bug with Passenger. 2010-07-01 13:50:05 +02:00
José Valim
8e3ef2a620 Add entry to CHANGELOG. 2010-06-30 12:49:41 +02:00
Trevor Turk
aefcd53765 more tests for remember_across_browsers
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-30 12:42:59 +02:00
Trevor Turk
0eb9208503 changelog note for remember_across_browsers
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-30 12:42:49 +02:00
Trevor Turk
8824b767f3 remember_across_browsers option for rememberable module
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-30 12:42:42 +02:00
José Valim
2103a673f0 Allow devise_for to be scoped with the scope method. This commit requires latest commits in Rails master. 2010-06-30 12:41:44 +02:00
José Valim
78e7642bd2 Tests green again. 2010-06-29 21:41:34 +02:00
José Valim
8526056bde Merge branch 'master' of github.com:plataformatec/devise 2010-06-29 12:02:06 +02:00
José Valim
4b272767d6 Fix a bug in Devise::TestHelpers where current_user was returning a Response object for non active accounts, closes #341. 2010-06-29 11:52:10 +02:00
José Valim
84c34ff0c4 Be more specific about master. 2010-06-28 12:25:03 -07:00
Maxim Filatov
4db3ac820b sign_out_all_scopes is false by default 2010-06-25 02:29:52 +08:00
Maxim Filatov
503d27f2e1 Renew devise:install due to sign_out_everybody => sign_out_all_scopes 2010-06-25 02:29:50 +08:00
Denis Lifanov
2475faf9c7 warden.logout(*scopes) instead of warden.logout(*Devise.mappings.keys) 2010-06-25 02:29:49 +08:00
Denis Lifanov
819db39263 simplification (sign_out_everybody => sign_out_all_scopes) 2010-06-25 02:29:48 +08:00
Maxim Filatov
f864259f1e Added config.sign_out_scoped to devise:install 2010-06-25 02:29:47 +08:00
Maxim Filatov
12ae21117c Missed rdoc 2010-06-25 02:29:46 +08:00
Denis Lifanov
1a224c7486 move sign_out_scoped logic to the Devise::SessionsController#destroy 2010-06-25 02:29:45 +08:00
Denis Lifanov
f10b747f7f Devise.sign_out_scoped option added 2010-06-25 02:29:43 +08:00
Denis Lifanov
8370006591 we should not fetch Devise.mappings.keys twice in #sign_out_everybody 2010-06-25 02:29:42 +08:00
Denis Lifanov
1924a915a8 sign_out_everybody helper (as a convenient proxy to warden) 2010-06-25 02:29:41 +08:00
José Valim
7a45043bc8 Be more friendly if the user goes ahead and adds devise_for :users before defining the model. 2010-06-24 16:51:30 +02:00
Rob Holland
ad63e25c89 config.load_paths is now config.autoload_paths 2010-06-24 19:28:34 +08:00
José Valim
895a7a4951 Use Rails master. 2010-06-23 12:52:44 +02:00
José Valim
b8c2bbe73c Revert "Revert "Track Deprecation of :name_prefix in Rails 3 RC""
Devise master will now follow Rails master.

This reverts commit b2c2cb272f.
2010-06-23 12:42:23 +02:00
José Valim
b76bf10203 Update README. 2010-06-23 12:42:13 +02:00
89 changed files with 1416 additions and 715 deletions

View File

@@ -1,3 +1,49 @@
== 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
* Rememberable module allows user to be remembered across browsers and is enabled by default (by github.com/trevorturk)
* Rememberable module allows you to activate the period the remember me token is extended (by github.com/trevorturk)
* devise_for can now be used together with scope method in routes but with a few limitations (check the documentation)
* Support `as` or `devise_scope` in the router to specify controller access scope
* HTTP Basic Auth can now be disabled/enabled for xhr(ajax) requests using http_authenticatable_on_xhr option (by github.com/pellja)
* bug fix
* Fix a bug in Devise::TestHelpers where current_user was returning a Response object for non active accounts
* Devise should respect script_name and path_info contracts
* Fix a bug when accessing a path with (.:format) (by github.com/klacointe)
* Do not add unlock routes unless unlock strategy is email or both
* Email should be case insensitive
* Store classes as string in session, to avoid serialization and stale data issues
* deprecations
* use_default_scope is deprecated and has no effect. Use :as or :devise_scope in the router instead
== 1.1.rc2
* enhancements
@@ -16,7 +62,7 @@
* devise.mailer.user.confirmations_instructions now should be devise.mailer.confirmations_instructions.user_subject
* Generators now use Rails 3 syntax (devise:install) instead of devise_install
== 1.1.rc
== 1.1.rc1
* enhancements
* Rails 3 compatibility
@@ -29,7 +75,7 @@
* E-mails now use any template available in the filesystem. Easy to create multipart e-mails
* E-mails asks headers_for in the model to set the proper headers
* Allow to specify haml in devise_views
* Compatibility with Datamapper and Mongoid
* 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

40
Gemfile
View File

@@ -1,29 +1,27 @@
source "http://rubygems.org"
# Need to install Rails from source
gem "rails", "3.0.0.beta4"
gem "warden", "0.10.7"
gem "sqlite3-ruby"
gem "webrat", "0.7.0"
gem "mocha", :require => false
gem "bcrypt-ruby", :require => "bcrypt"
gemspec
if RUBY_VERSION < '1.9'
gem "ruby-debug", ">= 0.10.3"
gem "rails", "~> 3.0.0"
group :test do
gem "webrat", "0.7.2", :require => false
gem "mocha", :require => false
end
group :mongoid do
gem "mongo"
gem "mongoid", :git => "git://github.com/durran/mongoid.git"
gem "bson_ext"
platforms :jruby do
gem 'activerecord-jdbcsqlite3-adapter'
end
group :data_mapper do
gem 'dm-core', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-core'
gem 'dm-migrations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-migrations'
gem 'dm-sqlite-adapter', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-sqlite-adapter'
gem 'dm-validations', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-validations'
gem 'dm-serializer', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-serializer'
gem 'dm-timestamps', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-timestamps'
gem 'dm-rails', '~> 1.0.0', :git => 'git://github.com/datamapper/dm-rails'
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

117
Gemfile.lock Normal file
View File

@@ -0,0 +1,117 @@
PATH
remote: .
specs:
devise (1.1.4)
bcrypt-ruby (~> 2.1.2)
warden (~> 1.0.2)
GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
actionmailer (3.0.3)
actionpack (= 3.0.3)
mail (~> 2.2.9)
actionpack (3.0.3)
activemodel (= 3.0.3)
activesupport (= 3.0.3)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.4)
rack (~> 1.2.1)
rack-mount (~> 0.6.13)
rack-test (~> 0.5.6)
tzinfo (~> 0.3.23)
activemodel (3.0.3)
activesupport (= 3.0.3)
builder (~> 2.1.2)
i18n (~> 0.4)
activerecord (3.0.3)
activemodel (= 3.0.3)
activesupport (= 3.0.3)
arel (~> 2.0.2)
tzinfo (~> 0.3.23)
activeresource (3.0.3)
activemodel (= 3.0.3)
activesupport (= 3.0.3)
activesupport (3.0.3)
arel (2.0.4)
bcrypt-ruby (2.1.2)
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.4.2)
linecache (0.43)
mail (2.2.10)
activesupport (>= 2.3.6)
i18n (~> 0.4.1)
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.6)
rack (>= 1.0)
rails (3.0.3)
actionmailer (= 3.0.3)
actionpack (= 3.0.3)
activerecord (= 3.0.3)
activeresource (= 3.0.3)
activesupport (= 3.0.3)
bundler (~> 1.0)
railties (= 3.0.3)
railties (3.0.3)
actionpack (= 3.0.3)
activesupport (= 3.0.3)
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.23)
warden (1.0.2)
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
bcrypt-ruby (~> 2.1.2)
bson_ext (= 1.1.2)
devise!
mocha
mongo (= 1.1.2)
mongoid (= 2.0.0.beta.20)
rails (~> 3.0.0)
ruby-debug (>= 0.10.3)
sqlite3-ruby
warden (~> 1.0.2)
webrat (= 0.7.2)

View File

@@ -22,19 +22,11 @@ Right now it's composed of 11 modules:
== Installation
=== Rails 3 beta 4
Devise 1.1 supports Rails 3 and is NOT backward compatible. You can use the latest Rails 3 beta gem with Devise latest gem:
To use Devise with Rails 3 beta 4, please use it straight from the git repository, by adding it to your Gemfile:
gem install devise --version=1.1.3
gem "devise", :git => "git://github.com/plataformatec/devise.git"
Then follow the same steps as below.
=== Rails 3 beta 3
Devise master branch now supports Rails 3 and is NOT backward compatible. You can use the latest Rails 3 beta gem with Devise latest gem:
gem install devise --version=1.1.rc1
If you want to use Rails master (from git repository) you need to use Devise from git repository and vice-versa.
After you install Devise and add it to your Gemfile, you need to run the generator:
@@ -46,11 +38,11 @@ The generator will install an initializer which describes ALL Devise's configura
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
== Rails 2.3
If you want to use the Rails 2.3.x version, you should do:
gem install devise --version=1.0.7
gem install devise --version=1.0.8
And please check the README at the v1.0 branch since this one is based on Rails 3:
@@ -283,6 +275,16 @@ Please consult their respective documentation for more information and requireme
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)

View File

@@ -45,7 +45,7 @@ begin
s.authors = ['José Valim', 'Carlos Antônio']
s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"]
s.extra_rdoc_files = FileList["[A-Z]*"] - %w(Gemfile Rakefile)
s.add_dependency("warden", "~> 0.10.7")
s.add_dependency("warden", "~> 1.0.2")
s.add_dependency("bcrypt-ruby", "~> 2.1.2")
end

View File

@@ -1,5 +1,4 @@
class Devise::UnlocksController < ApplicationController
prepend_before_filter :ensure_email_as_unlock_strategy
prepend_before_filter :require_no_authentication
include Devise::Controllers::InternalHelpers
@@ -32,10 +31,4 @@ class Devise::UnlocksController < ApplicationController
render_with_scope :new
end
end
protected
def ensure_email_as_unlock_strategy
raise ActionController::UnknownAction unless resource_class.unlock_strategy_enabled?(:email)
end
end

View File

@@ -22,14 +22,11 @@ class Devise::Mailer < ::ActionMailer::Base
@devise_mapping = Devise.mappings[@scope_name]
@resource = instance_variable_set("@#{@devise_mapping.name}", record)
template_path = ["devise/mailer"]
template_path.unshift "#{@devise_mapping.plural}/mailer" if self.class.scoped_views?
headers = {
:subject => translate(@devise_mapping, action),
:from => mailer_sender(@devise_mapping),
:to => record.email,
:template_path => template_path
:template_path => template_paths
}
headers.merge!(record.headers_for(action)) if record.respond_to?(:headers_for)
@@ -44,6 +41,12 @@ class Devise::Mailer < ::ActionMailer::Base
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:
#

View File

@@ -1,6 +1,6 @@
<h2>Resend confirmation instructions</h2>
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name)) do |f| %>
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :email %><br />

View File

@@ -1,6 +1,6 @@
<h2>Forgot your password?</h2>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name)) do |f| %>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :email %><br />

View File

@@ -1,6 +1,6 @@
<h2>Resend unlock instructions</h2>
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name)) do |f| %>
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :email %><br />

View File

@@ -5,15 +5,16 @@
Gem::Specification.new do |s|
s.name = %q{devise}
s.version = "1.1.rc2"
s.version = "1.1.4"
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-06-23}
s.date = %q{2010-11-26}
s.description = %q{Flexible authentication solution for Rails with Warden}
s.email = %q{contact@plataformatec.com.br}
s.extra_rdoc_files = [
"CHANGELOG.rdoc",
"Gemfile.lock",
"MIT-LICENSE",
"README.rdoc",
"TODO"
@@ -21,6 +22,7 @@ Gem::Specification.new do |s|
s.files = [
"CHANGELOG.rdoc",
"Gemfile",
"Gemfile.lock",
"MIT-LICENSE",
"README.rdoc",
"Rakefile",
@@ -77,7 +79,6 @@ Gem::Specification.new do |s|
"lib/devise/models/validatable.rb",
"lib/devise/modules.rb",
"lib/devise/orm/active_record.rb",
"lib/devise/orm/data_mapper.rb",
"lib/devise/orm/mongoid.rb",
"lib/devise/path_checker.rb",
"lib/devise/rails.rb",
@@ -91,15 +92,17 @@ Gem::Specification.new do |s|
"lib/devise/strategies/token_authenticatable.rb",
"lib/devise/test_helpers.rb",
"lib/devise/version.rb",
"lib/generators/devise/devise/devise_generator.rb",
"lib/generators/devise/devise/templates/migration.rb",
"lib/generators/devise/install/install_generator.rb",
"lib/generators/devise/install/templates/README",
"lib/generators/devise/install/templates/devise.rb",
"lib/generators/devise/views/views_generator.rb",
"lib/generators/devise_generator.rb",
"lib/generators/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/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"]
@@ -139,7 +142,6 @@ Gem::Specification.new do |s|
"test/models/validatable_test.rb",
"test/models_test.rb",
"test/orm/active_record.rb",
"test/orm/data_mapper.rb",
"test/orm/mongoid.rb",
"test/rails_app/app/active_record/admin.rb",
"test/rails_app/app/active_record/shim.rb",
@@ -147,11 +149,10 @@ Gem::Specification.new do |s|
"test/rails_app/app/controllers/admins_controller.rb",
"test/rails_app/app/controllers/application_controller.rb",
"test/rails_app/app/controllers/home_controller.rb",
"test/rails_app/app/controllers/publisher/registrations_controller.rb",
"test/rails_app/app/controllers/publisher/sessions_controller.rb",
"test/rails_app/app/controllers/sessions_controller.rb",
"test/rails_app/app/controllers/users_controller.rb",
"test/rails_app/app/data_mapper/admin.rb",
"test/rails_app/app/data_mapper/shim.rb",
"test/rails_app/app/data_mapper/user.rb",
"test/rails_app/app/helpers/application_helper.rb",
"test/rails_app/app/mongoid/admin.rb",
"test/rails_app/app/mongoid/shim.rb",
@@ -184,14 +185,14 @@ Gem::Specification.new do |s|
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<warden>, ["~> 0.10.7"])
s.add_runtime_dependency(%q<warden>, ["~> 1.0.2"])
s.add_runtime_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
else
s.add_dependency(%q<warden>, ["~> 0.10.7"])
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.10.7"])
s.add_dependency(%q<warden>, ["~> 1.0.2"])
s.add_dependency(%q<bcrypt-ruby>, ["~> 2.1.2"])
end
end

View File

@@ -69,6 +69,10 @@ module Devise
mattr_accessor :http_authenticatable
@@http_authenticatable = true
# If http authentication is used for ajax requests. True by default.
mattr_accessor :http_authenticatable_on_xhr
@@http_authenticatable_on_xhr = true
# If params authenticatable is enabled by default.
mattr_accessor :params_authenticatable
@@params_authenticatable = true
@@ -85,10 +89,18 @@ module Devise
mattr_accessor :password_length
@@password_length = 6..20
# Time interval where the remember me token is valid.
# The time the user will be remembered without asking for credentials again.
mattr_accessor :remember_for
@@remember_for = 2.weeks
# If true, a valid remember token can be re-used between multiple browsers.
mattr_accessor :remember_across_browsers
@@remember_across_browsers = true
# If true, extends the user's remember period when remembered via cookie.
mattr_accessor :extend_remember_period
@@extend_remember_period = false
# Time interval you can access your account before confirming your account.
mattr_accessor :confirm_within
@@confirm_within = 0.days
@@ -133,10 +145,6 @@ module Devise
mattr_accessor :unlock_in
@@unlock_in = 1.hour
# Tell when to use the default scope, if one cannot be found from routes.
mattr_accessor :use_default_scope
@@use_default_scope = false
# The default scope which is used by warden.
mattr_accessor :default_scope
@@default_scope = nil
@@ -149,6 +157,7 @@ module Devise
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
# Which formats should be treated as navigational.
mattr_accessor :navigational_formats
@@navigational_formats = [:html]
@@ -157,6 +166,17 @@ module Devise
@@warden_config = nil
@@warden_config_block = nil
# When set to true, signing out an user signs out all other scopes.
mattr_accessor :sign_out_all_scopes
@@sign_out_all_scopes = false
def self.use_default_scope=(*)
ActiveSupport::Deprecation.warn "config.use_default_scope is deprecated and removed from Devise. " <<
"If you are using non conventional routes in Devise, all you need to do is to pass the devise " <<
"scope in the router DSL:\n\n as :user do\n get \"sign_in\", :to => \"devise/sessions\"\n end\n\n" <<
"The method :as is also aliased to :devise_scope. Choose the one you prefer.", caller
end
# Default way to setup Devise. Run rails generate devise_install to create
# a fresh initializer with all configuration values.
def self.setup
@@ -174,10 +194,8 @@ module Devise
end
self.mailer = "Devise::Mailer"
# Register a model in Devise. You can call this manually if you don't want
# to use devise routes. Check devise_for in routes to know which options
# are available.
def self.add_model(resource, options)
# 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
@@ -247,6 +265,11 @@ module Devise
@@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! #:nodoc:

View File

@@ -64,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:
#
@@ -73,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
@@ -86,13 +96,13 @@ module Devise
#
# map.user_root '/users', :controller => 'users' # creates user_root_path
#
# map.resources :users do |users|
# users.root # creates user_root_path
# map.namespace :user do |user|
# user.root :controller => 'users' # creates user_root_path
# end
#
#
# If none of these are defined, root_path is used. However, if this default
# is not enough, you can customize it, for example:
# If the resource root path is not defined, root_path is used. However,
# if this default is not enough, you can customize it, for example:
#
# def after_sign_in_path_for(resource)
# if resource.is_a?(User) && resource.can_publish?
@@ -104,7 +114,7 @@ module Devise
#
def after_sign_in_path_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
home_path = :"#{scope}_root_path"
home_path = "#{scope}_root_path"
respond_to?(home_path, true) ? send(home_path) : root_path
end
@@ -164,7 +174,11 @@ module Devise
# after_sign_out_path_for.
def sign_out_and_redirect(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
sign_out(scope)
if Devise.sign_out_all_scopes
sign_out_all_scopes
else
sign_out(scope)
end
redirect_to after_sign_out_path_for(scope)
end

View File

@@ -8,7 +8,6 @@ module Devise
include Devise::Controllers::ScopedViews
included do
unloadable
helper DeviseHelper
helpers = %w(resource scope_name resource_name
@@ -38,11 +37,7 @@ module Devise
# Attempt to find the mapped route for devise based on request path
def devise_mapping
@devise_mapping ||= begin
mapping = Devise::Mapping.find_by_path(request.path)
mapping ||= Devise.mappings[Devise.default_scope] if Devise.use_default_scope
mapping
end
@devise_mapping ||= request.env["devise.mapping"]
end
# Overwrites devise_controller? to return true
@@ -54,8 +49,7 @@ module Devise
# Checks whether it's a devise mapped resource or not.
def is_devise_resource? #:nodoc:
raise ActionController::UnknownAction unless devise_mapping &&
devise_mapping.allowed_controllers.include?(controller_path)
raise ActionController::UnknownAction unless devise_mapping
end
# Sets the resource creating an instance variable

View File

@@ -12,7 +12,7 @@ module Devise
raise NotImplemented
end
def self.salt
def self.salt(stretches)
Devise.friendly_token
end
end

View File

@@ -11,8 +11,8 @@ module Devise
::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

View File

@@ -47,7 +47,7 @@ module Devise
def redirect
store_location!
flash[:alert] = i18n_message unless flash[:notice]
redirect_to send(:"new_#{scope}_session_path")
redirect_to redirect_url
end
protected
@@ -63,8 +63,12 @@ module Devise
end
end
def redirect_url
send(:"new_#{scope}_session_path")
end
def http_auth?
!Devise.navigational_formats.include?(request.format.to_sym) || request.xhr?
!Devise.navigational_formats.include?(request.format.to_sym) || (request.xhr? && Devise.http_authenticatable_on_xhr)
end
def http_auth_body

View File

@@ -5,7 +5,7 @@
Warden::Manager.before_logout do |record, warden, options|
if record.respond_to?(:forget_me!)
record.forget_me! unless record.frozen?
options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
warden.cookies.delete("remember_#{options[:scope]}_token", options)
cookie_options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
warden.cookies.delete("remember_#{options[:scope]}_token", cookie_options)
end
end

View File

@@ -9,7 +9,7 @@ module Devise
super
if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
resource.remember_me!
resource.remember_me!(extend_remember_period?)
configuration = {
:value => resource.class.serialize_into_cookie(resource),
@@ -24,6 +24,14 @@ module Devise
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

View File

@@ -22,19 +22,9 @@ module Devise
# # is the modules included in the class
#
class Mapping #:nodoc:
attr_reader :singular, :plural, :path, :controllers, :path_names, :path_prefix, :class_name
attr_reader :singular, :plural, :path, :controllers, :path_names, :class_name
alias :name :singular
# Loop through all mappings looking for a map that matches with the requested
# path (ie /users/sign_in). If a path prefix is given, it's taken into account.
def self.find_by_path(path)
Devise.mappings.each_value do |mapping|
route = path.split("/")[mapping.segment_position]
return mapping if route && mapping.path == route.to_sym
end
nil
end
# Receives an object and find a scope for it. If a scope cannot be found,
# raises an error. If a symbol is given, it's considered to be the scope.
def self.find_scope!(duck)
@@ -51,31 +41,22 @@ module Devise
end
def initialize(name, options) #:nodoc:
if as = options.delete(:as)
ActiveSupport::Deprecation.warn ":as is deprecated, please use :path instead."
options[:path] ||= as
end
@plural = (options[:as] ? "#{options[:as]}_#{name}" : name).to_sym
@singular = (options[:singular] || @plural.to_s.singularize).to_sym
if scope = options.delete(:scope)
ActiveSupport::Deprecation.warn ":scope is deprecated, please use :singular instead."
options[:singular] ||= scope
end
@plural = name.to_sym
@path = (options.delete(:path) || name).to_sym
@singular = (options.delete(:singular) || name.to_s.singularize).to_sym
@class_name = (options.delete(:class_name) || name.to_s.classify).to_s
@class_name = (options[:class_name] || name.to_s.classify).to_s
@ref = ActiveSupport::Dependencies.ref(@class_name)
@path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
@path = (options[:path] || name).to_s
@path_prefix = options[:path_prefix]
@controllers = Hash.new { |h,k| h[k] = "devise/#{k}" }
@controllers.merge!(options.delete(:controllers) || {})
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 = Hash.new { |h,k| h[k] = k.to_s }
@path_names.merge!(:registration => "")
@path_names.merge!(options.delete(:path_names) || {})
@path_names.merge!(options[:path_names] || {})
end
# Return modules for the mapping.
@@ -96,30 +77,14 @@ module Devise
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
end
# Keep a list of allowed controllers for this mapping. It's useful to ensure
# that an Admin cannot access the registrations controller unless it has
# :registerable in the model.
def allowed_controllers
@allowed_controllers ||= begin
canonical = CONTROLLERS.values_at(*self.modules).compact
@controllers.values_at(*canonical)
end
end
# Return in which position in the path prefix devise should find the as mapping.
def segment_position
self.path_prefix.count("/")
end
# Returns the raw path using path_prefix and as.
def full_path
path_prefix + path.to_s
end
def authenticatable?
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
end
def fullpath
"#{@path_prefix}/#{@path}".squeeze("/")
end
# Create magic predicates for verifying what module is activated by this map.
# Example:
#

View File

@@ -112,6 +112,14 @@ module Devise
record
end
# Generate a token by looping and ensuring does not already exist.
def generate_token(column)
loop do
token = Devise.friendly_token
break token unless find(:first, :conditions => { column => token })
end
end
end
end
end

View File

@@ -45,12 +45,12 @@ module Devise
# Verifies whether a user is confirmed or not
def confirmed?
persisted? && !confirmed_at.nil?
!!confirmed_at
end
# Send confirmation instructions by email
def send_confirmation_instructions
generate_confirmation_token if self.confirmation_token.nil?
generate_confirmation_token! if self.confirmation_token.nil?
::Devise.mailer.confirmation_instructions(self).deliver
end
@@ -75,15 +75,14 @@ module Devise
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now
@skip_confirmation = true
self.confirmed_at = Time.now
end
protected
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!@skip_confirmation
!confirmed?
end
# Checks if the confirmation for the user is within the limit time.
@@ -128,6 +127,10 @@ module Devise
self.confirmation_sent_at = Time.now.utc
end
def generate_confirmation_token!
generate_confirmation_token && save(:validate => false)
end
module ClassMethods
# Attempt to find a user by it's email. If a record is found, send new
# confirmation instructions to it. If not user is found, returns a new user
@@ -149,8 +152,9 @@ module Devise
confirmable
end
# Generate a token checking if one does not already exist in the database.
def confirmation_token
Devise.friendly_token
generate_token(:confirmation_token)
end
Devise::Models.config(self, :confirm_within)

View File

@@ -37,7 +37,7 @@ module Devise
@password = new_password
if @password.present?
self.password_salt = self.class.encryptor_class.salt
self.password_salt = self.class.password_salt
self.encrypted_password = password_digest(@password)
end
end
@@ -82,7 +82,9 @@ module Devise
# 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)
if self.password_salt.present?
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
end
end
module ClassMethods
@@ -93,6 +95,14 @@ module Devise
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
end
def password_salt
self.encryptor_class.salt(self.stretches)
end
# We assume this method already gets the sanitized values from the
# DatabaseAuthenticatable strategy. If you are using this method on
# your own, be sure to sanitize the conditions hash to only include
# the proper fields.
def find_for_database_authentication(conditions)
find_for_authentication(conditions)
end

View File

@@ -81,6 +81,8 @@ module Devise
when TrueClass
self.failed_attempts = 0
when FalseClass
# PostgreSQL uses nil as the default value for integer columns set to 0
self.failed_attempts ||= 0
self.failed_attempts += 1
if attempts_exceeded?
lock_access!

View File

@@ -35,7 +35,7 @@ module Devise
# Generates a new random token for reset password
def generate_reset_password_token
self.reset_password_token = Devise.friendly_token
self.reset_password_token = self.class.reset_password_token
end
# Resets the reset password token with and save the record without
@@ -60,6 +60,11 @@ module Devise
recoverable
end
# Generate a token checking if one does not already exist in the database.
def reset_password_token
generate_token(:reset_password_token)
end
# Attempt to find a user by it's reset_password_token to reset it's
# password. If a user is found, reset it's password and automatically
# try saving the record. If not user is found, returns a new user

View File

@@ -18,7 +18,15 @@ module Devise
# blocked and will have to enter his credentials again.
# This configuration is also used to calculate the expires
# time for the cookie created to remember the user.
# By default remember_for is 2.weeks.
# 2.weeks by default.
#
# remember_across_browsers: if true, a valid remember token can be
# re-used between multiple browsers.
# True by default.
#
# extend_remember_period: if true, extends the user's remember period
# when remembered via cookie.
# False by default.
#
# Examples:
#
@@ -38,10 +46,11 @@ module Devise
attr_accessor :remember_me
end
# Generate a new remember token and save the record without validations.
def remember_me!
self.remember_token = Devise.friendly_token
self.remember_created_at = Time.now.utc
# Generate a new remember token and save the record without validations
# unless remember_across_browsers is true and the user already has a valid token.
def remember_me!(extend_period=false)
self.remember_token = self.class.remember_token if generate_remember_token?
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
save(:validate => false)
end
@@ -57,7 +66,7 @@ module Devise
# Remember token should be expired if expiration time not overpass now.
def remember_expired?
remember_expires_at <= Time.now.utc
remember_created_at && (remember_expires_at <= Time.now.utc)
end
# Remember token expires at created time + remember_for configuration
@@ -73,6 +82,20 @@ module Devise
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)
@@ -86,7 +109,13 @@ module Devise
record if record && !record.remember_expired?
end
Devise::Models.config(self, :remember_for, :cookie_domain)
# 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

View File

@@ -44,16 +44,16 @@ module Devise
end
module ClassMethods
::Devise::Models.config(self, :token_authentication_key)
def find_for_token_authentication(conditions)
conditions[:authentication_token] ||= conditions.delete(token_authentication_key)
find_for_authentication(conditions)
find_for_authentication(:authentication_token => conditions[token_authentication_key])
end
# Generate a token checking if one does not already exist in the database.
def authentication_token
::Devise.friendly_token
generate_token(:authentication_token)
end
::Devise::Models.config(self, :token_authentication_key)
end
end
end

View File

@@ -16,7 +16,7 @@ module Devise
base.class_eval do
validates_presence_of :email
validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :allow_blank => true
validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :case_sensitive => false, :allow_blank => true
validates_format_of :email, :with => email_regexp, :allow_blank => true
with_options :if => :password_required? do |v|

View File

@@ -1,97 +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_devise_schema(name, type, options={})
SCHEMA_OPTIONS.each do |old_key, new_key|
next unless options.key?(old_key)
options[new_key] = options.delete(old_key)
end
options.delete(:default) if options[:default].nil?
property name, type, options
end
end
module Compatibility
extend ActiveSupport::Concern
module ClassMethods
# Hooks for confirmable
def before_create(*args)
wrap_hook(:before, :create, *args)
end
def after_create(*args)
wrap_hook(:after, :create, *args)
end
def before_save(*args)
wrap_hook(:before, :save, *args)
end
def wrap_hook(action, method, *args)
options = args.extract_options!
args.each do |callback|
send action, method, callback
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{callback}
super if #{options[:if] || true}
end
METHOD
end
end
# Add ActiveRecord like finder
def find(*args)
case args.first
when :first, :all
send(args.shift, *args)
else
get(*args)
end
end
end
def changed?
dirty?
end
def save(options=nil)
if options.is_a?(Hash) && options[:validate] == false
save!
else
super()
end
end
def update_attributes(*args)
update(*args)
end
end
end
end
end
DataMapper::Model.append_extensions(Devise::Models)
DataMapper::Model.append_extensions(Devise::Orm::DataMapper::Hook)

View File

@@ -2,12 +2,17 @@ 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)
@env, @scope = env, scope
@current_path = "/#{env["SCRIPT_NAME"]}/#{env["PATH_INFO"]}".squeeze("/")
@scope = scope
end
def signing_out?
@env["PATH_INFO"] == send("destroy_#{@scope}_session_path")
@current_path == send("destroy_#{@scope}_session_path")
end
end
end

View File

@@ -20,11 +20,16 @@ module Devise
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."
"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]

View File

@@ -15,9 +15,10 @@ module ActionDispatch::Routing
# generate all needed routes for devise, based on what modules you have
# defined in your model.
#
# Examples: Let's say you have an User model configured to use
# authenticatable, confirmable and recoverable modules. After creating this
# inside your routes:
# ==== Examples
#
# Let's say you have an User model configured to use authenticatable,
# confirmable and recoverable modules. After creating this inside your routes:
#
# devise_for :users
#
@@ -25,20 +26,22 @@ module ActionDispatch::Routing
# needed routes:
#
# # Session routes for Authenticatable (default)
# new_user_session GET /users/sign_in {:controller=>"sessions", :action=>"new"}
# user_session POST /users/sign_in {:controller=>"sessions", :action=>"create"}
# destroy_user_session GET /users/sign_out {:controller=>"sessions", :action=>"destroy"}
# new_user_session GET /users/sign_in {:controller=>"devise/sessions", :action=>"new"}
# user_session POST /users/sign_in {:controller=>"devise/sessions", :action=>"create"}
# destroy_user_session GET /users/sign_out {:controller=>"devise/sessions", :action=>"destroy"}
#
# # Password routes for Recoverable, if User model has :recoverable configured
# new_user_password GET /users/password/new(.:format) {:controller=>"passwords", :action=>"new"}
# edit_user_password GET /users/password/edit(.:format) {:controller=>"passwords", :action=>"edit"}
# user_password PUT /users/password(.:format) {:controller=>"passwords", :action=>"update"}
# POST /users/password(.:format) {:controller=>"passwords", :action=>"create"}
# new_user_password GET /users/password/new(.:format) {:controller=>"devise/passwords", :action=>"new"}
# edit_user_password GET /users/password/edit(.:format) {:controller=>"devise/passwords", :action=>"edit"}
# user_password PUT /users/password(.:format) {:controller=>"devise/passwords", :action=>"update"}
# POST /users/password(.:format) {:controller=>"devise/passwords", :action=>"create"}
#
# # Confirmation routes for Confirmable, if User model has :confirmable configured
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"confirmations", :action=>"new"}
# user_confirmation GET /users/confirmation(.:format) {:controller=>"confirmations", :action=>"show"}
# POST /users/confirmation(.:format) {:controller=>"confirmations", :action=>"create"}
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"devise/confirmations", :action=>"new"}
# user_confirmation GET /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"show"}
# POST /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"create"}
#
# ==== Options
#
# You can configure your routes with some options:
#
@@ -62,37 +65,84 @@ module ActionDispatch::Routing
#
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
#
# * :path_prefix => the path prefix to be used in all routes.
#
# devise_for :users, :path_prefix => "/:locale"
#
# If you are using a dynamic prefix, like :locale above, you need to configure default_url_options in your ApplicationController
# class level, so Devise can pick it:
#
# class ApplicationController < ActionController::Base
# def self.default_url_options
# { :locale => I18n.locale }
# end
# end
#
# * :controllers => the controller which should be used. All routes by default points to Devise controllers.
# However, if you want them to point to custom controller, you should do:
#
# devise_for :users, :controllers => { :sessions => "users/sessions" }
#
# * :module => the namespace to find controlers. By default, devise will access devise/sessions,
# devise/registrations and so on. If you want to namespace all at once, use module:
#
# devise_for :users, :module => "users"
#
# Notice that whenever you use namespace in the router DSL, it automatically sets the module.
# So the following setup:
#
# namespace :publisher
# devise_for :account
# end
#
# Will use publisher/sessions controller instead of devise/sessions controller. You can revert
# this by providing the :module option to devise_for.
#
# * :skip => tell which controller you want to skip routes from being created:
#
# devise_for :users, :skip => :sessions
#
# ==== Scoping
#
# Following Rails 3 routes DSL, you can nest devise_for calls inside a scope:
#
# scope "/my" do
# devise_for :users
# end
#
# However, since Devise uses the request path to retrieve the current user, it has one caveats.
# If you are using a dynamic segment, as below:
#
# scope ":locale" do
# devise_for :users
# end
#
# You are required to configure default_url_options in your ApplicationController class level, so
# Devise can pick it:
#
# class ApplicationController < ActionController::Base
# def self.default_url_options
# { :locale => I18n.locale }
# end
# end
#
def devise_for(*resources)
options = resources.extract_options!
if as = options.delete(:as)
ActiveSupport::Deprecation.warn ":as is deprecated, please use :path instead."
options[:path] ||= as
end
if scope = options.delete(:scope)
ActiveSupport::Deprecation.warn ":scope is deprecated, please use :singular instead."
options[:singular] ||= scope
end
options[:as] ||= @scope[:as] if @scope[:as].present?
options[:module] ||= @scope[:module] if @scope[:module].present?
options[:path_prefix] ||= @scope[:path] if @scope[:path].present?
options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {})
resources.map!(&:to_sym)
resources.each do |resource|
mapping = Devise.add_model(resource, options)
mapping = Devise.add_mapping(resource, options)
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)
@@ -101,12 +151,21 @@ module ActionDispatch::Routing
routes = mapping.routes
routes -= Array(options.delete(:skip)).map { |s| s.to_s.singularize.to_sym }
routes.each do |mod|
send(:"devise_#{mod}", mapping, mapping.controllers)
devise_scope mapping.name do
yield if block_given?
with_devise_exclusive_scope mapping.fullpath, mapping.name do
routes.each { |mod| send(:"devise_#{mod}", mapping, mapping.controllers) }
end
end
end
end
# Allow you to add authentication request from the router:
#
# authenticate(:user) do
# resources :post
# end
#
def authenticate(scope)
constraint = lambda do |request|
request.env["warden"].authenticate!(:scope => scope)
@@ -117,42 +176,70 @@ module ActionDispatch::Routing
end
end
# Sets the devise scope to be used in the controller. If you have custom routes,
# you are required to call this method (also aliased as :as) in order to specify
# to which controller it is targetted.
#
# as :user do
# get "sign_in", :to => "devise/sessions#new"
# end
#
# Notice you cannot have two scopes mapping to the same URL. And remember, if
# you try to access a devise controller without specifying a scope, it will
# raise ActionNotFound error.
def devise_scope(scope)
constraint = lambda do |request|
request.env["devise.mapping"] = Devise.mappings[scope]
true
end
constraints(constraint) do
yield
end
end
alias :as :devise_scope
protected
def devise_session(mapping, controllers)
scope mapping.full_path do
get mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#new", :as => :"new_#{mapping.name}_session"
post mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#create", :as => :"#{mapping.name}_session"
get mapping.path_names[:sign_out], :to => "#{controllers[:sessions]}#destroy", :as => :"destroy_#{mapping.name}_session"
def devise_session(mapping, controllers) #:nodoc:
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 devise_password(mapping, controllers)
scope mapping.full_path, :name_prefix => mapping.name do
resource :password, :only => [:new, :create, :edit, :update], :path => mapping.path_names[:password], :controller => controllers[:passwords]
end
def devise_password(mapping, controllers) #:nodoc:
resource :password, :only => [:new, :create, :edit, :update],
:path => mapping.path_names[:password], :controller => controllers[:passwords]
end
def devise_confirmation(mapping, controllers)
scope mapping.full_path, :name_prefix => mapping.name do
resource :confirmation, :only => [:new, :create, :show], :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
end
def devise_confirmation(mapping, controllers) #:nodoc:
resource :confirmation, :only => [:new, :create, :show],
:path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
end
def devise_unlock(mapping, controllers)
scope mapping.full_path, :name_prefix => mapping.name do
resource :unlock, :only => [:new, :create, :show], :path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
def devise_unlock(mapping, controllers) #:nodoc:
if mapping.to.unlock_strategy_enabled?(:email)
resource :unlock, :only => [:new, :create, :show],
:path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
end
end
def devise_registration(mapping, controllers)
scope mapping.full_path[1..-1], :name_prefix => mapping.name do
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => mapping.path_names[:registration],
: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 raise_no_devise_method_error!(klass)
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'"

View File

@@ -15,11 +15,103 @@ 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, 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
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

View File

@@ -19,7 +19,7 @@ module Devise
# encrypter password field in 128 characters.
def database_authenticatable(options={})
null = options[:null] || false
default = options[:default] || ""
default = options.key?(:default) ? options[:default] : ("" if null == false)
if options.delete(:encryptor)
ActiveSupport::Deprecation.warn ":encryptor as option is deprecated, simply remove it."

View File

@@ -14,6 +14,18 @@ module Devise
private
# Simply invokes valid_for_authentication? with the given block and deal with the result.
def validate(resource, &block)
result = resource && resource.valid_for_authentication?(&block)
case result
when Symbol, String
fail!(result)
else
result
end
end
# Check if this is strategy is valid for http authentication by:
#
# * Validating if the model allows params authentication;
@@ -84,8 +96,8 @@ module Devise
# Helper to decode credentials from HTTP.
def decode_credentials
username_and_password = request.authorization.split(' ', 2).last || ''
ActiveSupport::Base64.decode64(username_and_password).split(/:/, 2)
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.

View File

@@ -10,24 +10,6 @@ module Devise
mapping
end
end
protected
def succeeded?
@result == :success
end
# Simply invokes valid_for_authentication? with the given block and deal with the result.
def validate(resource, &block)
result = resource && resource.valid_for_authentication?(&block)
case result
when Symbol, String
fail!(result)
else
result
end
end
end
end
end

View File

@@ -6,7 +6,7 @@ module Devise
# to verify whether there is a cookie with the remember token, and to
# recreate the user from this cookie if it exists. Must be called *before*
# authenticatable.
class Rememberable < Devise::Strategies::Base
class Rememberable < Authenticatable
# A valid strategy for rememberable needs a remember token in the cookies.
def valid?
remember_cookie.present?
@@ -28,10 +28,18 @@ module Devise
private
def remember_me?
true
end
def remember_key
"remember_#{scope}_token"
end
def extend_remember_period?
mapping.to.extend_remember_period
end
# Accessor for remember cookie
def remember_cookie
@remember_cookie ||= cookies.signed[remember_key]

View File

@@ -42,6 +42,8 @@ module Devise
status, headers, body = Devise::FailureApp.call(env).to_a
@controller.send :render, :status => status, :text => body,
:content_type => headers["Content-Type"], :location => headers["Location"]
nil
else
result
end

View File

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

View 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

View File

@@ -10,6 +10,10 @@ class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
# 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

View File

@@ -1,86 +0,0 @@
require 'rails/generators/migration'
module Devise
module Generators
class DeviseGenerator < Rails::Generators::NamedBase
include Rails::Generators::Migration
source_root File.expand_path("../templates", __FILE__)
namespace "devise"
desc "Generates a model with the given NAME (if one does not exist) with devise " <<
"configuration plus a migration file and devise routes."
def self.orm_has_migration?
Rails::Generators.options[:rails][:orm] == :active_record
end
def self.next_migration_number(path)
Time.now.utc.strftime("%Y%m%d%H%M%S")
end
class_option :orm
class_option :migration, :type => :boolean, :default => orm_has_migration?
def invoke_orm_model
return unless behavior == :invoke
if model_exists?
say "* Model already exists. Adding Devise behavior."
elsif options[:orm].present?
invoke "model", [name], :migration => false, :orm => options[:orm]
unless model_exists?
abort "Tried to invoke the model generator for '#{options[:orm]}' but could not find it.\n" <<
"Please create your model by hand before calling `rails g devise #{name}`."
end
else
abort "Cannot create a devise model because config.generators.orm is blank.\n" <<
"Please create your model by hand or configure your generators orm before calling `rails g devise #{name}`."
end
end
def inject_devise_config_into_model
devise_class_setup = <<-CONTENT
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
CONTENT
case options[:orm].to_s
when "mongoid"
inject_into_file model_path, devise_class_setup, :after => "include Mongoid::Document\n"
when "data_mapper"
inject_into_file model_path, devise_class_setup, :after => "include DataMapper::Resource\n"
when "active_record"
inject_into_class model_path, class_name, devise_class_setup + <<-CONTENT
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation
CONTENT
end
end
def copy_migration_template
return unless options.migration?
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
end
def add_devise_routes
route "devise_for :#{table_name}"
end
protected
def model_exists?
File.exists?(File.join(destination_root, model_path))
end
def model_path
@model_path ||= File.join("app", "models", "#{file_path}.rb")
end
end
end
end

View File

@@ -0,0 +1,17 @@
module Devise
module Generators
class DeviseGenerator < Rails::Generators::NamedBase
namespace "devise"
source_root File.expand_path("../templates", __FILE__)
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 add_devise_routes
route "devise_for :#{table_name}"
end
end
end
end

View File

@@ -3,7 +3,7 @@ require 'active_support/secure_random'
module Devise
module Generators
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path("../templates", __FILE__)
source_root File.expand_path("../../templates", __FILE__)
desc "Creates a Devise initializer and copy locale files to your application."
class_option :orm
@@ -13,11 +13,11 @@ module Devise
end
def copy_locale
copy_file "../../../../../config/locales/en.yml", "config/locales/devise.en.yml"
copy_file "../../../config/locales/en.yml", "config/locales/devise.en.yml"
end
def show_readme
readme "README"
readme "README" if behavior == :invoke
end
end
end

View 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

View File

@@ -1,17 +1,17 @@
module Devise
module Generators
class ViewsGenerator < Rails::Generators::Base
source_root File.expand_path("../../../../../app/views", __FILE__)
source_root File.expand_path("../../../../app/views", __FILE__)
desc "Copies all Devise views to your application."
argument :scope, :required => false, :default => nil,
:desc => "The scope to copy views to"
class_option :template_engine, :type => :string, :aliases => "-t", :default => "erb",
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]
case options[:template_engine].to_s
when "haml"
verify_haml_existence
verify_haml_version

View File

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

View 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

View File

@@ -9,8 +9,9 @@ Devise.setup do |config|
# config.mailer = "Devise::Mailer"
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default), :mongoid
# (bson_ext recommended) and :data_mapper (experimental).
# 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
@@ -27,6 +28,9 @@ Devise.setup do |config|
# Tell if authentication through HTTP Basic Auth is enabled. True by default.
# config.http_authenticatable = true
# Set this to true to use Basic Auth for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
# The realm used in Http Basic Authentication
# config.http_authentication_realm = "Application"
@@ -57,6 +61,12 @@ Devise.setup do |config|
# 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
@@ -95,22 +105,19 @@ Devise.setup do |config|
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "sessions/users/new". It's turned off by default because it's slower if you
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
# config.scoped_views = true
# By default, devise detects the role accessed based on the url. So whenever
# accessing "/users/sign_in", it knows you are accessing an User. This makes
# routes as "/sign_in" not possible, unless you tell Devise to use the default
# scope, setting true below.
# Note that devise does not generate default routes. You also have to
# specify them in config/routes.rb
# config.use_default_scope = true
# Configure the default scope used by Devise. By default it's the first devise
# role declared in your routes.
# 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

View File

@@ -60,26 +60,36 @@ class ControllerAuthenticableTest < ActionController::TestCase
@controller.anybody_signed_in?
end
test 'proxy current_admin to authenticate with admin scope' do
@mock_warden.expects(:authenticate).with(:scope => :admin)
@controller.current_admin
end
test 'proxy current_user to authenticate with user scope' do
@mock_warden.expects(:authenticate).with(:scope => :user)
@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?
@@ -90,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({})
@@ -102,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)
@@ -126,6 +147,15 @@ class ControllerAuthenticableTest < ActionController::TestCase
@controller.sign_out(User.new)
end
test 'sign out everybody proxy to logout on warden' do
Devise.mappings.keys.each { |scope|
@mock_warden.expects(:user).with(scope).returns(true)
}
@mock_warden.expects(:logout).with(*Devise.mappings.keys).returns(true)
@controller.sign_out_all_scopes
end
test 'stored location for returns the location for a given scope' do
assert_nil @controller.stored_location_for(:user)
@controller.session[:"user_return_to"] = "/foo.bar"

View File

@@ -10,37 +10,28 @@ class HelpersTest < ActionController::TestCase
def setup
@mock_warden = OpenStruct.new
@controller.request.env['warden'] = @mock_warden
@controller.request.env['devise.mapping'] = Devise.mappings[:user]
end
test 'get resource name from request path' do
@request.path = '/users/session'
test 'get resource name from env' do
assert_equal :user, @controller.resource_name
end
test 'get resource name from specific request path' do
@request.path = '/admin_area/session'
assert_equal :admin, @controller.resource_name
end
test 'get resource class from request path' do
@request.path = '/users/session'
test 'get resource class from env' do
assert_equal User, @controller.resource_class
end
test 'get resource instance variable from request path' do
@request.path = '/admin_area/session'
@controller.instance_variable_set(:@admin, admin = Admin.new)
test 'get resource instance variable from env' do
@controller.instance_variable_set(:@user, admin = Admin.new)
assert_equal admin, @controller.resource
end
test 'set resource instance variable from request path' do
@request.path = '/admin_area/session'
test 'set resource instance variable from env' do
admin = @controller.send(:resource_class).new
@controller.send(:resource=, admin)
assert_equal admin, @controller.send(:resource)
assert_equal admin, @controller.instance_variable_get(:@admin)
assert_equal admin, @controller.instance_variable_get(:@user)
end
test 'resources methods are not controller actions' do

View File

@@ -44,4 +44,15 @@ class RoutesTest < ActionController::TestCase
assert_path_and_url :confirmation
assert_path_and_url :confirmation, :new
end
test 'should alias unlock to mapped user unlock' do
assert_path_and_url :unlock
assert_path_and_url :unlock, :new
end
test 'should alias registration to mapped user registration' do
assert_path_and_url :registration
assert_path_and_url :registration, :new
assert_path_and_url :registration, :edit
end
end

View File

@@ -23,7 +23,7 @@ class Encryptors < ActiveSupport::TestCase
test "should have length #{value} for #{key.inspect}" do
swap Devise, :encryptor => key do
encryptor = Devise::Encryptors.const_get(key.to_s.classify)
assert_equal value, encryptor.digest('a', 4, encryptor.salt, nil).size
assert_equal value, encryptor.digest('a', 4, encryptor.salt(4), nil).size
end
end
end

View File

@@ -77,6 +77,23 @@ class FailureTest < ActiveSupport::TestCase
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
@@ -88,11 +105,6 @@ class FailureTest < ActiveSupport::TestCase
assert_equal 401, @response.first
end
end
test 'works for xml http requests' do
call_failure('formats' => :html, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
assert_equal 401, @response.first
end
end
context 'With recall' do
@@ -100,6 +112,7 @@ class FailureTest < ActiveSupport::TestCase
env = {
"action_dispatch.request.parameters" => { :controller => "devise/sessions" },
"warden.options" => { :recall => "new", :attempted_path => "/users/sign_in" },
"devise.mapping" => Devise.mappings[:user],
"warden" => stub_everything
}
call_failure(env)

View File

@@ -1,6 +1,15 @@
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,6 +56,26 @@ 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
@@ -160,7 +189,7 @@ class AuthenticationRedirectTest < ActionController::IntegrationTest
follow_redirect!
sign_in_as_user :visit => false
assert_template 'users/index'
assert_current_url '/users'
assert_nil session[:"user_return_to"]
end
@@ -176,7 +205,7 @@ class AuthenticationRedirectTest < ActionController::IntegrationTest
follow_redirect!
sign_in_as_user :visit => false
assert_template 'users/index'
assert_current_url '/users'
assert_nil session[:"user_return_to"]
end
@@ -202,11 +231,22 @@ class AuthenticationSessionTest < ActionController::IntegrationTest
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
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
@@ -249,12 +289,16 @@ class AuthenticationWithScopesTest < ActionController::IntegrationTest
end
end
test 'uses the mapping from the default scope if specified' do
swap Devise, :use_default_scope => true do
get '/sign_in'
assert_response :ok
assert_contain 'Sign in'
end
test 'uses the mapping from router' do
sign_in_as_user :visit => "/as/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
test 'uses the mapping from nested devise_for call' do
sign_in_as_user :visit => "/devise_for/sign_in"
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
end
@@ -276,4 +320,36 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
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

View File

@@ -16,16 +16,13 @@ class ConfirmationTest < ActionController::IntegrationTest
fill_in 'email', :with => user.email
click_button 'Resend confirmation instructions'
assert_template 'sessions/new'
assert_current_url '/users/sign_in'
assert_contain 'You will receive an email with instructions about how to confirm your account in a few minutes'
assert_equal 1, ActionMailer::Base.deliveries.size
end
test 'user with invalid confirmation token should not be able to confirm an account' do
visit_user_confirmation_with_token('invalid_confirmation')
assert_response :success
assert_template 'confirmations/new'
assert_have_selector '#error_explanation'
assert_contain /Confirmation token(.*)invalid/
end
@@ -33,26 +30,36 @@ class ConfirmationTest < ActionController::IntegrationTest
test 'user with valid confirmation token should be able to confirm an account' do
user = create_user(:confirm => false)
assert_not user.confirmed?
visit_user_confirmation_with_token(user.confirmation_token)
assert_template 'home/index'
assert_contain 'Your account was successfully confirmed.'
assert_current_url '/'
assert user.reload.confirmed?
end
test 'user already confirmed user should not be able to confirm the account again' do
test 'already confirmed user should not be able to confirm the account again' do
user = create_user(:confirm => false)
user.confirmed_at = Time.now
user.save
visit_user_confirmation_with_token(user.confirmation_token)
assert_template 'confirmations/new'
assert_have_selector '#error_explanation'
assert_contain 'already confirmed'
end
test 'already confirmed user should not be able to confirm the account again neither request confirmation' do
user = create_user(:confirm => false)
user.confirmed_at = Time.now
user.save
visit_user_confirmation_with_token(user.confirmation_token)
assert_contain 'already confirmed'
fill_in 'email', :with => user.email
click_button 'Resend confirmation instructions'
assert_contain 'already confirmed'
end
test 'sign in user automatically after confirming it\'s email' do
user = create_user(:confirm => false)
visit_user_confirmation_with_token(user.confirmation_token)

View File

@@ -39,6 +39,14 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
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")
@@ -46,4 +54,11 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
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

View File

@@ -37,27 +37,25 @@ class LockTest < ActionController::IntegrationTest
end
test 'unlocked pages should not be available if email strategy is disabled' do
visit "/users/sign_in"
click_link "Didn't receive unlock instructions?"
visit "/admins/sign_in"
swap Devise, :unlock_strategy => :time do
visit "/users/sign_in"
assert_raise Webrat::NotFoundError do
click_link "Didn't receive unlock instructions?"
end
assert_raise AbstractController::ActionNotFound do
visit new_user_unlock_path
end
assert_raise Webrat::NotFoundError do
click_link "Didn't receive unlock instructions?"
end
assert_raise NameError do
visit new_admin_unlock_path
end
visit "/admins/unlock/new"
assert_response :not_found
end
test 'user with invalid unlock token should not be able to unlock an account' do
visit_user_unlock_with_token('invalid_token')
assert_response :success
assert_template 'unlocks/new'
assert_current_url '/users/unlock?unlock_token=invalid_token'
assert_have_selector '#error_explanation'
assert_contain /Unlock token(.*)invalid/
end
@@ -68,7 +66,7 @@ class LockTest < ActionController::IntegrationTest
visit_user_unlock_with_token(user.unlock_token)
assert_template 'home/index'
assert_current_url '/'
assert_contain 'Your account was successfully unlocked.'
assert_not user.reload.access_locked?

View File

@@ -65,8 +65,8 @@ class RegistrationTest < ActionController::IntegrationTest
fill_in 'password confirmation', :with => '123456'
click_button 'Sign up'
assert_template 'registrations/new'
assert_contain 'Email has already been taken'
assert_current_url '/users'
assert_contain(/Email .* already.*taken/)
assert_not warden.authenticated?(:user)
end
@@ -92,7 +92,7 @@ class RegistrationTest < ActionController::IntegrationTest
fill_in 'current password', :with => '123456'
click_button 'Update'
assert_template 'home/index'
assert_current_url '/'
assert_contain 'You updated your account successfully.'
assert_equal "user.new@email.com", User.first.email
@@ -122,7 +122,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 User.first.valid_password?('pas123')

View File

@@ -3,7 +3,6 @@ require 'test_helper'
class RememberMeTest < ActionController::IntegrationTest
def create_user_and_remember(add_to_token='')
Devise.remember_for = 1
user = create_user
user.remember_me!
raw_cookie = User.serialize_into_cookie(user).tap { |a| a.last << add_to_token }
@@ -17,6 +16,16 @@ class RememberMeTest < ActionController::IntegrationTest
request.cookie_jar['raw_cookie']
end
def signed_cookie(key)
controller.send(:cookies).signed[key]
end
def cookie_expires(key)
cookie = response.headers["Set-Cookie"].split("\n").grep(/^#{key}/).first
cookie.split(";").map(&:strip).grep(/^expires=/)
Time.parse($')
end
test 'do not remember the user if he has not checked remember me option' do
user = sign_in_as_user
assert_nil request.cookies["remember_user_cookie"]
@@ -47,6 +56,50 @@ class RememberMeTest < ActionController::IntegrationTest
assert warden.user(:user) == user
end
test 'does not extend remember period through sign in' do
swap Devise, :extend_remember_period => true, :remember_for => 1.year do
user = create_user
user.remember_me!
user.remember_created_at = old = 10.days.ago
user.save
sign_in_as_user :remember_me => true
user.reload
assert warden.user(:user) == user
assert_equal old.to_i, user.remember_created_at.to_i
end
end
test 'if both extend_remember_period and remember_across_browsers are true, sends the same token with a new expire date' do
swap Devise, :remember_across_browsers => true, :extend_remember_period => true, :remember_for => 1.year do
user = create_user_and_remember
token = user.remember_token
user.remember_created_at = old = 10.minutes.ago
user.save!
get users_path
assert (cookie_expires("remember_user_token") - 1.year) > (old + 5.minutes)
assert_equal token, signed_cookie("remember_user_token").last
end
end
test 'if both extend_remember_period and remember_across_browsers are false, sends a new token with old expire date' do
swap Devise, :remember_across_browsers => false, :extend_remember_period => false, :remember_for => 1.year do
user = create_user_and_remember
token = user.remember_token
user.remember_created_at = old = 10.minutes.ago
user.save!
get users_path
assert (cookie_expires("remember_user_token") - 1.year) < (old + 5.minutes)
assert_not_equal token, signed_cookie("remember_user_token").last
end
end
test 'do not remember other scopes' do
user = create_user_and_remember
get root_path
@@ -78,6 +131,7 @@ class RememberMeTest < ActionController::IntegrationTest
get destroy_user_session_path
assert_not warden.authenticated?(:user)
assert_nil user.reload.remember_token
assert_nil warden.cookies['remember_user_token']
end
test 'do not remember the user anymore after forget' do
@@ -87,5 +141,6 @@ class RememberMeTest < ActionController::IntegrationTest
get destroy_user_session_path
get users_path
assert_not warden.authenticated?(:user)
assert_nil warden.cookies['remember_user_token']
end
end

View File

@@ -1,6 +1,12 @@
require 'test_helper'
class FakeRequest < Struct.new(:path_info, :params)
end
class MappingTest < ActiveSupport::TestCase
def fake_request(path, params={})
FakeRequest.new(path, params)
end
test 'store options' do
mapping = Devise.mappings[:user]
@@ -8,27 +14,15 @@ class MappingTest < ActiveSupport::TestCase
assert_equal User.devise_modules, mapping.modules
assert_equal :users, mapping.plural
assert_equal :user, mapping.singular
assert_equal :users, mapping.path
assert_equal "users", mapping.path
end
test 'allows path to be given' do
assert_equal :admin_area, Devise.mappings[:admin].path
assert_equal "admin_area", Devise.mappings[:admin].path
end
test 'allows custom singular to be given' do
assert_equal :accounts, Devise.mappings[:manager].path
end
test 'allows a controller depending on the mapping' do
allowed = Devise.mappings[:user].allowed_controllers
assert allowed.include?("devise/sessions")
assert allowed.include?("devise/confirmations")
assert allowed.include?("devise/passwords")
allowed = Devise.mappings[:admin].allowed_controllers
assert allowed.include?("sessions")
assert_not allowed.include?("devise/confirmations")
assert_not allowed.include?("devise/unlocks")
assert_equal "accounts", Devise.mappings[:manager].path
end
test 'has strategies depending on the model declaration' do
@@ -36,15 +30,6 @@ class MappingTest < ActiveSupport::TestCase
assert_equal [:database_authenticatable], Devise.mappings[:admin].strategies
end
test 'find mapping by path' do
assert_nil Devise::Mapping.find_by_path("/foo/bar")
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session")
end
test 'find mapping by customized path' do
assert_equal Devise.mappings[:admin], Devise::Mapping.find_by_path("/admin_area/session")
end
test 'find scope for a given object' do
assert_equal :user, Devise::Mapping.find_scope!(User)
assert_equal :user, Devise::Mapping.find_scope!(:user)
@@ -82,26 +67,6 @@ class MappingTest < ActiveSupport::TestCase
assert_equal 'unblock', mapping.path_names[:unlock]
end
test 'has an empty path as default path prefix' do
mapping = Devise.mappings[:user]
assert_equal '/', mapping.path_prefix
end
test 'allow path prefix to be configured' do
mapping = Devise.mappings[:manager]
assert_equal '/:locale/', mapping.path_prefix
end
test 'retrieve as from the proper position' do
assert_equal 1, Devise.mappings[:user].segment_position
assert_equal 2, Devise.mappings[:manager].segment_position
end
test 'path is returned with path prefix and as' do
assert_equal '/users', Devise.mappings[:user].full_path
assert_equal '/:locale/accounts', Devise.mappings[:manager].full_path
end
test 'magic predicates' do
mapping = Devise.mappings[:user]
assert mapping.authenticatable?
@@ -113,8 +78,8 @@ class MappingTest < ActiveSupport::TestCase
mapping = Devise.mappings[:admin]
assert mapping.authenticatable?
assert mapping.recoverable?
assert mapping.lockable?
assert_not mapping.confirmable?
assert_not mapping.lockable?
assert_not mapping.rememberable?
end
end

View File

@@ -133,7 +133,7 @@ class ConfirmableTest < ActiveSupport::TestCase
user.instance_eval { def confirmation_required?; false end }
user.save
user.send_confirmation_instructions
assert_not_nil user.confirmation_token
assert_not_nil user.reload.confirmation_token
end
test 'should not resend email instructions if the user change his email' do

View File

@@ -98,6 +98,13 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
assert_not user.valid_password?('654321')
end
test 'should not validate password when salt is nil' do
admin = create_admin
admin.password_salt = nil
admin.save
assert_not admin.valid_password?('123456')
end
test 'should respond to current password' do
assert new_user.respond_to?(:current_password)
end

View File

@@ -107,4 +107,112 @@ class RememberableTest < ActiveSupport::TestCase
assert_not user.remember_expired?
end
end
test 'if extend_remember_period is false, remember_me! should generate a new timestamp if expired' do
swap Devise, :remember_for => 5.minutes do
user = create_user
user.remember_me!(false)
assert user.remember_created_at
user.remember_created_at = old = 10.minutes.ago
user.save
user.remember_me!(false)
assert_not_equal old.to_i, user.remember_created_at.to_i
end
end
test 'if extend_remember_period is false, remember_me! should not generate a new timestamp' do
swap Devise, :remember_for => 1.year do
user = create_user
user.remember_me!(false)
assert user.remember_created_at
user.remember_created_at = old = 10.minutes.ago.utc
user.save
user.remember_me!(false)
assert_equal old.to_i, user.remember_created_at.to_i
end
end
test 'if extend_remember_period is true, remember_me! should always generate a new timestamp' do
swap Devise, :remember_for => 1.year do
user = create_user
user.remember_me!(true)
assert user.remember_created_at
user.remember_created_at = old = 10.minutes.ago
user.save
user.remember_me!(true)
assert_not_equal old, user.remember_created_at
end
end
test 'if remember_across_browsers is true, remember_me! should create a new token if no token exists' do
swap Devise, :remember_across_browsers => true, :remember_for => 1.year do
user = create_user
assert_equal nil, user.remember_token
user.remember_me!
assert_not_equal nil, user.remember_token
end
end
test 'if remember_across_browsers is true, remember_me! should create a new token if a token exists but has expired' do
swap Devise, :remember_across_browsers => true, :remember_for => 1.day do
user = create_user
user.remember_me!
user.remember_created_at = 2.days.ago
user.save
token = user.remember_token
user.remember_me!
assert_not_equal token, user.remember_token
end
end
test 'if remember_across_browsers is true, remember_me! should not create a new token if a token exists and has not expired' do
swap Devise, :remember_across_browsers => true, :remember_for => 2.days do
user = create_user
user.remember_me!
user.remember_created_at = 1.day.ago
user.save
token = user.remember_token
user.remember_me!
assert_equal token, user.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if no token exists' do
swap Devise, :remember_across_browsers => false do
user = create_user
assert_equal nil, user.remember_token
user.remember_me!
assert_not_equal nil, user.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists but has expired' do
swap Devise, :remember_across_browsers => false, :remember_for => 1.day do
user = create_user
user.remember_me!
user.remember_created_at = 2.days.ago
user.save
token = user.remember_token
user.remember_me!
assert_not_equal token, user.remember_token
end
end
test 'if remember_across_browsers is false, remember_me! should create a new token if a token exists and has not expired' do
swap Devise, :remember_across_browsers => false, :remember_for => 2.days do
user = create_user
user.remember_me!
user.remember_created_at = 1.day.ago
user.save
token = user.remember_token
user.remember_me!
assert_not_equal token, user.remember_token
end
end
end

View File

@@ -1,8 +1,6 @@
require 'test_helper'
class ValidatableTest < ActiveSupport::TestCase
extend Devise::TestSilencer if [:mongoid, :data_mapper].include?(DEVISE_ORM)
test 'should require email to be set' do
user = new_user(:email => nil)
assert user.invalid?
@@ -15,11 +13,11 @@ class ValidatableTest < ActiveSupport::TestCase
user = new_user(:email => '')
assert user.invalid?
assert_not_equal 'has already been taken', user.errors[:email].join
assert_no_match(/taken/, user.errors[:email].join)
user.email = existing_user.email
assert user.invalid?
assert_equal 'has already been taken', user.errors[:email].join
assert_match(/taken/, user.errors[:email].join)
end
test 'should require correct email format, allowing blank' do

View File

@@ -26,16 +26,16 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
test 'can cherry pick modules' do
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable
end
test 'chosen modules are inheritable' do
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable
end
test 'order of module inclusion' do
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable]
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :lockable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable]
assert_include_modules Admin, *incorrect_module_order

View File

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

View File

@@ -1,5 +1,6 @@
Mongoid.configure do |config|
config.master = Mongo::Connection.new('127.0.0.1', 27017).db("devise-test-suite")
config.master = Mongo::Connection.new('127.0.0.1', 27017).db("devise-test-suite")
config.use_utc = true
end
class ActiveSupport::TestCase
@@ -7,4 +8,4 @@ class ActiveSupport::TestCase
User.delete_all
Admin.delete_all
end
end
end

View File

@@ -7,4 +7,4 @@ require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
Rails::Application.load_tasks
Rails.application.load_tasks

View File

@@ -1,3 +1,3 @@
class Admin < ActiveRecord::Base
devise :database_authenticatable, :registerable, :timeoutable, :recoverable
devise :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :unlock_strategy => :time
end

View File

@@ -0,0 +1,2 @@
class Publisher::RegistrationsController < ApplicationController
end

View File

@@ -0,0 +1,2 @@
class Publisher::SessionsController < ApplicationController
end

View File

@@ -1,5 +1,5 @@
class UsersController < ApplicationController
before_filter :authenticate_user!
before_filter :authenticate_user!, :except => :accept
respond_to :html, :xml
def index
@@ -7,6 +7,10 @@ class UsersController < ApplicationController
respond_with(current_user)
end
def accept
@current_user = current_user
end
def expire
user_session['last_request_at'] = 31.minutes.ago.utc
render :text => 'User will be expired on next request'

View File

@@ -1,12 +0,0 @@
class Admin
include DataMapper::Resource
property :id, Serial
property :username, String
devise :database_authenticatable, :registerable, :timeoutable, :recoverable
def self.create!(*args)
create(*args)
end
end

View File

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

View File

@@ -1,23 +0,0 @@
class User
include DataMapper::Resource
extend Devise::Orm::DataMapper::Schema
include Devise::Orm::DataMapper::Compatibility
property :id, Serial
property :username, String
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable
timestamps :at
def self.create!(*args)
create(*args)
end
def self.destroy_all
all.destroy
end
end

View File

@@ -2,5 +2,5 @@ class Admin
include Mongoid::Document
include Shim
devise :database_authenticatable, :timeoutable, :registerable, :recoverable
devise :database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :unlock_strategy => :time
end

View File

@@ -17,8 +17,8 @@ require "devise"
module RailsApp
class Application < Rails::Application
# Add additional load paths for your own custom dirs
config.load_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) }
config.load_paths += [ "#{config.root}/app/#{DEVISE_ORM}" ]
config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) }
config.autoload_paths += [ "#{config.root}/app/#{DEVISE_ORM}" ]
# Configure generators values. Many other options are available, be sure to check the documentation.
# config.generators do |g|

View File

@@ -7,7 +7,7 @@ begin
rescue LoadError
require 'rubygems'
require 'bundler'
Bundler.setup :default, DEVISE_ORM
Bundler.setup :default, :test, DEVISE_ORM
end
$:.unshift File.expand_path('../../../../lib', __FILE__)
$:.unshift File.expand_path('../../../../lib', __FILE__)

View File

@@ -28,4 +28,6 @@ RailsApp::Application.configure do
# config.active_record.schema_format = :sql
config.action_dispatch.show_exceptions = false
config.active_support.deprecation = :stderr
end

View File

@@ -1,20 +1,20 @@
# 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|
# 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"
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me@config-initializers-devise.com"
# Configure how many times you want the password re-encrypted. Default is 10.
# config.stretches = 10
# Configure the class responsible to send e-mails.
# config.mailer = "Devise::Mailer"
# Define which will be the encryption algorithm. Supported algorithms are :sha1
# (default) and :sha512. Devise also supports encryptors from others authentication
# frameworks 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
# ==> 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/#{DEVISE_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
@@ -22,40 +22,108 @@ Devise.setup do |config|
# session. If you need permissions, you should implement that in a before filter.
# config.authentication_keys = [ :email ]
# The time you want give to your user to confirm his account. During this time
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true
# Tell if authentication through HTTP Basic Auth is enabled. True by default.
# config.http_authenticatable = 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 = "d142367154e5beacca404b1a6a4f8bc52c6fdcfa3ccc3cf8eb49f3458a688ee6ac3b9fae488432a3bfca863b8a90008368a9f3a3dfbe5a962e64b6ab8f3a3a1a"
# ==> 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 = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/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
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me-omg@yourapp.com"
# Load and configure the ORM. Supports :active_record, :data_mapper and :mongoid.
require "devise/orm/#{DEVISE_ORM}"
# 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
# Number of authentication tries before locking an account.
# config.maximum_attempts = 20
# ==> 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
# :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
@@ -66,13 +134,6 @@ Devise.setup do |config|
# twitter.consumer_key = <YOUR CONSUMER KEY>
# twitter.options :site => 'http://twitter.com'
# end
# manager.default_strategies.unshift :twitter_oauth
# end
# Configure default_url_options if you are using dynamic segments in :path_prefix
# for devise_for.
#
# config.default_url_options do
# { :locale => I18n.locale }
# manager.default_strategies(:scope => :user).unshift :twitter_oauth
# end
end

View File

@@ -1,29 +1,47 @@
Rails::Application.routes.draw do
Rails.application.routes.draw do
# Resources for testing
resources :users, :only => [:index] do
get :expire, :on => :member
get :accept, :on => :member
end
resources :admins, :only => [:index]
devise_for :users
devise_for :admin, :path => "admin_area", :controllers => { :sessions => "sessions" }, :skip => :passwords
devise_for :accounts, :singular => "manager", :path_prefix => ":locale",
:class_name => "User", :path_names => {
:sign_in => "login", :sign_out => "logout",
:password => "secret", :confirmation => "verification",
:unlock => "unblock", :sign_up => "register",
:registration => "management"
}
# Users scope
devise_for :users do
match "/devise_for/sign_in", :to => "devise/sessions#new"
end
as :user do
match "/as/sign_in", :to => "devise/sessions#new"
end
match "/admin_area/home", :to => "admins#index", :as => :admin_root
match "/sign_in", :to => "devise/sessions#new"
# Dummy route for new admin pasword
match "/anywhere", :to => "foo#bar", :as => :new_admin_password
# Admin scope
devise_for :admin, :path => "admin_area", :controllers => { :sessions => "sessions" }, :skip => :passwords
root :to => "home#index"
match "/admin_area/home", :to => "admins#index", :as => :admin_root
match "/anywhere", :to => "foo#bar", :as => :new_admin_password
authenticate(:admin) do
match "/private", :to => "home#private", :as => :private
end
# Other routes for routing_test.rb
namespace :publisher, :path_names => { :sign_in => "i_don_care", :sign_out => "get_out" } do
devise_for :accounts, :class_name => "User", :path_names => { :sign_in => "get_in" }
end
scope ":locale" do
devise_for :accounts, :singular => "manager", :class_name => "User",
:path_names => {
:sign_in => "login", :sign_out => "logout",
:password => "secret", :confirmation => "verification",
:unlock => "unblock", :sign_up => "register",
:registration => "management"
}
end
root :to => "home#index"
end

View File

@@ -1,25 +1,29 @@
require 'test_helper'
class MapRoutingTest < ActionController::TestCase
class DefaultRoutingTest < ActionController::TestCase
test 'map new user session' do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, {:path => 'users/sign_in', :method => :get})
assert_named_route "/users/sign_in", :new_user_session_path
end
test 'map create user session' do
assert_recognizes({:controller => 'devise/sessions', :action => 'create'}, {:path => 'users/sign_in', :method => :post})
assert_named_route "/users/sign_in", :user_session_path
end
test 'map destroy user session' do
assert_recognizes({:controller => 'devise/sessions', :action => 'destroy'}, {:path => 'users/sign_out', :method => :get})
assert_named_route "/users/sign_out", :destroy_user_session_path
end
test 'map new user confirmation' do
assert_recognizes({:controller => 'devise/confirmations', :action => 'new'}, 'users/confirmation/new')
assert_named_route "/users/confirmation/new", :new_user_confirmation_path
end
test 'map create user confirmation' do
assert_recognizes({:controller => 'devise/confirmations', :action => 'create'}, {:path => 'users/confirmation', :method => :post})
assert_named_route "/users/confirmation", :user_confirmation_path
end
test 'map show user confirmation' do
@@ -28,14 +32,17 @@ class MapRoutingTest < ActionController::TestCase
test 'map new user password' do
assert_recognizes({:controller => 'devise/passwords', :action => 'new'}, 'users/password/new')
assert_named_route "/users/password/new", :new_user_password_path
end
test 'map create user password' do
assert_recognizes({:controller => 'devise/passwords', :action => 'create'}, {:path => 'users/password', :method => :post})
assert_named_route "/users/password", :user_password_path
end
test 'map edit user password' do
assert_recognizes({:controller => 'devise/passwords', :action => 'edit'}, 'users/password/edit')
assert_named_route "/users/password/edit", :edit_user_password_path
end
test 'map update user password' do
@@ -44,10 +51,12 @@ class MapRoutingTest < ActionController::TestCase
test 'map new user unlock' do
assert_recognizes({:controller => 'devise/unlocks', :action => 'new'}, 'users/unlock/new')
assert_named_route "/users/unlock/new", :new_user_unlock_path
end
test 'map create user unlock' do
assert_recognizes({:controller => 'devise/unlocks', :action => 'create'}, {:path => 'users/unlock', :method => :post})
assert_named_route "/users/unlock", :user_unlock_path
end
test 'map show user unlock' do
@@ -56,14 +65,17 @@ class MapRoutingTest < ActionController::TestCase
test 'map new user registration' do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, 'users/sign_up')
assert_named_route "/users/sign_up", :new_user_registration_path
end
test 'map create user registration' do
assert_recognizes({:controller => 'devise/registrations', :action => 'create'}, {:path => 'users', :method => :post})
assert_named_route "/users", :user_registration_path
end
test 'map edit user registration' do
assert_recognizes({:controller => 'devise/registrations', :action => 'edit'}, {:path => 'users/edit', :method => :get})
assert_named_route "/users/edit", :edit_user_registration_path
end
test 'map update user registration' do
@@ -74,6 +86,14 @@ class MapRoutingTest < ActionController::TestCase
assert_recognizes({:controller => 'devise/registrations', :action => 'destroy'}, {:path => 'users', :method => :delete})
end
protected
def assert_named_route(result, name)
assert_equal result, @routes.url_helpers.send(name)
end
end
class CustomizedRoutingTest < ActionController::TestCase
test 'map admin with :path option' do
assert_recognizes({:controller => 'devise/registrations', :action => 'new'}, {:path => 'admin_area/sign_up', :method => :get})
end
@@ -112,3 +132,15 @@ class MapRoutingTest < ActionController::TestCase
assert_recognizes({:controller => 'devise/registrations', :action => 'new', :locale => 'en'}, '/en/accounts/management/register')
end
end
class ScopedRoutingTest < ActionController::TestCase
test 'map publisher account' do
assert_recognizes({:controller => 'publisher/registrations', :action => 'new'}, {:path => '/publisher/accounts/sign_up', :method => :get})
assert_equal '/publisher/accounts/sign_up', @routes.url_helpers.new_publisher_account_registration_path
end
test 'map publisher account merges path names' do
assert_recognizes({:controller => 'publisher/sessions', :action => 'new'}, {:path => '/publisher/accounts/get_in', :method => :get})
assert_equal '/publisher/accounts/get_in', @routes.url_helpers.new_publisher_account_session_path
end
end

View File

@@ -37,6 +37,12 @@ class ActiveSupport::TestCase
User.create!(valid_attributes(attributes))
end
def create_admin(attributes={})
valid_attributes = valid_attributes(attributes)
valid_attributes.delete(:username)
Admin.create!(valid_attributes)
end
# Execute the block setting the given values and restoring old values after
# the block is executed.
def swap(object, new_values)

View File

@@ -31,7 +31,7 @@ class ActionDispatch::IntegrationTest
def sign_in_as_user(options={}, &block)
user = create_user(options)
get new_user_session_path unless options[:visit] == false
visit_with_option options[:visit], new_user_session_path
fill_in 'email', :with => 'user@test.com'
fill_in 'password', :with => options[:password] || '123456'
check 'remember me' if options[:remember_me] == true
@@ -42,7 +42,7 @@ class ActionDispatch::IntegrationTest
def sign_in_as_admin(options={}, &block)
admin = create_admin(options)
get new_admin_session_path unless options[:visit] == false
visit_with_option options[:visit], new_admin_session_path
fill_in 'email', :with => 'admin@test.com'
fill_in 'password', :with => '123456'
yield if block_given?
@@ -57,16 +57,32 @@ class ActionDispatch::IntegrationTest
assert [301, 302].include?(@integration_session.status),
"Expected status to be 301 or 302, got #{@integration_session.status}"
url = prepend_host(url)
location = prepend_host(@integration_session.headers["Location"])
assert_equal url, location
assert_url url, @integration_session.headers["Location"]
end
def assert_current_url(expected)
assert_url expected, current_url
end
def assert_url(expected, actual)
assert_equal prepend_host(expected), prepend_host(actual)
end
protected
def visit_with_option(given, default)
case given
when String
visit given
when FalseClass
# Do nothing
else
visit default
end
end
def prepend_host(url)
url = "http://#{request.host}#{url}" if url[0] == ?/
url
end
end

View File

@@ -1,9 +1,9 @@
require 'webrat/core/elements/field'
require 'webrat/core/elements/form'
require 'action_dispatch/testing/integration'
module Webrat
Field.class_eval do
def parse_rails_request_params(params)
Form.class_eval do
def self.parse_rails_request_params(params)
Rack::Utils.parse_nested_query(params)
end
end
@@ -13,20 +13,5 @@ module ActionDispatch #:nodoc:
IntegrationTest.class_eval do
include Webrat::Methods
include Webrat::Matchers
# The Rails version of within supports passing in a model and Webrat
# will apply a scope based on Rails' dom_id for that model.
#
# Example:
# within User.last do
# click_link "Delete"
# end
def within(selector_or_object, &block)
if selector_or_object.is_a?(String)
super
else
super('#' + RecordIdentifier.dom_id(selector_or_object), &block)
end
end
end
end
end

View File

@@ -9,8 +9,9 @@ require "rails/test_help"
require "orm/#{DEVISE_ORM}"
I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__)
require 'mocha'
require 'mocha'
require 'webrat'
Webrat.configure do |config|
config.mode = :rails
config.open_error_files = false
@@ -18,4 +19,4 @@ end
# Add support to load paths so we can overwrite broken webrat setup
$:.unshift File.expand_path('../support', __FILE__)
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }

View File

@@ -10,14 +10,28 @@ class TestHelpersTest < ActionController::TestCase
assert_equal "You need to sign in or sign up before continuing.", flash[:alert]
end
test "redirects if attempting to access a page with a unconfirmed account" do
test "redirects if attempting to access a page with an unconfirmed account" do
swap Devise, :confirm_within => 0 do
sign_in create_user
user = create_user
assert !user.active?
sign_in user
get :index
assert_redirected_to new_user_session_path
end
end
test "returns nil if accessing current_user with an unconfirmed account" do
swap Devise, :confirm_within => 0 do
user = create_user
assert !user.active?
sign_in user
get :accept, :id => user
assert_nil assigns(:current_user)
end
end
test "does not redirect with valid user" do
user = create_user
user.confirm!