mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-09 23:58:06 -05:00
Compare commits
410 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
442beefa9b | ||
|
|
61fe99577d | ||
|
|
dc3bfac876 | ||
|
|
426223dda0 | ||
|
|
5909d6a0c5 | ||
|
|
5570929b56 | ||
|
|
5ba6670164 | ||
|
|
589442b09b | ||
|
|
0c67cff2a0 | ||
|
|
9c3d5705b5 | ||
|
|
2f2662e7a5 | ||
|
|
99040535d7 | ||
|
|
582f00ed95 | ||
|
|
1d2f906af1 | ||
|
|
dfb8ff372d | ||
|
|
1e37e42239 | ||
|
|
ce1bd142e2 | ||
|
|
35015e5ceb | ||
|
|
03b56ffd1f | ||
|
|
065963f6d3 | ||
|
|
a71319a080 | ||
|
|
9ea7249368 | ||
|
|
301e24c06c | ||
|
|
6b108404ba | ||
|
|
0b661b6d7f | ||
|
|
3ab68a6896 | ||
|
|
97d8e39932 | ||
|
|
5c71c1cf19 | ||
|
|
dc8aa9ef83 | ||
|
|
ab54e1f66a | ||
|
|
0fd5493220 | ||
|
|
5c3f75d90a | ||
|
|
e8aabd4652 | ||
|
|
350bd188df | ||
|
|
7e9ba53d82 | ||
|
|
16208f7ad7 | ||
|
|
cc822e08aa | ||
|
|
c3880e52e4 | ||
|
|
a5aa03b983 | ||
|
|
06b7baabcc | ||
|
|
b7cffeed8c | ||
|
|
380df0121b | ||
|
|
611e0335cc | ||
|
|
22136a708b | ||
|
|
2a29e87eb9 | ||
|
|
ea9e8c0c9b | ||
|
|
58d61c290a | ||
|
|
bad6049d73 | ||
|
|
24b26026ef | ||
|
|
4629beecd7 | ||
|
|
f67793cb0d | ||
|
|
538c16cd00 | ||
|
|
3a26eea0cc | ||
|
|
f9ef2cd32e | ||
|
|
493ddbd99e | ||
|
|
f00d9c5eff | ||
|
|
95be78ac5e | ||
|
|
e9c263c326 | ||
|
|
1bace6df4e | ||
|
|
0439c35198 | ||
|
|
a816e538ab | ||
|
|
bbd117bd92 | ||
|
|
d448e7d841 | ||
|
|
6fcfba229d | ||
|
|
d525636423 | ||
|
|
d11402612f | ||
|
|
6079a025ca | ||
|
|
81f0c203a9 | ||
|
|
60822641cb | ||
|
|
fac02b58bc | ||
|
|
c9902f34d1 | ||
|
|
8b45c0a856 | ||
|
|
2a5ad4664b | ||
|
|
b98720d324 | ||
|
|
3f0b5fbd71 | ||
|
|
fa1034b04c | ||
|
|
13ed2183ee | ||
|
|
6fae1f60fd | ||
|
|
a46144e022 | ||
|
|
2372823fd8 | ||
|
|
52282a5a26 | ||
|
|
96f55a7ac7 | ||
|
|
990dcc8eef | ||
|
|
76bff0d4de | ||
|
|
59f2767345 | ||
|
|
bba6562dcc | ||
|
|
f3aa5e40fb | ||
|
|
1e2dab3c0c | ||
|
|
bc8fc2d4e4 | ||
|
|
15b76e93d1 | ||
|
|
bc2a311a38 | ||
|
|
f19955705f | ||
|
|
e4902af15a | ||
|
|
ab9d856568 | ||
|
|
dd1d128333 | ||
|
|
a629654a15 | ||
|
|
08a8d7bf51 | ||
|
|
335d36088f | ||
|
|
0b9a95e294 | ||
|
|
98acc84111 | ||
|
|
261c01dfa3 | ||
|
|
dbda19f658 | ||
|
|
8067022d98 | ||
|
|
72ba56b071 | ||
|
|
30046f35d7 | ||
|
|
10451e9e38 | ||
|
|
ea7f15917f | ||
|
|
df3e711ee0 | ||
|
|
263e903046 | ||
|
|
f7bbac0ab9 | ||
|
|
9ebcb691b0 | ||
|
|
601e1d3dc9 | ||
|
|
7b0a8f9bdc | ||
|
|
dd36324756 | ||
|
|
1b5d0af824 | ||
|
|
edcca8cd3f | ||
|
|
c95ca15b49 | ||
|
|
055117e07a | ||
|
|
ebbabaea5b | ||
|
|
eba53f8f94 | ||
|
|
071f54ac59 | ||
|
|
8796c1c601 | ||
|
|
ef4eb47d50 | ||
|
|
295088f9e8 | ||
|
|
4222afe3c7 | ||
|
|
79d89a3c20 | ||
|
|
8ad414b217 | ||
|
|
7b1418be3b | ||
|
|
7396c6911d | ||
|
|
673c707085 | ||
|
|
f21d05a235 | ||
|
|
1dd19c1a72 | ||
|
|
a8d9695324 | ||
|
|
99d539b9a7 | ||
|
|
179cb2c88a | ||
|
|
9629da863d | ||
|
|
4f76e6f577 | ||
|
|
0f3cef4091 | ||
|
|
7665cbf21d | ||
|
|
b9413ab316 | ||
|
|
a3bff7d6a2 | ||
|
|
7e54dc7903 | ||
|
|
fb1220af97 | ||
|
|
282c7e85ec | ||
|
|
bc15bb53dc | ||
|
|
a729e059de | ||
|
|
7c628f7689 | ||
|
|
6d65c28f1f | ||
|
|
31e4ef5e4b | ||
|
|
d38341b5e0 | ||
|
|
ff90d9da9c | ||
|
|
84c62ed034 | ||
|
|
e76ba05516 | ||
|
|
90d99b16f1 | ||
|
|
3cedba1de8 | ||
|
|
ccbf26be0a | ||
|
|
6448490de5 | ||
|
|
98651dae9d | ||
|
|
bf57ef400d | ||
|
|
27cae04446 | ||
|
|
430eadc1b2 | ||
|
|
e954737a92 | ||
|
|
191d5222e7 | ||
|
|
e77af4b40f | ||
|
|
da3c47259d | ||
|
|
c95575b284 | ||
|
|
7a5086a2be | ||
|
|
c3a665320e | ||
|
|
372dfecf05 | ||
|
|
68bd6809a7 | ||
|
|
7bfdd07a71 | ||
|
|
6bc93173f1 | ||
|
|
55af9f8a40 | ||
|
|
866b35d27c | ||
|
|
5374119f18 | ||
|
|
919404df53 | ||
|
|
fd07c74578 | ||
|
|
560961e3fc | ||
|
|
873e49ab66 | ||
|
|
0f8f786f9f | ||
|
|
7b3e267729 | ||
|
|
7264bb55b2 | ||
|
|
ed6dfed67f | ||
|
|
3488066031 | ||
|
|
bc9ea93f50 | ||
|
|
1920b79a0d | ||
|
|
9131570703 | ||
|
|
770c1a973f | ||
|
|
b7b21a0b72 | ||
|
|
4d91fb4910 | ||
|
|
4ce9d6f29a | ||
|
|
d2a4c503f7 | ||
|
|
a2700bc17f | ||
|
|
0a04d73883 | ||
|
|
502dae3c1f | ||
|
|
e9c766277d | ||
|
|
762f3907fa | ||
|
|
3698b64a10 | ||
|
|
2a6c160d39 | ||
|
|
795754cd60 | ||
|
|
517343ddb5 | ||
|
|
90a5e2f9af | ||
|
|
93180fbb6d | ||
|
|
04cb78947a | ||
|
|
5423f2d5cb | ||
|
|
51d15b7293 | ||
|
|
7a2e018df8 | ||
|
|
1fd4beb18a | ||
|
|
33d7644b4f | ||
|
|
5a98e4f4e8 | ||
|
|
82ae53dd75 | ||
|
|
07db04e773 | ||
|
|
6a8ee475fd | ||
|
|
767a7a7c21 | ||
|
|
a3b56f7eb1 | ||
|
|
5e1a998cde | ||
|
|
219fbc0056 | ||
|
|
dcee6413f4 | ||
|
|
e2895239d8 | ||
|
|
c8077c8d9f | ||
|
|
46c2d5a8f2 | ||
|
|
adb127bb3e | ||
|
|
42f0285278 | ||
|
|
13ef23f517 | ||
|
|
0bf28b19ab | ||
|
|
29a0af78bc | ||
|
|
cf487c771e | ||
|
|
7e711089a8 | ||
|
|
1c81a40a76 | ||
|
|
dba8f91f99 | ||
|
|
8e70e71143 | ||
|
|
f43a7c4f24 | ||
|
|
4e56d92ed8 | ||
|
|
5645d733ba | ||
|
|
42b07f1f47 | ||
|
|
e75354b3b0 | ||
|
|
80122856c4 | ||
|
|
308238ab42 | ||
|
|
e937cf78cf | ||
|
|
2ae2fdc9f8 | ||
|
|
3184834d72 | ||
|
|
8ef5534d92 | ||
|
|
41bb96be5d | ||
|
|
b37055fa47 | ||
|
|
515b727f52 | ||
|
|
77d6d1e8c2 | ||
|
|
04b614ce10 | ||
|
|
62e11ddbe4 | ||
|
|
8e3ab5921f | ||
|
|
1d87997647 | ||
|
|
b58e0ef991 | ||
|
|
db959da247 | ||
|
|
6199252011 | ||
|
|
40c0a7b50b | ||
|
|
422bc4aaa6 | ||
|
|
225c89fbf1 | ||
|
|
76281ff15c | ||
|
|
8b54ff699f | ||
|
|
7d160650b8 | ||
|
|
803e46cda7 | ||
|
|
004fe2ad12 | ||
|
|
09baf2091e | ||
|
|
135a94b4f7 | ||
|
|
a41d185768 | ||
|
|
c3432e57b1 | ||
|
|
a8d88d193e | ||
|
|
471e4d6e72 | ||
|
|
14fec4cfb3 | ||
|
|
4bcd1c6fcd | ||
|
|
84e1a89c44 | ||
|
|
e0162df465 | ||
|
|
7631456047 | ||
|
|
2bc51ab2bd | ||
|
|
d23ecef831 | ||
|
|
c0017ce76d | ||
|
|
30f9da9d71 | ||
|
|
e242ca0937 | ||
|
|
17596b0dc6 | ||
|
|
8e87a2d80d | ||
|
|
4964f53a42 | ||
|
|
6250fa8529 | ||
|
|
944e1c0378 | ||
|
|
4f446241a4 | ||
|
|
97659a1193 | ||
|
|
0bcf71f8df | ||
|
|
ab3bb9cf4d | ||
|
|
69126a31db | ||
|
|
03e3803cff | ||
|
|
58f8c7c613 | ||
|
|
acd1c76c3b | ||
|
|
4c8cc5e3f3 | ||
|
|
72bb33f962 | ||
|
|
2e61e52520 | ||
|
|
75490d0375 | ||
|
|
0fbe4cb6b9 | ||
|
|
d2b3f49384 | ||
|
|
136992b8df | ||
|
|
a130f848f2 | ||
|
|
e10bc9e3c0 | ||
|
|
d56741ca4f | ||
|
|
92c9ed2d6c | ||
|
|
50a5ad54ce | ||
|
|
9dcb44ba61 | ||
|
|
8bdc4b544f | ||
|
|
e763f843c4 | ||
|
|
b5732e31c6 | ||
|
|
ea24ffdd51 | ||
|
|
56f7fbf2d1 | ||
|
|
89b53ea39c | ||
|
|
9cc69277bc | ||
|
|
7e79ed6d4e | ||
|
|
b5190d8df2 | ||
|
|
b03c93c4fe | ||
|
|
8e12ddf7ed | ||
|
|
4fd866d113 | ||
|
|
a59410a254 | ||
|
|
b1a27ad633 | ||
|
|
4a3ad7f348 | ||
|
|
89e4ab8a45 | ||
|
|
fd8e34650e | ||
|
|
e26c8ce499 | ||
|
|
64cf8a4534 | ||
|
|
ae976f60ca | ||
|
|
f152860bc5 | ||
|
|
40153b7422 | ||
|
|
fdfe6a8340 | ||
|
|
79c100008a | ||
|
|
f132c7891b | ||
|
|
bdad984ace | ||
|
|
a229627a54 | ||
|
|
0b598cf132 | ||
|
|
0e657eece1 | ||
|
|
b6cf1df659 | ||
|
|
29afe2d21c | ||
|
|
a722c6236c | ||
|
|
14aedc416a | ||
|
|
9fe0cb4954 | ||
|
|
2a5669967f | ||
|
|
13376d22de | ||
|
|
6b21531916 | ||
|
|
4a4dcb30ef | ||
|
|
2cfa58b433 | ||
|
|
c6dd846718 | ||
|
|
7a2d76d002 | ||
|
|
e5a8febe3b | ||
|
|
60809719b8 | ||
|
|
ee6a8ab93a | ||
|
|
c3d92095f8 | ||
|
|
460beae671 | ||
|
|
fa6c8ab321 | ||
|
|
d02f86bef5 | ||
|
|
0d74c1b4f0 | ||
|
|
8f3539c14f | ||
|
|
3d5e692c2c | ||
|
|
cb622e99d8 | ||
|
|
567d59e48a | ||
|
|
f89f71262d | ||
|
|
5e2ee5eb6a | ||
|
|
34a54dac2d | ||
|
|
e329930a82 | ||
|
|
3940846d79 | ||
|
|
c608fbe89e | ||
|
|
8db00eedea | ||
|
|
0e904dda79 | ||
|
|
e4af6adaf7 | ||
|
|
e1c7c49a0c | ||
|
|
bd9f148d24 | ||
|
|
f009011179 | ||
|
|
5adb854aa5 | ||
|
|
1f51524bae | ||
|
|
23f8dbed80 | ||
|
|
140acfe4cc | ||
|
|
cb2cb2cff7 | ||
|
|
30300fc6b9 | ||
|
|
de8982563a | ||
|
|
e7154b3af9 | ||
|
|
39360dc419 | ||
|
|
eeb61929ac | ||
|
|
56fd7031e5 | ||
|
|
425fe7f22d | ||
|
|
ed51fc7636 | ||
|
|
d23a7ca8d5 | ||
|
|
1b1dc2a429 | ||
|
|
be2aeee70f | ||
|
|
8a3deb98cd | ||
|
|
e4902143f8 | ||
|
|
d3a374777b | ||
|
|
5b94d9b803 | ||
|
|
b6652abc7c | ||
|
|
97f0bacfa0 | ||
|
|
210bc6aa66 | ||
|
|
8170d5e340 | ||
|
|
6225902034 | ||
|
|
0487e9eafe | ||
|
|
73669e09c8 | ||
|
|
da510508bb | ||
|
|
02ae0c22ef | ||
|
|
edee511cd1 | ||
|
|
fbd35ec332 | ||
|
|
30b35e3727 | ||
|
|
330cafd3d2 | ||
|
|
fe9024218c | ||
|
|
0c9bd3259e | ||
|
|
b23e2e807a | ||
|
|
7876acf960 | ||
|
|
74166e224b | ||
|
|
cb778d033f | ||
|
|
1bf7da148a | ||
|
|
d58a72ee32 | ||
|
|
15d195d2f0 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,4 +7,6 @@ coverage/*
|
||||
rdoc/*
|
||||
pkg
|
||||
log
|
||||
test/tmp/*
|
||||
test/tmp/*
|
||||
Gemfile.lock
|
||||
|
||||
|
||||
14
.travis.yml
14
.travis.yml
@@ -1 +1,13 @@
|
||||
script: "rake test"
|
||||
script: "bundle exec rake test"
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- ree
|
||||
- rbx
|
||||
- rbx-2.0
|
||||
notifications:
|
||||
recipients:
|
||||
- jose.valim@plataformatec.com.br
|
||||
- carlos@plataformatec.com.br
|
||||
- rodrigo.flores@plataformatec.com.br
|
||||
- rafael.franca@plataformatec.com.br
|
||||
|
||||
180
CHANGELOG.rdoc
180
CHANGELOG.rdoc
@@ -1,3 +1,183 @@
|
||||
== 1.5.2
|
||||
|
||||
* enhancements
|
||||
* Add support for rails 3.1 new mass assignment conventions (by github.com/kirs)
|
||||
* timeout_in option can be a Proc object (by github.com/lest)
|
||||
|
||||
* bug fix
|
||||
* OmniAuth error message now shows the proper option (:strategy_class instead of :klass)
|
||||
|
||||
== 1.5.1
|
||||
|
||||
* bug fix
|
||||
* Devise should not attempt to load OmniAuth strategies. Strategies should be loaded before hand by the developer or explicitly given to Devise.
|
||||
|
||||
== 1.5.0
|
||||
|
||||
* enhancements
|
||||
* Timeoutable also skips tracking if skip_trackable is given
|
||||
* devise_for now accepts :failure_app as an option
|
||||
* Models can select the proper mailer via devise_mailer method (by github.com/locomotivecms)
|
||||
* Migration generator now uses the change method (by github.com/nashby)
|
||||
* Support to markerb templates on the mailer generator (by github.com/sbounmy)
|
||||
* Support for Omniauth 1.0 (older versions are no longer supported) (by github.com/TamiasSibiricus)
|
||||
|
||||
* bug fix
|
||||
* Allow idempotent API requests
|
||||
* Fix bug where logs did not show 401 as status code
|
||||
* Change paranoid settings to behave as success instead of as failure
|
||||
* Fix bug where activation messages were shown first than the credentials error message
|
||||
* Instance variables are expired after sign out
|
||||
|
||||
* deprecation
|
||||
* redirect_location is deprecated, please use after_sign_in_path_for
|
||||
* after_sign_in_path_for now redirects to session[scope_return_to] if any value is stored in it
|
||||
|
||||
== 1.4.9
|
||||
|
||||
* bug fix
|
||||
* url helpers were not being set under some circumstances
|
||||
|
||||
== 1.4.8
|
||||
|
||||
* enhancements
|
||||
* Add docs for assets pipeline and Heroku
|
||||
|
||||
* bug fix
|
||||
* confirmation_url was not being set under some circumstances
|
||||
|
||||
== 1.4.7
|
||||
|
||||
* bug fix
|
||||
* Fix backward incompatible change from 1.4.6 for those using custom controllers
|
||||
|
||||
== 1.4.6
|
||||
|
||||
* enhancements
|
||||
* Allow devise_for :skip => :all
|
||||
* Allow options to be passed to authenticate_user!
|
||||
* Allow --skip-routes to devise generator
|
||||
* Add allow_params_authentication! to make it explicit when params authentication is allowed in a controller
|
||||
|
||||
== 1.4.5
|
||||
|
||||
* bug fix
|
||||
* Failure app tries the root path if a session one does not exist
|
||||
* No need to finalize Devise helpers all the time (by github.com/bradleypriest)
|
||||
* Reset password shows proper message if user is not active
|
||||
* `clean_up_passwords` sets the accessors to nil to skip validations
|
||||
|
||||
== 1.4.4
|
||||
|
||||
* bug fix
|
||||
* Do not always skip helpers, instead provide :skip_helpers as option to trigger it manually
|
||||
|
||||
== 1.4.3
|
||||
|
||||
* enhancements
|
||||
* Improve Rails 3.1 compatibility
|
||||
* Use serialize_into_session and serialize_from_session in Warden serialize to improve extensibility
|
||||
|
||||
* bug fix
|
||||
* Generator properly generates a change_table migration if a model already exists
|
||||
* Properly deprecate setup_mail
|
||||
* Fix encoding issues with email regexp
|
||||
* Only generate helpers for the used mappings
|
||||
* Wrap :action constraints in the proper hash
|
||||
|
||||
* deprecations
|
||||
* Loosened the used email regexp to simply assert the existent of "@". If someone relies on a more strict regexp, they may use https://github.com/SixArm/sixarm_ruby_email_address_validation
|
||||
|
||||
== 1.4.2
|
||||
|
||||
* bug fix
|
||||
* Provide a more robust behavior to serializers and add :force_except option
|
||||
|
||||
== 1.4.1
|
||||
|
||||
* enhancements
|
||||
* Add :defaults and :format support on router
|
||||
* Add simple form generators
|
||||
* Better localization for devise_error_messages! (by github.com/zedtux)
|
||||
|
||||
* bug fix
|
||||
* Ensure to_xml is properly white listened
|
||||
* Ensure handle_unverified_request clean up any cached signed-in user
|
||||
|
||||
== 1.4.0
|
||||
|
||||
* enhancements
|
||||
* Added authenticated and unauthenticated to the router to route the used based on his status (by github.com/sj26)
|
||||
* Improve e-mail regexp (by github.com/rodrigoflores)
|
||||
* Add strip_whitespace_keys and default to e-mail (by github.com/swrobel)
|
||||
* Do not run format and uniqueness validations on e-mail if it hasn't changed (by github.com/Thibaut)
|
||||
* Added update_without_password to update models but not allowing the password to change (by github.com/fschwahn)
|
||||
* Added config.paranoid, check the generator for more information (by github.com/rodrigoflores)
|
||||
|
||||
* bug fix
|
||||
* password_required? should not affect length validation
|
||||
* User cannot access sign up and similar pages if he is already signed in through a cookie or token
|
||||
* Do not convert booleans to strings on finders (by github.com/xavier)
|
||||
* Run validations even if current_password fails (by github.com/crx)
|
||||
* Devise now honors routes constraints (by github.com/macmartine)
|
||||
* Do not return the user resource when requesting instructions (by github.com/rodrigoflores)
|
||||
|
||||
== 1.3.4
|
||||
|
||||
* bug fix
|
||||
* Do not add formats if html or "*/*"
|
||||
|
||||
== 1.3.3
|
||||
|
||||
* bug fix
|
||||
* Explicitly mark the token as expired if so
|
||||
|
||||
== 1.3.2
|
||||
|
||||
* bug fix
|
||||
* Fix another regression related to reset_password_sent_at (by github.com/alexdreher)
|
||||
|
||||
== 1.3.1
|
||||
|
||||
* enhancements
|
||||
* Improve failure_app responses (by github.com/indirect)
|
||||
* sessions/new and registrations/new also respond to xml and json now
|
||||
|
||||
* bug fix
|
||||
* Fix a regression that occurred if reset_password_sent_at is not present (by github.com/stevehodgkiss)
|
||||
|
||||
== 1.3.0
|
||||
|
||||
* enhancements
|
||||
* All controllers can now handle different mime types than html using Responders (by github.com/sikachu)
|
||||
* Added reset_password_within as configuration option to send the token for recovery (by github.com/jdguyot)
|
||||
* Bump password length to 128 characters (by github.com/k33l0r)
|
||||
* Add :only as option to devise_for (by github.com/timoschilling)
|
||||
* Allow to override path after sending password instructions (by github.com/irohiroki)
|
||||
* require_no_authentication has its own flash message (by github.com/jackdempsey)
|
||||
|
||||
* bug fix
|
||||
* Fix a bug where configuration options were being included too late
|
||||
* Ensure Devise::TestHelpers can be used to tests Devise internal controllers (by github.com/jwilger)
|
||||
* valid_password? should not choke on empty passwords (by github.com/mikel)
|
||||
* Calling devise more than once does not include previously added modules anymore
|
||||
* downcase_keys before validation
|
||||
|
||||
* backward incompatible changes
|
||||
* authentication_keys are no longer considered when creating the e-mail validations, the previous behavior was buggy. You must double check if you were relying on such behavior.
|
||||
|
||||
== 1.2.1
|
||||
|
||||
* enhancements
|
||||
* Improve update path messages
|
||||
|
||||
== 1.2.0
|
||||
|
||||
* bug fix
|
||||
* Properly ignore path prefix on omniauthable
|
||||
* Faster uniqueness queries
|
||||
* Rename active? to active_for_authentication? to avoid conflicts
|
||||
|
||||
== 1.2.rc2
|
||||
|
||||
* enhancements
|
||||
|
||||
28
Gemfile
28
Gemfile
@@ -2,28 +2,34 @@ source "http://rubygems.org"
|
||||
|
||||
gemspec
|
||||
|
||||
gem "rails", "~> 3.0.4"
|
||||
gem "oa-oauth", '~> 0.2.0', :require => "omniauth/oauth"
|
||||
gem "oa-openid", '~> 0.2.0', :require => "omniauth/openid"
|
||||
gem "rails", "~> 3.1.0"
|
||||
gem "omniauth", "~> 1.0.0"
|
||||
gem "omniauth-oauth2", "~> 1.0.0"
|
||||
gem "rdoc"
|
||||
|
||||
group :test do
|
||||
gem "omniauth-facebook"
|
||||
gem "omniauth-openid", "~> 1.0.1"
|
||||
gem "webrat", "0.7.2", :require => false
|
||||
gem "mocha", :require => false
|
||||
|
||||
platforms :mri_18 do
|
||||
gem "ruby-debug", ">= 0.10.3"
|
||||
end
|
||||
end
|
||||
|
||||
platforms :jruby do
|
||||
gem 'activerecord-jdbcsqlite3-adapter'
|
||||
gem "activerecord-jdbc-adapter"
|
||||
gem "activerecord-jdbcsqlite3-adapter"
|
||||
gem "jruby-openssl"
|
||||
end
|
||||
|
||||
platforms :ruby do
|
||||
group :test do
|
||||
gem "sqlite3-ruby"
|
||||
gem "ruby-debug", ">= 0.10.3" if RUBY_VERSION < '1.9'
|
||||
end
|
||||
gem "sqlite3-ruby"
|
||||
|
||||
group :mongoid do
|
||||
gem "mongo", "1.1.2"
|
||||
gem "mongoid", "2.0.0.beta.20"
|
||||
gem "bson_ext", "1.2.1"
|
||||
gem "mongo", "~> 1.3.0"
|
||||
gem "mongoid", "~> 2.0"
|
||||
gem "bson_ext", "~> 1.3.0"
|
||||
end
|
||||
end
|
||||
|
||||
158
Gemfile.lock
158
Gemfile.lock
@@ -1,158 +0,0 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
devise (1.2.rc)
|
||||
bcrypt-ruby (~> 2.1.2)
|
||||
orm_adapter (~> 0.0.3)
|
||||
warden (~> 1.0.3)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
abstract (1.0.0)
|
||||
actionmailer (3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
mail (~> 2.2.15)
|
||||
actionpack (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
builder (~> 2.1.2)
|
||||
erubis (~> 2.6.6)
|
||||
i18n (~> 0.4)
|
||||
rack (~> 1.2.1)
|
||||
rack-mount (~> 0.6.13)
|
||||
rack-test (~> 0.5.7)
|
||||
tzinfo (~> 0.3.23)
|
||||
activemodel (3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
builder (~> 2.1.2)
|
||||
i18n (~> 0.4)
|
||||
activerecord (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
arel (~> 2.0.2)
|
||||
tzinfo (~> 0.3.23)
|
||||
activerecord-jdbc-adapter (1.1.1)
|
||||
activerecord-jdbcsqlite3-adapter (1.1.1)
|
||||
activerecord-jdbc-adapter (= 1.1.1)
|
||||
jdbc-sqlite3 (~> 3.6.0)
|
||||
activeresource (3.0.4)
|
||||
activemodel (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
activesupport (3.0.4)
|
||||
addressable (2.2.4)
|
||||
arel (2.0.8)
|
||||
bcrypt-ruby (2.1.4)
|
||||
bson (1.2.1)
|
||||
bson_ext (1.2.1)
|
||||
builder (2.1.2)
|
||||
columnize (0.3.2)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
faraday (0.5.7)
|
||||
addressable (~> 2.2.4)
|
||||
multipart-post (~> 1.1.0)
|
||||
rack (>= 1.1.0, < 2)
|
||||
i18n (0.5.0)
|
||||
jdbc-sqlite3 (3.6.14.2.056-java)
|
||||
linecache (0.43)
|
||||
mail (2.2.15)
|
||||
activesupport (>= 2.3.6)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.16)
|
||||
mocha (0.9.12)
|
||||
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)
|
||||
multi_json (0.0.5)
|
||||
multipart-post (1.1.0)
|
||||
nokogiri (1.4.4)
|
||||
nokogiri (1.4.4-java)
|
||||
weakling (>= 0.0.3)
|
||||
oa-core (0.2.0)
|
||||
rack (~> 1.1)
|
||||
oa-oauth (0.2.0)
|
||||
multi_json (~> 0.0.2)
|
||||
nokogiri (~> 1.4.2)
|
||||
oa-core (= 0.2.0)
|
||||
oauth (~> 0.4.0)
|
||||
oauth2 (~> 0.1.1)
|
||||
oa-openid (0.2.0)
|
||||
oa-core (= 0.2.0)
|
||||
rack-openid (~> 1.2.0)
|
||||
ruby-openid-apps-discovery
|
||||
oauth (0.4.4)
|
||||
oauth2 (0.1.1)
|
||||
faraday (~> 0.5.0)
|
||||
multi_json (~> 0.0.4)
|
||||
orm_adapter (0.0.4)
|
||||
polyglot (0.3.1)
|
||||
rack (1.2.1)
|
||||
rack-mount (0.6.13)
|
||||
rack (>= 1.0.0)
|
||||
rack-openid (1.2.0)
|
||||
rack (>= 1.1.0)
|
||||
ruby-openid (>= 2.1.8)
|
||||
rack-test (0.5.7)
|
||||
rack (>= 1.0)
|
||||
rails (3.0.4)
|
||||
actionmailer (= 3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
activerecord (= 3.0.4)
|
||||
activeresource (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.0.4)
|
||||
railties (3.0.4)
|
||||
actionpack (= 3.0.4)
|
||||
activesupport (= 3.0.4)
|
||||
rake (>= 0.8.7)
|
||||
thor (~> 0.14.4)
|
||||
rake (0.8.7)
|
||||
ruby-debug (0.10.4)
|
||||
columnize (>= 0.1)
|
||||
ruby-debug-base (~> 0.10.4.0)
|
||||
ruby-debug-base (0.10.4)
|
||||
linecache (>= 0.3)
|
||||
ruby-openid (2.1.8)
|
||||
ruby-openid-apps-discovery (1.2.0)
|
||||
ruby-openid (>= 2.1.7)
|
||||
sqlite3 (1.3.3)
|
||||
sqlite3-ruby (1.3.3)
|
||||
sqlite3 (>= 1.3.3)
|
||||
thor (0.14.6)
|
||||
treetop (1.4.9)
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.24)
|
||||
warden (1.0.3)
|
||||
rack (>= 1.0.0)
|
||||
weakling (0.0.4-java)
|
||||
webrat (0.7.2)
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
will_paginate (3.0.pre2)
|
||||
|
||||
PLATFORMS
|
||||
java
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activerecord-jdbcsqlite3-adapter
|
||||
bson_ext (= 1.2.1)
|
||||
devise!
|
||||
mocha
|
||||
mongo (= 1.1.2)
|
||||
mongoid (= 2.0.0.beta.20)
|
||||
oa-oauth (~> 0.2.0)
|
||||
oa-openid (~> 0.2.0)
|
||||
rails (~> 3.0.4)
|
||||
ruby-debug (>= 0.10.3)
|
||||
sqlite3-ruby
|
||||
webrat (= 0.7.2)
|
||||
68
README.rdoc
68
README.rdoc
@@ -1,5 +1,7 @@
|
||||
== Devise
|
||||
|
||||
{<img src="https://secure.travis-ci.org/plataformatec/devise.png" />}[http://travis-ci.org/plataformatec/devise]
|
||||
|
||||
Devise is a flexible authentication solution for Rails based on Warden. It:
|
||||
|
||||
* Is Rack based;
|
||||
@@ -7,7 +9,7 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
|
||||
* Allows you to have multiple roles (or models/scopes) signed in at the same time;
|
||||
* Is based on a modularity concept: use just what you really need.
|
||||
|
||||
It's composed of 12 modules:
|
||||
It's comprised of 12 modules:
|
||||
|
||||
* Database Authenticatable: encrypts and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
|
||||
* Token Authenticatable: signs in a user based on an authentication token (also known as "single access token"). The token can be given both through query string or HTTP Basic Authentication.
|
||||
@@ -28,13 +30,13 @@ It's composed of 12 modules:
|
||||
|
||||
The Devise Wiki has lots of additional information about Devise including many "how-to" articles and answers to the most frequently asked questions. Please browse the Wiki after finishing this README:
|
||||
|
||||
http://wiki.github.com/plataformatec/devise
|
||||
https://wiki.github.com/plataformatec/devise
|
||||
|
||||
=== Bug reports
|
||||
|
||||
If you discover a problem with Devise, we would like to know about it. However, we ask that you please review these guidelines before submitting a bug report:
|
||||
|
||||
http://github.com/plataformatec/devise/wiki/Bug-reports
|
||||
https://github.com/plataformatec/devise/wiki/Bug-reports
|
||||
|
||||
If you found a security bug, do *NOT* use the GitHub issue tracker. Send email or a private GitHub message to the maintainers listed at the bottom of the README.
|
||||
|
||||
@@ -42,7 +44,7 @@ If you found a security bug, do *NOT* use the GitHub issue tracker. Send email o
|
||||
|
||||
If you have any questions, comments, or concerns, please use the Google Group instead of the GitHub issue tracker:
|
||||
|
||||
http://groups.google.com/group/plataformatec-devise
|
||||
https://groups.google.com/group/plataformatec-devise
|
||||
|
||||
=== RDocs
|
||||
|
||||
@@ -56,19 +58,19 @@ If you need to use Devise with Rails 2.3, you can always run `gem server` from t
|
||||
|
||||
There are a few example applications available on GitHub that demonstrate various features of Devise with different versions of Rails. You can view them here:
|
||||
|
||||
http://github.com/plataformatec/devise/wiki/Example-Applications
|
||||
https://github.com/plataformatec/devise/wiki/Example-Applications
|
||||
|
||||
=== Extensions
|
||||
|
||||
Our community has created a number of extensions that add functionality above and beyond what is included with Devise. You can view a list of available extensions and add your own here:
|
||||
|
||||
http://github.com/plataformatec/devise/wiki/Extensions
|
||||
https://github.com/plataformatec/devise/wiki/Extensions
|
||||
|
||||
=== Contributing
|
||||
|
||||
We hope that you will consider contributing to Devise. Please read this short overview for some information about how to get started:
|
||||
|
||||
http://github.com/plataformatec/devise/wiki/Contributing
|
||||
https://github.com/plataformatec/devise/wiki/Contributing
|
||||
|
||||
You will usually want to write tests for your changes. To run the test suite, `cd` into Devise's top-level directory and run `bundle install` and `rake`. For the tests to pass, you will need to have a MongoDB server (version 1.6 or newer) running on your system.
|
||||
|
||||
@@ -86,7 +88,7 @@ The generator will install an initializer which describes ALL Devise's configura
|
||||
|
||||
rails generate devise MODEL
|
||||
|
||||
Replace MODEL by the class name you want to add devise, like User, Admin, etc. This will create a model (if one does not exist) and configure it with default Devise modules. The generator will also create a migration file (if your ORM support them) and configure your routes. Continue reading this file to understand exactly what the generator produces and how to use it.
|
||||
Replace MODEL by the class name used for the applications users, it's frequently 'User' but could also be 'Admin'. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run db:migrate as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file, continue reading this file to understand exactly what the generator produces and how to use it. Finally, if your server was already running, then restart it as Rails doesn't automatically load methods from a new gem.
|
||||
|
||||
Support for Rails 2.3.x can be found by installing Devise 1.0.x from the v1.0 branch.
|
||||
|
||||
@@ -97,7 +99,7 @@ If you are building your first Rails application, we recommend you to *not* use
|
||||
* Michael Hartl's online book: http://railstutorial.org/chapters/modeling-and-viewing-users-two#top
|
||||
* Ryan Bates' Railscast: http://railscasts.com/episodes/250-authentication-from-scratch
|
||||
|
||||
Once you have solidified you understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. :)
|
||||
Once you have solidified your understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. :)
|
||||
|
||||
== Getting started
|
||||
|
||||
@@ -108,7 +110,7 @@ Devise must be set up within the model (or models) you want to use. Devise route
|
||||
We're assuming here you want a User model with some Devise modules, as outlined below:
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
|
||||
end
|
||||
|
||||
After you choose which modules to use, you need to set up your migrations. Luckily, Devise has some helpers to save you from this boring work:
|
||||
@@ -152,7 +154,7 @@ You can access the session for this scope:
|
||||
|
||||
After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect. Example: For a :user resource, it will use user_root_path if it exists, otherwise default root_path will be used. This means that you need to set the root inside your routes:
|
||||
|
||||
root :to => "home"
|
||||
root :to => "home#index"
|
||||
|
||||
You can also overwrite after_sign_in_path_for and after_sign_out_path_for to customize your redirect hooks.
|
||||
|
||||
@@ -174,7 +176,7 @@ Notice that if your devise model is not called "user" but "member", then the hel
|
||||
|
||||
The devise method in your models also accepts some options to configure its modules. For example, you can choose which encryptor to use in database_authenticatable:
|
||||
|
||||
devise :database_authenticatable, :confirmable, :recoverable, :stretches => 20
|
||||
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :stretches => 20
|
||||
|
||||
Besides :stretches, you can define :pepper, :encryptor, :confirm_within, :remember_for, :timeout_in, :unlock_in and other values. For details, see the initializer file that was created when you invoked the "devise:install" generator described above.
|
||||
|
||||
@@ -212,14 +214,6 @@ Since Devise is an engine, all its views are packaged inside the gem. These view
|
||||
|
||||
rails generate devise:views
|
||||
|
||||
Devise currently supports generating views for the following template engines (use the `-e` flag for the devise:views generator):
|
||||
|
||||
* Erb
|
||||
* Haml (http://github.com/nex3/haml)
|
||||
* Slim (http://github.com/stonean/slim)
|
||||
|
||||
Note: If you are generating Haml or Slim templates, you will need to have a few dependencies such as `ruby_parser` (for Haml), `hpricot` (for both Haml and Slim) and `haml2slim` (for Slim) installed.
|
||||
|
||||
If you have more than one role in your application (such as "User" and "Admin"), you will notice that Devise uses the same views for all roles. Fortunately, Devise offers an easy way to customize views. All you need to do is set "config.scoped_views = true" inside "config/initializers/devise.rb".
|
||||
|
||||
After doing so, you will be able to have views based on the role like "users/sessions/new" and "admins/sessions/new". If no view is found within the scope, Devise will use the default view at "devise/sessions/new". You can also use the generator to generate scoped views:
|
||||
@@ -267,7 +261,7 @@ Feel free to choose the one you prefer!
|
||||
|
||||
=== I18n
|
||||
|
||||
Devise uses flash messages with I18n with the flash keys :success and :failure. To customize your app, you can set up your locale file:
|
||||
Devise uses flash messages with I18n with the flash keys :notice and :alert. To customize your app, you can set up your locale file:
|
||||
|
||||
en:
|
||||
devise:
|
||||
@@ -297,7 +291,7 @@ The Devise mailer uses a similar pattern to create subject messages:
|
||||
|
||||
Take a look at our locale file to check all available messages. You may also be interested in one of the many translations that are available on our wiki:
|
||||
|
||||
http://github.com/plataformatec/devise/wiki/I18n
|
||||
https://github.com/plataformatec/devise/wiki/I18n
|
||||
|
||||
=== Test helpers
|
||||
|
||||
@@ -321,14 +315,13 @@ If you're using RSpec and want the helpers automatically included within all +de
|
||||
config.include Devise::TestHelpers, :type => :controller
|
||||
end
|
||||
|
||||
Do not use such helpers for integration tests such as Cucumber or Webrat. Instead, fill in the form or explicitly set the user in session. For more tips, check the wiki (http://wiki.github.com/plataformatec/devise).
|
||||
Do not use such helpers for integration tests such as Cucumber or Webrat. Instead, fill in the form or explicitly set the user in session. For more tips, check the wiki (https://wiki.github.com/plataformatec/devise).
|
||||
|
||||
=== OAuth2
|
||||
=== Omniauth
|
||||
|
||||
Devise comes with OAuth support out of the box if you're using Devise from the git repository (for now). You can read more about OAuth2 support in the wiki:
|
||||
Devise comes with Omniauth support out of the box to authenticate from other providers. You can read more about Omniauth support in the wiki:
|
||||
|
||||
* http://github.com/plataformatec/devise/wiki/OAuth2:-Overview
|
||||
* http://github.com/plataformatec/devise/wiki/OAuth2:-Testing
|
||||
* https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
|
||||
|
||||
=== Other ORMs
|
||||
|
||||
@@ -338,25 +331,36 @@ Devise supports ActiveRecord (default) and Mongoid. To choose other ORM, you jus
|
||||
|
||||
Devise implements encryption strategies for Clearance, Authlogic and Restful-Authentication. To make use of these strategies, you need set the desired encryptor in the encryptor initializer config option and add :encryptable to your model. You might also need to rename your encrypted password and salt columns to match Devise's fields (encrypted_password and password_salt).
|
||||
|
||||
== Troubleshooting
|
||||
|
||||
=== Heroku
|
||||
|
||||
Using devise on Heroku with Ruby on Rails 3.1 requires setting:
|
||||
|
||||
config.assets.initialize_on_precompile = false
|
||||
|
||||
Read more about the potential issues at http://guides.rubyonrails.org/asset_pipeline.html
|
||||
|
||||
== Additional information
|
||||
|
||||
=== Warden
|
||||
|
||||
Devise is based on Warden, which is a general Rack authentication framework created by Daniel Neighman. We encourage you to read more about Warden here:
|
||||
|
||||
http://github.com/hassox/warden
|
||||
https://github.com/hassox/warden
|
||||
|
||||
=== Contributors
|
||||
|
||||
We have a long list of valued contributors. Check them all at:
|
||||
|
||||
http://github.com/plataformatec/devise/contributors
|
||||
https://github.com/plataformatec/devise/contributors
|
||||
|
||||
=== Maintainers
|
||||
|
||||
* José Valim (http://github.com/josevalim)
|
||||
* Carlos Antônio da Silva (http://github.com/carlosantoniodasilva)
|
||||
* José Valim (https://github.com/josevalim)
|
||||
* Carlos Antônio da Silva (https://github.com/carlosantoniodasilva)
|
||||
* Rodrigo Flores (https://github.com/rodrigoflores)
|
||||
|
||||
== License
|
||||
|
||||
MIT License. Copyright 2010 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
MIT License. Copyright 2011 Plataforma Tecnologia. http://blog.plataformatec.com.br
|
||||
|
||||
4
Rakefile
4
Rakefile
@@ -1,10 +1,10 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rdoc/task'
|
||||
|
||||
desc 'Default: run tests for all ORMs.'
|
||||
task :default => :pre_commit
|
||||
task :default => :test
|
||||
|
||||
desc 'Run Devise tests for all ORMs.'
|
||||
task :pre_commit do
|
||||
|
||||
4
TODO
4
TODO
@@ -1,4 +0,0 @@
|
||||
* Move integration tests to Capybara
|
||||
* Better ORM integration
|
||||
* Add support to automatically refresh the access token for OAuth
|
||||
* Add test to generators using the new Rails::Generators::TestCase
|
||||
@@ -11,11 +11,10 @@ class Devise::ConfirmationsController < ApplicationController
|
||||
def create
|
||||
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :send_instructions
|
||||
redirect_to new_session_path(resource_name)
|
||||
if successfully_sent?(resource)
|
||||
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
|
||||
else
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource){ render_with_scope :new }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,10 +23,24 @@ class Devise::ConfirmationsController < ApplicationController
|
||||
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :confirmed
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
set_flash_message(:notice, :confirmed) if is_navigational_format?
|
||||
sign_in(resource_name, resource)
|
||||
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
|
||||
else
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# The path used after resending confirmation instructions.
|
||||
def after_resending_confirmation_instructions_path_for(resource_name)
|
||||
new_session_path(resource_name)
|
||||
end
|
||||
|
||||
# The path used after confirmation.
|
||||
def after_confirmation_path_for(resource_name, resource)
|
||||
after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -12,11 +12,10 @@ class Devise::PasswordsController < ApplicationController
|
||||
def create
|
||||
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :send_instructions
|
||||
redirect_to new_session_path(resource_name)
|
||||
if successfully_sent?(resource)
|
||||
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
|
||||
else
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource){ render_with_scope :new }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,10 +31,20 @@ class Devise::PasswordsController < ApplicationController
|
||||
self.resource = resource_class.reset_password_by_token(params[resource_name])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :updated
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
|
||||
set_flash_message(:notice, flash_message) if is_navigational_format?
|
||||
sign_in(resource_name, resource)
|
||||
respond_with resource, :location => after_sign_in_path_for(resource)
|
||||
else
|
||||
render_with_scope :edit
|
||||
respond_with_navigational(resource){ render_with_scope :edit }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# The path used after sending reset password instructions
|
||||
def after_sending_reset_password_instructions_path_for(resource_name)
|
||||
new_session_path(resource_name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,8 +5,8 @@ class Devise::RegistrationsController < ApplicationController
|
||||
|
||||
# GET /resource/sign_up
|
||||
def new
|
||||
build_resource({})
|
||||
render_with_scope :new
|
||||
resource = build_resource({})
|
||||
respond_with_navigational(resource){ render_with_scope :new }
|
||||
end
|
||||
|
||||
# POST /resource
|
||||
@@ -14,17 +14,18 @@ class Devise::RegistrationsController < ApplicationController
|
||||
build_resource
|
||||
|
||||
if resource.save
|
||||
if resource.active?
|
||||
set_flash_message :notice, :signed_up
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
if resource.active_for_authentication?
|
||||
set_flash_message :notice, :signed_up if is_navigational_format?
|
||||
sign_in(resource_name, resource)
|
||||
respond_with resource, :location => after_sign_up_path_for(resource)
|
||||
else
|
||||
set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s
|
||||
set_flash_message :notice, :inactive_signed_up, :reason => inactive_reason(resource) if is_navigational_format?
|
||||
expire_session_data_after_sign_in!
|
||||
redirect_to after_inactive_sign_up_path_for(resource)
|
||||
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
|
||||
end
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource) { render_with_scope :new }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,22 +35,27 @@ class Devise::RegistrationsController < ApplicationController
|
||||
end
|
||||
|
||||
# PUT /resource
|
||||
# We need to use a copy of the resource because we don't want to change
|
||||
# the current user in place.
|
||||
def update
|
||||
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
|
||||
|
||||
if resource.update_with_password(params[resource_name])
|
||||
set_flash_message :notice, :updated
|
||||
set_flash_message :notice, :updated if is_navigational_format?
|
||||
sign_in resource_name, resource, :bypass => true
|
||||
redirect_to after_update_path_for(resource)
|
||||
respond_with resource, :location => after_update_path_for(resource)
|
||||
else
|
||||
clean_up_passwords(resource)
|
||||
render_with_scope :edit
|
||||
respond_with_navigational(resource){ render_with_scope :edit }
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /resource
|
||||
def destroy
|
||||
resource.destroy
|
||||
sign_out_and_redirect(self.resource)
|
||||
set_flash_message :notice, :destroyed
|
||||
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
|
||||
set_flash_message :notice, :destroyed if is_navigational_format?
|
||||
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
|
||||
end
|
||||
|
||||
# GET /resource/cancel
|
||||
@@ -77,9 +83,10 @@ class Devise::RegistrationsController < ApplicationController
|
||||
after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
# Overwrite redirect_for_sign_in so it takes uses after_sign_up_path_for.
|
||||
def redirect_location(scope, resource) #:nodoc:
|
||||
stored_location_for(scope) || after_sign_up_path_for(resource)
|
||||
# Returns the inactive reason translated.
|
||||
def inactive_reason(resource)
|
||||
reason = resource.inactive_message.to_s
|
||||
I18n.t("devise.registrations.reasons.#{reason}", :default => reason)
|
||||
end
|
||||
|
||||
# The path used after sign up for inactive accounts. You need to overwrite
|
||||
@@ -91,20 +98,12 @@ class Devise::RegistrationsController < ApplicationController
|
||||
# The default url to be used after updating a resource. You need to overwrite
|
||||
# this method in your own RegistrationsController.
|
||||
def after_update_path_for(resource)
|
||||
if defined?(super)
|
||||
ActiveSupport::Deprecation.warn "Defining after_update_path_for in ApplicationController " <<
|
||||
"is deprecated. Please add a RegistrationsController to your application and define it there."
|
||||
super
|
||||
else
|
||||
after_sign_in_path_for(resource)
|
||||
end
|
||||
signed_in_root_path(resource)
|
||||
end
|
||||
|
||||
# Authenticates the current scope and gets a copy of the current resource.
|
||||
# We need to use a copy because we don't want actions like update changing
|
||||
# the current user in place.
|
||||
# Authenticates the current scope and gets the current resource from the session.
|
||||
def authenticate_scope!
|
||||
send(:"authenticate_#{resource_name}!", true)
|
||||
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
|
||||
send(:"authenticate_#{resource_name}!", :force => true)
|
||||
self.resource = send(:"current_#{resource_name}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
class Devise::SessionsController < ApplicationController
|
||||
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
|
||||
prepend_before_filter :allow_params_authentication!, :only => :create
|
||||
include Devise::Controllers::InternalHelpers
|
||||
|
||||
# GET /resource/sign_in
|
||||
def new
|
||||
clean_up_passwords(build_resource)
|
||||
render_with_scope :new
|
||||
resource = build_resource
|
||||
clean_up_passwords(resource)
|
||||
respond_with_navigational(resource, stub_options(resource)){ render_with_scope :new }
|
||||
end
|
||||
|
||||
# POST /resource/sign_in
|
||||
@@ -13,13 +15,35 @@ class Devise::SessionsController < ApplicationController
|
||||
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
|
||||
set_flash_message(:notice, :signed_in) if is_navigational_format?
|
||||
sign_in(resource_name, resource)
|
||||
respond_with resource, :location => redirect_location(resource_name, resource)
|
||||
respond_with resource, :location => after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
# GET /resource/sign_out
|
||||
# DELETE /resource/sign_out
|
||||
def destroy
|
||||
signed_in = signed_in?(resource_name)
|
||||
sign_out_and_redirect(resource_name)
|
||||
redirect_path = after_sign_out_path_for(resource_name)
|
||||
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
|
||||
set_flash_message :notice, :signed_out if signed_in
|
||||
|
||||
# We actually need to hardcode this as Rails default responder doesn't
|
||||
# support returning empty response on GET request
|
||||
respond_to do |format|
|
||||
format.any(*navigational_formats) { redirect_to redirect_path }
|
||||
format.all do
|
||||
method = "to_#{request_format}"
|
||||
text = {}.respond_to?(method) ? {}.send(method) : ""
|
||||
render :text => text, :status => :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def stub_options(resource)
|
||||
methods = resource_class.authentication_keys.dup
|
||||
methods = methods.keys if methods.is_a?(Hash)
|
||||
methods << :password if resource.respond_to?(:password)
|
||||
{ :methods => methods, :only => [:password] }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@ class Devise::UnlocksController < ApplicationController
|
||||
def create
|
||||
self.resource = resource_class.send_unlock_instructions(params[resource_name])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :send_instructions
|
||||
redirect_to new_session_path(resource_name)
|
||||
if successfully_sent?(resource)
|
||||
respond_with({}, :location => new_session_path(resource_name))
|
||||
else
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource){ render_with_scope :new }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,10 +24,11 @@ class Devise::UnlocksController < ApplicationController
|
||||
self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
|
||||
|
||||
if resource.errors.empty?
|
||||
set_flash_message :notice, :unlocked
|
||||
sign_in_and_redirect(resource_name, resource)
|
||||
set_flash_message :notice, :unlocked if is_navigational_format?
|
||||
sign_in(resource_name, resource)
|
||||
respond_with_navigational(resource){ redirect_to after_sign_in_path_for(resource) }
|
||||
else
|
||||
render_with_scope :new
|
||||
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ module DeviseHelper
|
||||
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
|
||||
sentence = I18n.t("errors.messages.not_saved",
|
||||
:count => resource.errors.count,
|
||||
:resource => resource_name)
|
||||
:resource => resource.class.model_name.human.downcase)
|
||||
|
||||
html = <<-HTML
|
||||
<div id="error_explanation">
|
||||
|
||||
@@ -1,88 +1,15 @@
|
||||
class Devise::Mailer < ::ActionMailer::Base
|
||||
include Devise::Controllers::ScopedViews
|
||||
attr_reader :scope_name, :resource
|
||||
include Devise::Mailers::Helpers
|
||||
|
||||
def confirmation_instructions(record)
|
||||
setup_mail(record, :confirmation_instructions)
|
||||
devise_mail(record, :confirmation_instructions)
|
||||
end
|
||||
|
||||
def reset_password_instructions(record)
|
||||
setup_mail(record, :reset_password_instructions)
|
||||
devise_mail(record, :reset_password_instructions)
|
||||
end
|
||||
|
||||
def unlock_instructions(record)
|
||||
setup_mail(record, :unlock_instructions)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Configure default email options
|
||||
def setup_mail(record, action)
|
||||
initialize_from_record(record)
|
||||
mail headers_for(action)
|
||||
end
|
||||
|
||||
def initialize_from_record(record)
|
||||
@scope_name = Devise::Mapping.find_scope!(record)
|
||||
@resource = instance_variable_set("@#{devise_mapping.name}", record)
|
||||
end
|
||||
|
||||
def devise_mapping
|
||||
@devise_mapping ||= Devise.mappings[scope_name]
|
||||
end
|
||||
|
||||
def headers_for(action)
|
||||
headers = {
|
||||
:subject => translate(devise_mapping, action),
|
||||
:from => mailer_sender(devise_mapping),
|
||||
:to => resource.email,
|
||||
:template_path => template_paths
|
||||
}
|
||||
|
||||
if resource.respond_to?(:headers_for)
|
||||
headers.merge!(resource.headers_for(action))
|
||||
end
|
||||
|
||||
unless headers.key?(:reply_to)
|
||||
headers[:reply_to] = headers[:from]
|
||||
end
|
||||
|
||||
headers
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
def template_paths
|
||||
template_path = [self.class.mailer_name]
|
||||
template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
|
||||
template_path
|
||||
end
|
||||
|
||||
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
|
||||
# based on the current mapping:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# user_subject: '...'
|
||||
#
|
||||
# If one does not exist, it fallbacks to ActionMailer default:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# subject: '...'
|
||||
#
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
|
||||
:default => [:subject, key.to_s.humanize])
|
||||
devise_mail(record, :unlock_instructions)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.submit "Resend confirmation instructions" %></p>
|
||||
<div><%= f.submit "Resend confirmation instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -4,13 +4,13 @@
|
||||
<%= devise_error_messages! %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<p><%= f.label :password, "New password" %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
<div><%= f.label :password, "New password" %><br />
|
||||
<%= f.password_field :password %></div>
|
||||
|
||||
<p><%= f.label :password_confirmation, "Confirm new password" %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
<div><%= f.label :password_confirmation, "Confirm new password" %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<p><%= f.submit "Change my password" %></p>
|
||||
<div><%= f.submit "Change my password" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -3,10 +3,10 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.submit "Send me reset password instructions" %></p>
|
||||
<div><%= f.submit "Send me reset password instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -3,19 +3,19 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password %></p>
|
||||
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password %></div>
|
||||
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
<div><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password %></p>
|
||||
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password %></div>
|
||||
|
||||
<p><%= f.submit "Update" %></p>
|
||||
<div><%= f.submit "Update" %></div>
|
||||
<% end %>
|
||||
|
||||
<h3>Cancel my account</h3>
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
<div><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></div>
|
||||
|
||||
<p><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></p>
|
||||
<div><%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation %></div>
|
||||
|
||||
<p><%= f.submit "Sign up" %></p>
|
||||
<div><%= f.submit "Sign up" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<h2>Sign in</h2>
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></p>
|
||||
<div><%= f.label :password %><br />
|
||||
<%= f.password_field :password %></div>
|
||||
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p>
|
||||
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
|
||||
<% end -%>
|
||||
|
||||
<p><%= f.submit "Sign in" %></p>
|
||||
<div><%= f.submit "Sign in" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -3,10 +3,10 @@
|
||||
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
|
||||
<p><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></p>
|
||||
<div><%= f.label :email %><br />
|
||||
<%= f.email_field :email %></div>
|
||||
|
||||
<p><%= f.submit "Resend unlock instructions" %></p>
|
||||
<div><%= f.submit "Resend unlock instructions" %></div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -1,8 +1,9 @@
|
||||
# Additional translations at http://github.com/plataformatec/devise/wiki/I18n
|
||||
# Additional translations at https://github.com/plataformatec/devise/wiki/I18n
|
||||
|
||||
en:
|
||||
errors:
|
||||
messages:
|
||||
expired: "has expired, please request a new one"
|
||||
not_found: "not found"
|
||||
already_confirmed: "was already confirmed, please try signing in"
|
||||
not_locked: "was not locked"
|
||||
@@ -12,6 +13,7 @@ en:
|
||||
|
||||
devise:
|
||||
failure:
|
||||
already_authenticated: 'You are already signed in.'
|
||||
unauthenticated: 'You need to sign in or sign up before continuing.'
|
||||
unconfirmed: 'You have to confirm your account before continuing.'
|
||||
locked: 'Your account is locked.'
|
||||
@@ -25,17 +27,25 @@ en:
|
||||
passwords:
|
||||
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
|
||||
updated: 'Your password was changed successfully. You are now signed in.'
|
||||
updated_not_active: 'Your password was changed successfully.'
|
||||
send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail"
|
||||
confirmations:
|
||||
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
|
||||
send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.'
|
||||
confirmed: 'Your account was successfully confirmed. You are now signed in.'
|
||||
registrations:
|
||||
signed_up: 'Welcome! You have signed up successfully.'
|
||||
inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
|
||||
updated: 'You updated your account successfully.'
|
||||
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
|
||||
reasons:
|
||||
inactive: 'inactive'
|
||||
unconfirmed: 'unconfirmed'
|
||||
locked: 'locked'
|
||||
unlocks:
|
||||
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
|
||||
unlocked: 'Your account was successfully unlocked. You are now signed in.'
|
||||
send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.'
|
||||
omniauth_callbacks:
|
||||
success: 'Successfully authorized from %{kind} account.'
|
||||
failure: 'Could not authorize you from %{kind} because "%{reason}".'
|
||||
|
||||
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
s.require_paths = ["lib"]
|
||||
|
||||
s.add_dependency("warden", "~> 1.0.3")
|
||||
s.add_dependency("warden", "~> 1.1")
|
||||
s.add_dependency("orm_adapter", "~> 0.0.3")
|
||||
s.add_dependency("bcrypt-ruby", "~> 2.1.2")
|
||||
s.add_dependency("bcrypt-ruby", "~> 3.0")
|
||||
end
|
||||
@@ -3,12 +3,15 @@ require 'active_support/core_ext/numeric/time'
|
||||
require 'active_support/dependencies'
|
||||
require 'orm_adapter'
|
||||
require 'set'
|
||||
require 'securerandom'
|
||||
|
||||
module Devise
|
||||
autoload :FailureApp, 'devise/failure_app'
|
||||
autoload :OmniAuth, 'devise/omniauth'
|
||||
autoload :Delegator, 'devise/delegator'
|
||||
autoload :FailureApp, 'devise/failure_app'
|
||||
autoload :OmniAuth, 'devise/omniauth'
|
||||
autoload :ParamFilter, 'devise/param_filter'
|
||||
autoload :PathChecker, 'devise/path_checker'
|
||||
autoload :Schema, 'devise/schema'
|
||||
autoload :Schema, 'devise/schema'
|
||||
autoload :TestHelpers, 'devise/test_helpers'
|
||||
|
||||
module Controllers
|
||||
@@ -16,6 +19,7 @@ module Devise
|
||||
autoload :InternalHelpers, 'devise/controllers/internal_helpers'
|
||||
autoload :Rememberable, 'devise/controllers/rememberable'
|
||||
autoload :ScopedViews, 'devise/controllers/scoped_views'
|
||||
autoload :SharedHelpers, 'devise/controllers/shared_helpers'
|
||||
autoload :UrlHelpers, 'devise/controllers/url_helpers'
|
||||
end
|
||||
|
||||
@@ -28,6 +32,10 @@ module Devise
|
||||
autoload :Sha1, 'devise/encryptors/sha1'
|
||||
end
|
||||
|
||||
module Mailers
|
||||
autoload :Helpers, 'devise/mailers/helpers'
|
||||
end
|
||||
|
||||
module Strategies
|
||||
autoload :Base, 'devise/strategies/base'
|
||||
autoload :Authenticatable, 'devise/strategies/authenticatable'
|
||||
@@ -41,6 +49,9 @@ module Devise
|
||||
STRATEGIES = ActiveSupport::OrderedHash.new
|
||||
URL_HELPERS = ActiveSupport::OrderedHash.new
|
||||
|
||||
# Strategies that do not require user input.
|
||||
NO_INPUT = []
|
||||
|
||||
# True values used to check params
|
||||
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
|
||||
|
||||
@@ -70,9 +81,14 @@ module Devise
|
||||
@@request_keys = []
|
||||
|
||||
# Keys that should be case-insensitive.
|
||||
# Empty by default for backwards compatibility.
|
||||
# False by default for backwards compatibility.
|
||||
mattr_accessor :case_insensitive_keys
|
||||
@@case_insensitive_keys = []
|
||||
@@case_insensitive_keys = false
|
||||
|
||||
# Keys that should have whitespace stripped.
|
||||
# False by default for backwards compatibility.
|
||||
mattr_accessor :strip_whitespace_keys
|
||||
@@strip_whitespace_keys = false
|
||||
|
||||
# If http authentication is enabled by default.
|
||||
mattr_accessor :http_authenticatable
|
||||
@@ -90,13 +106,15 @@ module Devise
|
||||
mattr_accessor :http_authentication_realm
|
||||
@@http_authentication_realm = "Application"
|
||||
|
||||
# Email regex used to validate email formats. Adapted from authlogic.
|
||||
# Email regex used to validate email formats. It simply asserts that
|
||||
# an one (and only one) @ exists in the given string. This is mainly
|
||||
# to give user feedback and not to assert the e-mail validity.
|
||||
mattr_accessor :email_regexp
|
||||
@@email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
|
||||
@@email_regexp = /\A[^@]+@([^@\.]+\.)+[^@\.]+\z/
|
||||
|
||||
# Range validation for password length
|
||||
mattr_accessor :password_length
|
||||
@@password_length = 6..20
|
||||
@@password_length = 6..128
|
||||
|
||||
# The time the user will be remembered without asking for credentials again.
|
||||
mattr_accessor :remember_for
|
||||
@@ -171,6 +189,10 @@ module Devise
|
||||
mattr_accessor :reset_password_keys
|
||||
@@reset_password_keys = [ :email ]
|
||||
|
||||
# Time interval you can reset your password with a reset password key
|
||||
mattr_accessor :reset_password_within
|
||||
@@reset_password_within = nil
|
||||
|
||||
# The default scope which is used by warden.
|
||||
mattr_accessor :default_scope
|
||||
@@default_scope = nil
|
||||
@@ -220,20 +242,37 @@ module Devise
|
||||
@@warden_config = nil
|
||||
@@warden_config_block = nil
|
||||
|
||||
# When true, enter in paranoid mode to avoid user enumeration.
|
||||
mattr_accessor :paranoid
|
||||
@@paranoid = false
|
||||
|
||||
# Default way to setup Devise. Run rails generate devise_install to create
|
||||
# a fresh initializer with all configuration values.
|
||||
def self.setup
|
||||
yield self
|
||||
end
|
||||
|
||||
def self.omniauth_providers
|
||||
omniauth_configs.keys
|
||||
class Getter
|
||||
def initialize name
|
||||
@name = name
|
||||
end
|
||||
|
||||
def get
|
||||
ActiveSupport::Dependencies.constantize(@name)
|
||||
end
|
||||
end
|
||||
|
||||
def self.cookie_domain=(value)
|
||||
ActiveSupport::Deprecation.warn "Devise.cookie_domain=(value) is deprecated. "
|
||||
"Please use Devise.cookie_options = { :domain => value } instead."
|
||||
self.cookie_options[:domain] = value
|
||||
def self.ref(arg)
|
||||
if defined?(ActiveSupport::Dependencies::ClassCache)
|
||||
ActiveSupport::Dependencies::reference(arg)
|
||||
Getter.new(arg)
|
||||
else
|
||||
ActiveSupport::Dependencies.ref(arg)
|
||||
end
|
||||
end
|
||||
|
||||
def self.omniauth_providers
|
||||
omniauth_configs.keys
|
||||
end
|
||||
|
||||
# Get the mailer class from the mailer reference object.
|
||||
@@ -243,7 +282,7 @@ module Devise
|
||||
|
||||
# Set the mailer reference object to access the mailer.
|
||||
def self.mailer=(class_name)
|
||||
@@mailer_ref = ActiveSupport::Dependencies.ref(class_name)
|
||||
@@mailer_ref = ref(class_name)
|
||||
end
|
||||
self.mailer = "Devise::Mailer"
|
||||
|
||||
@@ -279,13 +318,17 @@ module Devise
|
||||
options.assert_valid_keys(:strategy, :model, :controller, :route)
|
||||
|
||||
if strategy = options[:strategy]
|
||||
STRATEGIES[module_name] = (strategy == true ? module_name : strategy)
|
||||
strategy = (strategy == true ? module_name : strategy)
|
||||
STRATEGIES[module_name] = strategy
|
||||
end
|
||||
|
||||
if controller = options[:controller]
|
||||
CONTROLLERS[module_name] = (controller == true ? module_name : controller)
|
||||
controller = (controller == true ? module_name : controller)
|
||||
CONTROLLERS[module_name] = controller
|
||||
end
|
||||
|
||||
NO_INPUT << strategy if strategy && controller != :sessions
|
||||
|
||||
if route = options[:route]
|
||||
case route
|
||||
when TrueClass
|
||||
@@ -307,7 +350,8 @@ module Devise
|
||||
|
||||
if options[:model]
|
||||
path = (options[:model] == true ? "devise/models/#{module_name}" : options[:model])
|
||||
Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, path)
|
||||
camelized = ActiveSupport::Inflector.camelize(module_name.to_s)
|
||||
Devise::Models.send(:autoload, camelized.to_sym, path)
|
||||
end
|
||||
|
||||
Devise::Mapping.add_module module_name
|
||||
@@ -334,7 +378,8 @@ module Devise
|
||||
#
|
||||
def self.omniauth(provider, *args)
|
||||
@@helpers << Devise::OmniAuth::UrlHelpers
|
||||
@@omniauth_configs[provider] = Devise::OmniAuth::Config.new(provider, args)
|
||||
config = Devise::OmniAuth::Config.new(provider, args)
|
||||
@@omniauth_configs[config.strategy_name.to_sym] = config
|
||||
end
|
||||
|
||||
# Include helpers in the given scope to AC and AV.
|
||||
@@ -354,11 +399,17 @@ module Devise
|
||||
Rails::VERSION::STRING[0,3] != "3.0"
|
||||
end
|
||||
|
||||
# Regenerates url helpers considering Devise.mapping
|
||||
def self.regenerate_helpers!
|
||||
Devise::Controllers::UrlHelpers.remove_helpers!
|
||||
Devise::Controllers::UrlHelpers.generate_helpers!
|
||||
end
|
||||
|
||||
# A method used internally to setup warden manager from the Rails initialize
|
||||
# block.
|
||||
def self.configure_warden! #:nodoc:
|
||||
@@warden_configured ||= begin
|
||||
warden_config.failure_app = Devise::FailureApp
|
||||
warden_config.failure_app = Devise::Delegator.new
|
||||
warden_config.default_scope = Devise.default_scope
|
||||
warden_config.intercept_401 = false
|
||||
|
||||
@@ -373,7 +424,7 @@ module Devise
|
||||
|
||||
# Generate a friendly string randomically to be used as token.
|
||||
def self.friendly_token
|
||||
ActiveSupport::SecureRandom.base64(15).tr('+/=', 'xyz')
|
||||
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
|
||||
end
|
||||
|
||||
# constant-time comparison algorithm to prevent timing attacks
|
||||
|
||||
@@ -5,7 +5,14 @@ module Devise
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
helper_method :warden, :signed_in?, :devise_controller?, :anybody_signed_in?
|
||||
helper_method :warden, :signed_in?, :devise_controller?
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def log_process_action(payload)
|
||||
payload[:status] ||= 401 unless payload[:exception]
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Define authentication filters and accessor helpers based on mappings.
|
||||
@@ -36,8 +43,9 @@ module Devise
|
||||
mapping = mapping.name
|
||||
|
||||
class_eval <<-METHODS, __FILE__, __LINE__ + 1
|
||||
def authenticate_#{mapping}!(force = false)
|
||||
warden.authenticate!(:scope => :#{mapping}) if !devise_controller? || force
|
||||
def authenticate_#{mapping}!(opts={})
|
||||
opts[:scope] = :#{mapping}
|
||||
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
|
||||
end
|
||||
|
||||
def #{mapping}_signed_in?
|
||||
@@ -72,20 +80,19 @@ module Devise
|
||||
false
|
||||
end
|
||||
|
||||
# Tell warden that params authentication is allowed for that specific page.
|
||||
def allow_params_authentication!
|
||||
request.env["devise.allow_params_authentication"] = true
|
||||
end
|
||||
|
||||
# Return true if the given scope is signed in session. If no scope given, return
|
||||
# true if any scope is signed in. Does not run authentication hooks.
|
||||
def signed_in?(scope=nil)
|
||||
[ scope || Devise.mappings.keys ].flatten.any? do |scope|
|
||||
[ scope || Devise.mappings.keys ].flatten.any? do |scope|
|
||||
warden.authenticate?(:scope => scope)
|
||||
end
|
||||
end
|
||||
|
||||
def anybody_signed_in?
|
||||
ActiveSupport::Deprecation.warn "Devise#anybody_signed_in? is deprecated. "
|
||||
"Please use Devise#signed_in?(nil) instead."
|
||||
signed_in?
|
||||
end
|
||||
|
||||
# Sign in a user that already was authenticated. This helper is useful for logging
|
||||
# users in after sign up.
|
||||
#
|
||||
@@ -100,7 +107,7 @@ module Devise
|
||||
# sign_in @user # sign_in(resource)
|
||||
# sign_in @user, :event => :authentication # sign_in(resource, options)
|
||||
# sign_in @user, :bypass => true # sign_in(resource, options)
|
||||
#
|
||||
#
|
||||
def sign_in(resource_or_scope, *args)
|
||||
options = args.extract_options!
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
@@ -112,6 +119,7 @@ module Devise
|
||||
warden.session_serializer.store(resource, scope)
|
||||
elsif warden.user(scope) == resource && !options.delete(:force)
|
||||
# Do nothing. User already signed in and we are not forcing it.
|
||||
true
|
||||
else
|
||||
warden.set_user(resource, options.merge!(:scope => scope))
|
||||
end
|
||||
@@ -131,6 +139,7 @@ module Devise
|
||||
warden.user(scope) # Without loading user here, before_logout hook is not called
|
||||
warden.raw_session.inspect # Without this inspect here. The session does not clear.
|
||||
warden.logout(scope)
|
||||
instance_variable_set(:"@current_#{scope}", nil)
|
||||
end
|
||||
|
||||
# Sign out all active users or scopes. This helper is useful for signing out all roles
|
||||
@@ -139,6 +148,7 @@ module Devise
|
||||
Devise.mappings.keys.each { |s| warden.user(s) }
|
||||
warden.raw_session.inspect
|
||||
warden.logout
|
||||
expire_devise_cached_variables!
|
||||
end
|
||||
|
||||
# Returns and delete the url stored in the session for the given scope. Useful
|
||||
@@ -153,12 +163,21 @@ module Devise
|
||||
session.delete("#{scope}_return_to")
|
||||
end
|
||||
|
||||
# The scope root url to be used when he's signed in. By default, it first
|
||||
# tries to find a resource_root_path, otherwise it uses the root_path.
|
||||
def signed_in_root_path(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
home_path = "#{scope}_root_path"
|
||||
respond_to?(home_path, true) ? send(home_path) : root_path
|
||||
end
|
||||
|
||||
# The default url to be used after signing in. This is used by all Devise
|
||||
# controllers and you can overwrite it in your ApplicationController to
|
||||
# provide a custom hook for a custom resource.
|
||||
#
|
||||
# By default, it first tries to find a resource_root_path, otherwise it
|
||||
# uses the root path. For a user scope, you can define the default url in
|
||||
# By default, it first tries to find a valid resource_return_to key in the
|
||||
# session, then it fallbacks to resource_root_path, otherwise it uses the
|
||||
# root path. For a user scope, you can define the default url in
|
||||
# the following way:
|
||||
#
|
||||
# map.user_root '/users', :controller => 'users' # creates user_root_path
|
||||
@@ -167,22 +186,20 @@ module Devise
|
||||
# user.root :controller => 'users' # creates user_root_path
|
||||
# end
|
||||
#
|
||||
#
|
||||
# If the resource root path is not defined, root_path is used. However,
|
||||
# if this default is not enough, you can customize it, for example:
|
||||
#
|
||||
# def after_sign_in_path_for(resource)
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
# publisher_url
|
||||
# else
|
||||
# super
|
||||
# end
|
||||
# stored_location_for(resource) ||
|
||||
# if resource.is_a?(User) && resource.can_publish?
|
||||
# publisher_url
|
||||
# else
|
||||
# signed_in_root_path(resource)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def after_sign_in_path_for(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
home_path = "#{scope}_root_path"
|
||||
respond_to?(home_path, true) ? send(home_path) : root_path
|
||||
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
|
||||
end
|
||||
|
||||
# Method used by sessions controller to sign out a user. You can overwrite
|
||||
@@ -190,7 +207,7 @@ module Devise
|
||||
# scope. Notice that differently from +after_sign_in_path_for+ this method
|
||||
# receives a symbol with the scope, and not the resource.
|
||||
#
|
||||
# By default is the root_path.
|
||||
# By default it is the root_path.
|
||||
def after_sign_out_path_for(resource_or_scope)
|
||||
root_path
|
||||
end
|
||||
@@ -203,32 +220,41 @@ module Devise
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
resource = args.last || resource_or_scope
|
||||
sign_in(scope, resource, options)
|
||||
redirect_to redirect_location(scope, resource)
|
||||
redirect_to after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
def redirect_location(scope, resource) #:nodoc:
|
||||
stored_location_for(scope) || after_sign_in_path_for(resource)
|
||||
ActiveSupport::Deprecation.warn "redirect_location in Devise is deprecated. Please use after_sign_in_path_for instead.", caller
|
||||
after_sign_in_path_for(resource)
|
||||
end
|
||||
|
||||
def expire_session_data_after_sign_in!
|
||||
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
|
||||
end
|
||||
|
||||
# Sign out a user and tries to redirect to the url specified by
|
||||
# after_sign_out_path_for.
|
||||
def sign_out_and_redirect(resource_or_scope)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
redirect_path = after_sign_out_path_for(scope)
|
||||
Devise.sign_out_all_scopes ? sign_out : sign_out(scope)
|
||||
redirect_to after_sign_out_path_for(scope)
|
||||
redirect_to redirect_path
|
||||
end
|
||||
|
||||
# A hook called to expire session data after sign up/in. All keys
|
||||
# stored under "devise." namespace are removed after sign in.
|
||||
def expire_session_data_after_sign_in!
|
||||
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
|
||||
end
|
||||
|
||||
# Overwrite Rails' handle unverified request to sign out all scopes.
|
||||
# Overwrite Rails' handle unverified request to sign out all scopes,
|
||||
# clear run strategies and remove cached variables.
|
||||
def handle_unverified_request
|
||||
sign_out_all_scopes
|
||||
warden.clear_strategies_cache!
|
||||
expire_devise_cached_variables!
|
||||
super # call the default behaviour which resets the session
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expire_devise_cached_variables!
|
||||
Devise.mappings.each { |_,m| instance_variable_set("@current_#{m.name}", nil) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ module Devise
|
||||
module InternalHelpers #:nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Controllers::ScopedViews
|
||||
include Devise::Controllers::SharedHelpers
|
||||
|
||||
included do
|
||||
helper DeviseHelper
|
||||
@@ -54,12 +55,19 @@ module Devise
|
||||
|
||||
# Checks whether it's a devise mapped resource or not.
|
||||
def is_devise_resource? #:nodoc:
|
||||
unknown_action!("Could not find devise mapping for path #{request.fullpath.inspect}") unless devise_mapping
|
||||
unknown_action! <<-MESSAGE unless devise_mapping
|
||||
Could not find devise mapping for path #{request.fullpath.inspect}.
|
||||
Maybe you forgot to wrap your route inside the scope block? For example:
|
||||
|
||||
devise_scope :user do
|
||||
match "/some/route" => "some_devise_controller"
|
||||
end
|
||||
MESSAGE
|
||||
end
|
||||
|
||||
# Check whether it's navigational format, such as :html or :iphone, or not.
|
||||
def is_navigational_format?
|
||||
Devise.navigational_formats.include?(request.format.to_sym)
|
||||
# Returns real navigational formats which are supported by Rails
|
||||
def navigational_formats
|
||||
@navigational_formats ||= Devise.navigational_formats.select{ |format| Mime::EXTENSION_LOOKUP[format.to_s] }
|
||||
end
|
||||
|
||||
def unknown_action!(msg)
|
||||
@@ -83,12 +91,33 @@ module Devise
|
||||
# Example:
|
||||
# before_filter :require_no_authentication, :only => :new
|
||||
def require_no_authentication
|
||||
if warden.authenticated?(resource_name)
|
||||
return unless is_navigational_format?
|
||||
no_input = devise_mapping.no_input_strategies
|
||||
args = no_input.dup.push :scope => resource_name
|
||||
if no_input.present? && warden.authenticate?(*args)
|
||||
resource = warden.user(resource_name)
|
||||
flash[:alert] = I18n.t("devise.failure.already_authenticated")
|
||||
redirect_to after_sign_in_path_for(resource)
|
||||
end
|
||||
end
|
||||
|
||||
# Helper for use after calling send_*_instructions methods on a resource.
|
||||
# If we are in paranoid mode, we always act as if the resource was valid
|
||||
# and instructions were sent.
|
||||
def successfully_sent?(resource)
|
||||
notice = if Devise.paranoid
|
||||
resource.errors.clear
|
||||
:send_paranoid_instructions
|
||||
elsif resource.errors.empty?
|
||||
:send_instructions
|
||||
end
|
||||
|
||||
if notice
|
||||
set_flash_message :notice, notice if is_navigational_format?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the flash message with :key, using I18n. By default you are able
|
||||
# to setup your messages using specific resource scope, and if no one is
|
||||
# found we look to default scope.
|
||||
@@ -114,6 +143,12 @@ module Devise
|
||||
def clean_up_passwords(object) #:nodoc:
|
||||
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
|
||||
end
|
||||
|
||||
def respond_with_navigational(*args, &block)
|
||||
respond_with(*args) do |format|
|
||||
format.any(*navigational_formats, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,7 +29,7 @@ module Devise
|
||||
# Forgets the given resource by deleting a cookie
|
||||
def forget_me(resource)
|
||||
scope = Devise::Mapping.find_scope!(resource)
|
||||
resource.forget_me! unless resource.frozen?
|
||||
resource.forget_me!
|
||||
cookies.delete("remember_#{scope}_token", forget_cookie_values(resource))
|
||||
end
|
||||
|
||||
|
||||
26
lib/devise/controllers/shared_helpers.rb
Normal file
26
lib/devise/controllers/shared_helpers.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
module Devise
|
||||
module Controllers
|
||||
# Helpers used in both FailureApp and Devise controllers.
|
||||
module SharedHelpers
|
||||
MIME_REFERENCES = Mime::HTML.respond_to?(:ref)
|
||||
|
||||
protected
|
||||
|
||||
# Helper used by FailureApp and Devise controllers to retrieve proper formats.
|
||||
def request_format
|
||||
@request_format ||= if request.format.respond_to?(:ref)
|
||||
request.format.ref
|
||||
elsif MIME_REFERENCES
|
||||
request.format
|
||||
elsif request.format # Rails < 3.0.4
|
||||
request.format.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
# Check whether it's navigational format, such as :html or :iphone, or not.
|
||||
def is_navigational_format?
|
||||
Devise.navigational_formats.include?(request_format)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -18,22 +18,36 @@ module Devise
|
||||
#
|
||||
# Those helpers are added to your ApplicationController.
|
||||
module UrlHelpers
|
||||
def self.remove_helpers!
|
||||
self.instance_methods.map(&:to_s).grep(/_(url|path)$/).each do |method|
|
||||
remove_method method
|
||||
end
|
||||
end
|
||||
|
||||
Devise::URL_HELPERS.each do |module_name, actions|
|
||||
[:path, :url].each do |path_or_url|
|
||||
actions.each do |action|
|
||||
action = action ? "#{action}_" : ""
|
||||
def self.generate_helpers!(routes=nil)
|
||||
routes ||= begin
|
||||
mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
|
||||
Devise::URL_HELPERS.slice(*mappings)
|
||||
end
|
||||
|
||||
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
|
||||
def #{action}#{module_name}_#{path_or_url}(resource_or_scope, *args)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
send("#{action}\#{scope}_#{module_name}_#{path_or_url}", *args)
|
||||
end
|
||||
URL_HELPERS
|
||||
routes.each do |module_name, actions|
|
||||
[:path, :url].each do |path_or_url|
|
||||
actions.each do |action|
|
||||
action = action ? "#{action}_" : ""
|
||||
method = "#{action}#{module_name}_#{path_or_url}"
|
||||
|
||||
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
|
||||
def #{method}(resource_or_scope, *args)
|
||||
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
||||
send("#{action}\#{scope}_#{module_name}_#{path_or_url}", *args)
|
||||
end
|
||||
URL_HELPERS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
generate_helpers!(Devise::URL_HELPERS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
16
lib/devise/delegator.rb
Normal file
16
lib/devise/delegator.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module Devise
|
||||
# Checks the scope in the given environment and returns the associated failure app.
|
||||
class Delegator
|
||||
def call(env)
|
||||
failure_app(env).call(env)
|
||||
end
|
||||
|
||||
def failure_app(env)
|
||||
app = env["warden.options"] &&
|
||||
(scope = env["warden.options"][:scope]) &&
|
||||
Devise.mappings[scope].failure_app
|
||||
|
||||
app || Devise::FailureApp
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,7 +7,7 @@ module Devise
|
||||
# Warning: it uses Devise's stretches configuration to port Authlogic's one. Should be set to 20 in the initializer to simulate
|
||||
# the default behavior.
|
||||
class AuthlogicSha512 < Base
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# Generates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = [password, salt].flatten.join('')
|
||||
|
||||
@@ -7,7 +7,7 @@ module Devise
|
||||
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
||||
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
|
||||
class ClearanceSha1 < Base
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# Generates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
||||
|
||||
@@ -9,7 +9,7 @@ module Devise
|
||||
# the initializer to simulate the default behavior.
|
||||
class RestfulAuthenticationSha1 < Base
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# Generates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
|
||||
@@ -5,7 +5,7 @@ module Devise
|
||||
# = Sha1
|
||||
# Uses the Sha1 hash algorithm to encrypt passwords.
|
||||
class Sha1 < Base
|
||||
# Gererates a default password digest based on stretches, salt, pepper and the
|
||||
# Generates a default password digest based on stretches, salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
|
||||
@@ -5,7 +5,7 @@ module Devise
|
||||
# = Sha512
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512 < Base
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# Generates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
|
||||
@@ -10,11 +10,13 @@ module Devise
|
||||
include ActionController::UrlFor
|
||||
include ActionController::Redirecting
|
||||
include Rails.application.routes.url_helpers
|
||||
include Devise::Controllers::SharedHelpers
|
||||
|
||||
delegate :flash, :to => :request
|
||||
|
||||
def self.call(env)
|
||||
action(:respond).call(env)
|
||||
@respond ||= action(:respond)
|
||||
@respond.call(env)
|
||||
end
|
||||
|
||||
def self.default_url_options(*args)
|
||||
@@ -64,13 +66,21 @@ module Devise
|
||||
end
|
||||
|
||||
def redirect_url
|
||||
if request_format == :html
|
||||
send(:"new_#{scope}_session_path")
|
||||
opts = {}
|
||||
route = :"new_#{scope}_session_path"
|
||||
opts[:format] = request_format unless skip_format?
|
||||
|
||||
if respond_to?(route)
|
||||
send(route, opts)
|
||||
else
|
||||
send(:"new_#{scope}_session_path", :format => request_format)
|
||||
root_path(opts)
|
||||
end
|
||||
end
|
||||
|
||||
def skip_format?
|
||||
%w(html */*).include? request_format.to_s
|
||||
end
|
||||
|
||||
# Choose whether we should respond in a http authentication fashion,
|
||||
# including 401 and optional headers.
|
||||
#
|
||||
@@ -83,7 +93,7 @@ module Devise
|
||||
if request.xhr?
|
||||
Devise.http_authenticatable_on_xhr
|
||||
else
|
||||
!(request_format && Devise.navigational_formats.include?(request_format))
|
||||
!(request_format && is_navigational_format?)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -96,12 +106,20 @@ module Devise
|
||||
def http_auth_body
|
||||
return i18n_message unless request_format
|
||||
method = "to_#{request_format}"
|
||||
{}.respond_to?(method) ? { :error => i18n_message }.send(method) : i18n_message
|
||||
if method == "to_xml"
|
||||
{ :error => i18n_message }.to_xml(:root => "errors")
|
||||
elsif {}.respond_to?(method)
|
||||
{ :error => i18n_message }.send(method)
|
||||
else
|
||||
i18n_message
|
||||
end
|
||||
end
|
||||
|
||||
def recall_app(app)
|
||||
controller, action = app.split("#")
|
||||
"#{controller.camelize}Controller".constantize.action(action)
|
||||
controller_name = ActiveSupport::Inflector.camelize(controller)
|
||||
controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
|
||||
controller_klass.action(action)
|
||||
end
|
||||
|
||||
def warden
|
||||
@@ -127,17 +145,5 @@ module Devise
|
||||
def store_location!
|
||||
session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
|
||||
end
|
||||
|
||||
MIME_REFERENCES = Mime::HTML.respond_to?(:ref)
|
||||
|
||||
def request_format
|
||||
@request_format ||= if request.format.respond_to?(:ref)
|
||||
request.format.ref
|
||||
elsif MIME_REFERENCES
|
||||
request.format
|
||||
else # Rails < 3.0.4
|
||||
request.format.to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Deny user access whenever his account is not active yet. All strategies that inherits from
|
||||
# Devise::Strategies::Authenticatable and uses the validate already check if the user is active?
|
||||
# Devise::Strategies::Authenticatable and uses the validate already check if the user is active_for_authentication?
|
||||
# before actively signing him in. However, we need this as hook to validate the user activity
|
||||
# in each request and in case the user is using other strategies beside Devise ones.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record && record.respond_to?(:active?) && !record.active?
|
||||
if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
|
||||
scope = options[:scope]
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => record.inactive_message
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# remembered again. Notice that we forget the user unless the record is not persisted.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, options|
|
||||
if record.respond_to?(:forget_me!)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Each time a record is set we check whether its session has already timed out
|
||||
# or not, based on last request time. If so, the record is logged out and
|
||||
# redirected to the sign in page. Also, each time the request comes and the
|
||||
# record is set, we set the last request time inside it's scoped session to
|
||||
# record is set, we set the last request time inside its scoped session to
|
||||
# verify timeout in the following request.
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
@@ -17,6 +17,8 @@ Warden::Manager.after_set_user do |record, warden, options|
|
||||
end
|
||||
end
|
||||
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
unless warden.request.env['devise.skip_trackable']
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# and on authentication. Retrieving the user from session (:fetch) does
|
||||
# not trigger it.
|
||||
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
|
||||
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope])
|
||||
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
|
||||
record.update_tracked_fields!(warden.request)
|
||||
end
|
||||
end
|
||||
|
||||
86
lib/devise/mailers/helpers.rb
Normal file
86
lib/devise/mailers/helpers.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
module Devise
|
||||
module Mailers
|
||||
module Helpers
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
include Devise::Controllers::ScopedViews
|
||||
attr_reader :scope_name, :resource
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Configure default email options
|
||||
def devise_mail(record, action)
|
||||
initialize_from_record(record)
|
||||
mail headers_for(action)
|
||||
end
|
||||
|
||||
def initialize_from_record(record)
|
||||
@scope_name = Devise::Mapping.find_scope!(record)
|
||||
@resource = instance_variable_set("@#{devise_mapping.name}", record)
|
||||
end
|
||||
|
||||
def devise_mapping
|
||||
@devise_mapping ||= Devise.mappings[scope_name]
|
||||
end
|
||||
|
||||
def headers_for(action)
|
||||
headers = {
|
||||
:subject => translate(devise_mapping, action),
|
||||
:from => mailer_sender(devise_mapping),
|
||||
:to => resource.email,
|
||||
:template_path => template_paths
|
||||
}
|
||||
|
||||
if resource.respond_to?(:headers_for)
|
||||
headers.merge!(resource.headers_for(action))
|
||||
end
|
||||
|
||||
unless headers.key?(:reply_to)
|
||||
headers[:reply_to] = headers[:from]
|
||||
end
|
||||
|
||||
headers
|
||||
end
|
||||
|
||||
def mailer_sender(mapping)
|
||||
if default_params[:from].present?
|
||||
default_params[:from]
|
||||
elsif Devise.mailer_sender.is_a?(Proc)
|
||||
Devise.mailer_sender.call(mapping.name)
|
||||
else
|
||||
Devise.mailer_sender
|
||||
end
|
||||
end
|
||||
|
||||
def template_paths
|
||||
template_path = [self.class.mailer_name]
|
||||
template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
|
||||
template_path
|
||||
end
|
||||
|
||||
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
|
||||
# based on the current mapping:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# user_subject: '...'
|
||||
#
|
||||
# If one does not exist, it fallbacks to ActionMailer default:
|
||||
#
|
||||
# en:
|
||||
# devise:
|
||||
# mailer:
|
||||
# confirmation_instructions:
|
||||
# subject: '...'
|
||||
#
|
||||
def translate(mapping, key)
|
||||
I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
|
||||
:default => [:subject, key.to_s.humanize])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -22,7 +22,10 @@ module Devise
|
||||
# # is the modules included in the class
|
||||
#
|
||||
class Mapping #:nodoc:
|
||||
attr_reader :singular, :scoped_path, :path, :controllers, :path_names, :class_name, :sign_out_via
|
||||
attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
|
||||
:class_name, :sign_out_via, :format, :used_routes, :used_helpers,
|
||||
:constraints, :defaults, :failure_app
|
||||
|
||||
alias :name :singular
|
||||
|
||||
# Receives an object and find a scope for it. If a scope cannot be found,
|
||||
@@ -50,20 +53,21 @@ module Devise
|
||||
@singular = (options[:singular] || @scoped_path.tr('/', '_').singularize).to_sym
|
||||
|
||||
@class_name = (options[:class_name] || name.to_s.classify).to_s
|
||||
@ref = ActiveSupport::Dependencies.ref(@class_name)
|
||||
@klass = Devise.ref(@class_name)
|
||||
|
||||
@path = (options[:path] || name).to_s
|
||||
@path_prefix = options[:path_prefix]
|
||||
|
||||
mod = options[:module] || "devise"
|
||||
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
||||
@controllers.merge!(options[:controllers] || {})
|
||||
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names.merge!(:registration => "")
|
||||
@path_names.merge!(options[:path_names] || {})
|
||||
|
||||
@sign_out_via = options[:sign_out_via] || Devise.sign_out_via
|
||||
@format = options[:format]
|
||||
|
||||
default_failure_app(options)
|
||||
default_controllers(options)
|
||||
default_path_names(options)
|
||||
default_constraints(options)
|
||||
default_defaults(options)
|
||||
default_used_route(options)
|
||||
default_used_helpers(options)
|
||||
end
|
||||
|
||||
# Return modules for the mapping.
|
||||
@@ -73,13 +77,17 @@ module Devise
|
||||
|
||||
# Gives the class the mapping points to.
|
||||
def to
|
||||
@ref.get
|
||||
@klass.get
|
||||
end
|
||||
|
||||
def strategies
|
||||
@strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
|
||||
end
|
||||
|
||||
def no_input_strategies
|
||||
self.strategies & Devise::NO_INPUT
|
||||
end
|
||||
|
||||
def routes
|
||||
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
|
||||
end
|
||||
@@ -106,5 +114,62 @@ module Devise
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_failure_app(options)
|
||||
@failure_app = options[:failure_app] || Devise::FailureApp
|
||||
if @failure_app.is_a?(String)
|
||||
ref = Devise.ref(@failure_app)
|
||||
@failure_app = lambda { |env| ref.get.call(env) }
|
||||
end
|
||||
end
|
||||
|
||||
def default_controllers(options)
|
||||
mod = options[:module] || "devise"
|
||||
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
||||
@controllers.merge!(options[:controllers]) if options[:controllers]
|
||||
@controllers.each { |k,v| @controllers[k] = v.to_s }
|
||||
end
|
||||
|
||||
def default_path_names(options)
|
||||
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
||||
@path_names[:registration] = ""
|
||||
@path_names.merge!(options[:path_names]) if options[:path_names]
|
||||
end
|
||||
|
||||
def default_constraints(options)
|
||||
@constraints = Hash.new
|
||||
@constraints.merge!(options[:constraints]) if options[:constraints]
|
||||
end
|
||||
|
||||
def default_defaults(options)
|
||||
@defaults = Hash.new
|
||||
@defaults.merge!(options[:defaults]) if options[:defaults]
|
||||
end
|
||||
|
||||
def default_used_route(options)
|
||||
singularizer = lambda { |s| s.to_s.singularize.to_sym }
|
||||
|
||||
if options.has_key?(:only)
|
||||
@used_routes = self.routes & Array(options[:only]).map(&singularizer)
|
||||
elsif options[:skip] == :all
|
||||
@used_routes = []
|
||||
else
|
||||
@used_routes = self.routes - Array(options[:skip]).map(&singularizer)
|
||||
end
|
||||
end
|
||||
|
||||
def default_used_helpers(options)
|
||||
singularizer = lambda { |s| s.to_s.singularize.to_sym }
|
||||
|
||||
if options[:skip_helpers] == true
|
||||
@used_helpers = @used_routes
|
||||
elsif skip = options[:skip_helpers]
|
||||
@used_helpers = self.routes - Array(skip).map(&singularizer)
|
||||
else
|
||||
@used_helpers = self.routes
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,6 +17,9 @@ module Devise
|
||||
# inside the given class.
|
||||
#
|
||||
def self.config(mod, *accessors) #:nodoc:
|
||||
(class << mod; self; end).send :attr_accessor, :available_configs
|
||||
mod.available_configs = accessors
|
||||
|
||||
accessors.each do |accessor|
|
||||
mod.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
||||
def #{accessor}
|
||||
@@ -46,13 +49,33 @@ module Devise
|
||||
#
|
||||
def devise(*modules)
|
||||
include Devise::Models::Authenticatable
|
||||
options = modules.extract_options!
|
||||
self.devise_modules += modules.map(&:to_sym).uniq.sort_by { |s|
|
||||
options = modules.extract_options!.dup
|
||||
|
||||
selected_modules = modules.map(&:to_sym).uniq.sort_by do |s|
|
||||
Devise::ALL.index(s) || -1 # follow Devise::ALL order
|
||||
}
|
||||
end
|
||||
|
||||
devise_modules_hook! do
|
||||
devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
||||
selected_modules.each do |m|
|
||||
mod = Devise::Models.const_get(m.to_s.classify)
|
||||
|
||||
if mod.const_defined?("ClassMethods")
|
||||
class_mod = mod.const_get("ClassMethods")
|
||||
extend class_mod
|
||||
|
||||
if class_mod.respond_to?(:available_configs)
|
||||
available_configs = class_mod.available_configs
|
||||
available_configs.each do |config|
|
||||
next unless options.key?(config)
|
||||
send(:"#{config}=", options.delete(config))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include mod
|
||||
end
|
||||
|
||||
self.devise_modules |= selected_modules
|
||||
options.each { |key, value| send(:"#{key}=", value) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'devise/hooks/activatable'
|
||||
require 'devise/models/serializable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
@@ -24,19 +25,19 @@ module Devise
|
||||
# * +params_authenticatable+: if this model allows authentication through request params. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow params authentication.
|
||||
#
|
||||
# == Active?
|
||||
# == active_for_authentication?
|
||||
#
|
||||
# Before authenticating a user and in each request, Devise checks if your model is active by
|
||||
# calling model.active?. This method is overwriten by other devise modules. For instance,
|
||||
# :confirmable overwrites .active? to only return true if your model was confirmed.
|
||||
# After authenticating a user and in each request, Devise checks if your model is active by
|
||||
# calling model.active_for_authentication?. This method is overwriten by other devise modules. For instance,
|
||||
# :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
|
||||
#
|
||||
# You overwrite this method yourself, but if you do, don't forget to call super:
|
||||
#
|
||||
# def active?
|
||||
# def active_for_authentication?
|
||||
# super && special_condition_is_valid?
|
||||
# end
|
||||
#
|
||||
# Whenever active? returns false, Devise asks the reason why your model is inactive using
|
||||
# Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using
|
||||
# the inactive_message method. You can overwrite it as well:
|
||||
#
|
||||
# def inactive_message
|
||||
@@ -46,6 +47,8 @@ module Devise
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include Devise::Models::Serializable
|
||||
|
||||
included do
|
||||
class_attribute :devise_modules, :instance_writer => false
|
||||
self.devise_modules ||= []
|
||||
@@ -55,17 +58,13 @@ module Devise
|
||||
# find_for_authentication are the methods used in a Warden::Strategy to check
|
||||
# if a model should be signed in or not.
|
||||
#
|
||||
# However, you should not overwrite this method, you should overwrite active? and
|
||||
# inactive_message instead.
|
||||
# However, you should not overwrite this method, you should overwrite active_for_authentication?
|
||||
# and inactive_message instead.
|
||||
def valid_for_authentication?
|
||||
if active?
|
||||
block_given? ? yield : true
|
||||
else
|
||||
inactive_message
|
||||
end
|
||||
block_given? ? yield : true
|
||||
end
|
||||
|
||||
def active?
|
||||
def active_for_authentication?
|
||||
true
|
||||
end
|
||||
|
||||
@@ -76,8 +75,21 @@ module Devise
|
||||
def authenticatable_salt
|
||||
end
|
||||
|
||||
def devise_mailer
|
||||
Devise.mailer
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :authentication_keys, :request_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
|
||||
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
|
||||
|
||||
def serialize_into_session(record)
|
||||
[record.to_key, record.authenticatable_salt]
|
||||
end
|
||||
|
||||
def serialize_from_session(key, salt)
|
||||
record = to_adapter.get(key)
|
||||
record if record && record.authenticatable_salt == salt
|
||||
end
|
||||
|
||||
def params_authenticatable?(strategy)
|
||||
params_authenticatable.is_a?(Array) ?
|
||||
@@ -100,9 +112,11 @@ module Devise
|
||||
# end
|
||||
#
|
||||
def find_for_authentication(conditions)
|
||||
filter_auth_params(conditions)
|
||||
case_insensitive_keys.each { |k| conditions[k].try(:downcase!) }
|
||||
to_adapter.find_first(conditions)
|
||||
find_first_by_auth_conditions(conditions)
|
||||
end
|
||||
|
||||
def find_first_by_auth_conditions(conditions)
|
||||
to_adapter.find_first devise_param_filter.filter(conditions)
|
||||
end
|
||||
|
||||
# Find an initialize a record setting an error if it can't be found.
|
||||
@@ -112,15 +126,13 @@ module Devise
|
||||
|
||||
# Find an initialize a group of attributes based on a list of required attributes.
|
||||
def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
|
||||
case_insensitive_keys.each { |k| attributes[k].try(:downcase!) }
|
||||
|
||||
attributes = attributes.slice(*required_attributes)
|
||||
attributes.delete_if { |key, value| value.blank? }
|
||||
|
||||
if attributes.size == required_attributes.size
|
||||
record = to_adapter.find_first(filter_auth_params(attributes))
|
||||
record = find_first_by_auth_conditions(attributes)
|
||||
end
|
||||
|
||||
|
||||
unless record
|
||||
record = new
|
||||
|
||||
@@ -136,11 +148,8 @@ module Devise
|
||||
|
||||
protected
|
||||
|
||||
# Force keys to be string to avoid injection on mongoid related database.
|
||||
def filter_auth_params(conditions)
|
||||
conditions.each do |k, v|
|
||||
conditions[k] = v.to_s
|
||||
end
|
||||
def devise_param_filter
|
||||
@devise_param_filter ||= Devise::ParamFilter.new(case_insensitive_keys, strip_whitespace_keys)
|
||||
end
|
||||
|
||||
# Generate a token by looping and ensuring does not already exist.
|
||||
|
||||
@@ -29,12 +29,12 @@ module Devise
|
||||
after_create :send_confirmation_instructions, :if => :confirmation_required?
|
||||
end
|
||||
|
||||
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
||||
# Confirm a user by setting its confirmed_at to actual time. If the user
|
||||
# is already confirmed, add en error to email field
|
||||
def confirm!
|
||||
unless_confirmed do
|
||||
self.confirmation_token = nil
|
||||
self.confirmed_at = Time.now
|
||||
self.confirmed_at = Time.now.utc
|
||||
save(:validate => false)
|
||||
end
|
||||
end
|
||||
@@ -47,7 +47,7 @@ module Devise
|
||||
# Send confirmation instructions by email
|
||||
def send_confirmation_instructions
|
||||
generate_confirmation_token! if self.confirmation_token.nil?
|
||||
::Devise.mailer.confirmation_instructions(self).deliver
|
||||
self.devise_mailer.confirmation_instructions(self).deliver
|
||||
end
|
||||
|
||||
# Resend confirmation token. This method does not need to generate a new token.
|
||||
@@ -55,11 +55,11 @@ module Devise
|
||||
unless_confirmed { send_confirmation_instructions }
|
||||
end
|
||||
|
||||
# Overwrites active? from Devise::Models::Activatable for confirmation
|
||||
# Overwrites active_for_authentication? for confirmation
|
||||
# by verifying whether a user is active to sign in or not. If the user
|
||||
# is already confirmed, it should never be blocked. Otherwise we need to
|
||||
# calculate if the confirm time has not expired for this user.
|
||||
def active?
|
||||
def active_for_authentication?
|
||||
super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
|
||||
end
|
||||
|
||||
@@ -71,7 +71,7 @@ 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
|
||||
self.confirmed_at = Time.now.utc
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -84,7 +84,7 @@ module Devise
|
||||
# Checks if the confirmation for the user is within the limit time.
|
||||
# We do this by calculating if the difference between today and the
|
||||
# confirmation sent date does not exceed the confirm in time configured.
|
||||
# Confirm_in is a model configuration, must always be an integer value.
|
||||
# Confirm_within is a model configuration, must always be an integer value.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
@@ -127,8 +127,13 @@ module Devise
|
||||
generate_confirmation_token && save(:validate => false)
|
||||
end
|
||||
|
||||
def after_password_reset
|
||||
super
|
||||
confirm! unless confirmed?
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attempt to find a user by it's email. If a record is found, send new
|
||||
# Attempt to find a user by its email. If a record is found, send new
|
||||
# confirmation instructions to it. If not user is found, returns a new user
|
||||
# with an email not found error.
|
||||
# Options must contain the user email
|
||||
@@ -138,7 +143,7 @@ module Devise
|
||||
confirmable
|
||||
end
|
||||
|
||||
# Find a user by it's confirmation token and try to confirm it.
|
||||
# Find a user by its confirmation token and try to confirm it.
|
||||
# If no user is found, returns a new user with an error.
|
||||
# If the user is already confirmed, create an error for the user
|
||||
# Options must have the confirmation_token
|
||||
|
||||
@@ -10,6 +10,9 @@ module Devise
|
||||
#
|
||||
# DatabaseAuthenticable adds the following options to devise_for:
|
||||
#
|
||||
# * +pepper+: a random string used to provide a more secure hash. Use
|
||||
# `rake secret` to generate new keys.
|
||||
#
|
||||
# * +stretches+: the cost given to bcrypt.
|
||||
#
|
||||
# == Examples
|
||||
@@ -22,7 +25,8 @@ module Devise
|
||||
included do
|
||||
attr_reader :password, :current_password
|
||||
attr_accessor :password_confirmation
|
||||
before_save :downcase_keys
|
||||
before_validation :downcase_keys
|
||||
before_validation :strip_whitespace
|
||||
end
|
||||
|
||||
# Generates password encryption based on the given value.
|
||||
@@ -33,6 +37,7 @@ module Devise
|
||||
|
||||
# Verifies whether an password (ie from sign in) is the user password.
|
||||
def valid_password?(password)
|
||||
return false if encrypted_password.blank?
|
||||
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
|
||||
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
|
||||
Devise.secure_compare(password, self.encrypted_password)
|
||||
@@ -46,7 +51,7 @@ module Devise
|
||||
# Update record attributes when :current_password matches, otherwise returns
|
||||
# error on :current_password. It also automatically rejects :password and
|
||||
# :password_confirmation if they are blank.
|
||||
def update_with_password(params={})
|
||||
def update_with_password(params, *options)
|
||||
current_password = params.delete(:current_password)
|
||||
|
||||
if params[:password].blank?
|
||||
@@ -55,10 +60,11 @@ module Devise
|
||||
end
|
||||
|
||||
result = if valid_password?(current_password)
|
||||
update_attributes(params)
|
||||
update_attributes(params, *options)
|
||||
else
|
||||
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
||||
self.attributes = params
|
||||
self.valid?
|
||||
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
||||
false
|
||||
end
|
||||
|
||||
@@ -66,6 +72,27 @@ module Devise
|
||||
result
|
||||
end
|
||||
|
||||
# Updates record attributes without asking for the current password.
|
||||
# Never allows to change the current password. If you are using this
|
||||
# method, you should probably override this method to protect other
|
||||
# attributes you would not like to be updated without a password.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# def update_without_password(params={})
|
||||
# params.delete(:email)
|
||||
# super(params)
|
||||
# end
|
||||
#
|
||||
def update_without_password(params, *options)
|
||||
params.delete(:password)
|
||||
params.delete(:password_confirmation)
|
||||
|
||||
result = update_attributes(params, *options)
|
||||
clean_up_passwords
|
||||
result
|
||||
end
|
||||
|
||||
def after_database_authentication
|
||||
end
|
||||
|
||||
@@ -78,7 +105,11 @@ module Devise
|
||||
|
||||
# Downcase case-insensitive keys
|
||||
def downcase_keys
|
||||
self.class.case_insensitive_keys.each { |k| self[k].try(:downcase!) }
|
||||
(self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
|
||||
end
|
||||
|
||||
def strip_whitespace
|
||||
(self.class.strip_whitespace_keys || []).each { |k| self[k].try(:strip!) }
|
||||
end
|
||||
|
||||
# Digests the password using bcrypt.
|
||||
|
||||
@@ -3,13 +3,13 @@ module Devise
|
||||
# Handles blocking a user access after a certain number of attempts.
|
||||
# Lockable accepts two different strategies to unlock a user after it's
|
||||
# blocked: email and time. The former will send an email to the user when
|
||||
# the lock happens, containing a link to unlock it's account. The second
|
||||
# the lock happens, containing a link to unlock its account. The second
|
||||
# will unlock the user automatically after some configured time (ie 2.hours).
|
||||
# It's also possible to setup lockable to use both email and time strategies.
|
||||
#
|
||||
# == Options
|
||||
#
|
||||
# Lockable adds the following options to devise_for:
|
||||
# Lockable adds the following options to +devise+:
|
||||
#
|
||||
# * +maximum_attempts+: how many attempts should be accepted before blocking the user.
|
||||
# * +lock_strategy+: lock the user account by :failed_attempts or :none.
|
||||
@@ -22,9 +22,9 @@ module Devise
|
||||
|
||||
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
||||
|
||||
# Lock a user setting it's locked_at to actual time.
|
||||
# Lock a user setting its locked_at to actual time.
|
||||
def lock_access!
|
||||
self.locked_at = Time.now
|
||||
self.locked_at = Time.now.utc
|
||||
|
||||
if unlock_strategy_enabled?(:email)
|
||||
generate_unlock_token
|
||||
@@ -49,7 +49,7 @@ module Devise
|
||||
|
||||
# Send unlock instructions by email
|
||||
def send_unlock_instructions
|
||||
::Devise.mailer.unlock_instructions(self).deliver
|
||||
self.devise_mailer.unlock_instructions(self).deliver
|
||||
end
|
||||
|
||||
# Resend the unlock instructions if the user is locked.
|
||||
@@ -57,9 +57,9 @@ module Devise
|
||||
if_access_locked { send_unlock_instructions }
|
||||
end
|
||||
|
||||
# Overwrites active? from Devise::Models::Activatable for locking purposes
|
||||
# Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes
|
||||
# by verifying whether a user is active to sign in or not based on locked?
|
||||
def active?
|
||||
def active_for_authentication?
|
||||
super && !access_locked?
|
||||
end
|
||||
|
||||
@@ -79,25 +79,21 @@ module Devise
|
||||
# if the user can login or not (wrong password, etc)
|
||||
unlock_access! if lock_expired?
|
||||
|
||||
case (result = super)
|
||||
when Symbol
|
||||
return result
|
||||
when TrueClass
|
||||
if super
|
||||
self.failed_attempts = 0
|
||||
save(:validate => false)
|
||||
when FalseClass
|
||||
# PostgreSQL uses nil as the default value for integer columns set to 0
|
||||
true
|
||||
else
|
||||
self.failed_attempts ||= 0
|
||||
self.failed_attempts += 1
|
||||
if attempts_exceeded?
|
||||
lock_access!
|
||||
lock_access! unless access_locked?
|
||||
return :locked
|
||||
else
|
||||
save(:validate => false)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -132,7 +128,7 @@ module Devise
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attempt to find a user by it's email. If a record is found, send new
|
||||
# Attempt to find a user by its email. If a record is found, send new
|
||||
# unlock instructions to it. If not user is found, returns a new user
|
||||
# with an email not found error.
|
||||
# Options must contain the user email
|
||||
@@ -142,7 +138,7 @@ module Devise
|
||||
lockable
|
||||
end
|
||||
|
||||
# Find a user by it's unlock token and try to unlock it.
|
||||
# Find a user by its unlock token and try to unlock it.
|
||||
# If no user is found, returns a new user with an error.
|
||||
# If the user is not locked, creates an error for the user
|
||||
# Options must have the unlock_token
|
||||
|
||||
@@ -29,21 +29,56 @@ module Devise
|
||||
def reset_password!(new_password, new_password_confirmation)
|
||||
self.password = new_password
|
||||
self.password_confirmation = new_password_confirmation
|
||||
clear_reset_password_token if valid?
|
||||
if valid?
|
||||
clear_reset_password_token
|
||||
after_password_reset
|
||||
end
|
||||
|
||||
save
|
||||
end
|
||||
|
||||
# Resets reset password token and send reset password instructions by email
|
||||
def send_reset_password_instructions
|
||||
generate_reset_password_token!
|
||||
::Devise.mailer.reset_password_instructions(self).deliver
|
||||
generate_reset_password_token! if should_generate_token?
|
||||
self.devise_mailer.reset_password_instructions(self).deliver
|
||||
end
|
||||
|
||||
# Checks if the reset password token sent is within the limit time.
|
||||
# We do this by calculating if the difference between today and the
|
||||
# sending date does not exceed the confirm in time configured.
|
||||
# Returns true if the resource is not responding to reset_password_sent_at at all.
|
||||
# reset_password_within is a model configuration, must always be an integer value.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# # reset_password_within = 1.day and reset_password_sent_at = today
|
||||
# reset_password_period_valid? # returns true
|
||||
#
|
||||
# # reset_password_within = 5.days and reset_password_sent_at = 4.days.ago
|
||||
# reset_password_period_valid? # returns true
|
||||
#
|
||||
# # reset_password_within = 5.days and reset_password_sent_at = 5.days.ago
|
||||
# reset_password_period_valid? # returns false
|
||||
#
|
||||
# # reset_password_within = 0.days
|
||||
# reset_password_period_valid? # will always return false
|
||||
#
|
||||
def reset_password_period_valid?
|
||||
return true unless respond_to?(:reset_password_sent_at)
|
||||
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def should_generate_token?
|
||||
reset_password_token.nil? || !reset_password_period_valid?
|
||||
end
|
||||
|
||||
# Generates a new random token for reset password
|
||||
def generate_reset_password_token
|
||||
self.reset_password_token = self.class.reset_password_token
|
||||
self.reset_password_sent_at = Time.now.utc if respond_to?(:reset_password_sent_at=)
|
||||
self.reset_password_token
|
||||
end
|
||||
|
||||
# Resets the reset password token with and save the record without
|
||||
@@ -55,10 +90,14 @@ module Devise
|
||||
# Removes reset_password token
|
||||
def clear_reset_password_token
|
||||
self.reset_password_token = nil
|
||||
self.reset_password_sent_at = nil if respond_to?(:reset_password_sent_at=)
|
||||
end
|
||||
|
||||
def after_password_reset
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Attempt to find a user by it's email. If a record is found, send new
|
||||
# Attempt to find a user by its email. If a record is found, send new
|
||||
# password instructions to it. If not user is found, returns a new user
|
||||
# with an email not found error.
|
||||
# Attributes must contain the user email
|
||||
@@ -73,18 +112,24 @@ module Devise
|
||||
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
|
||||
# Attempt to find a user by its reset_password_token to reset its
|
||||
# password. If a user is found and token is still valid, reset its password and automatically
|
||||
# try saving the record. If not user is found, returns a new user
|
||||
# containing an error in reset_password_token attribute.
|
||||
# Attributes must contain reset_password_token, password and confirmation
|
||||
def reset_password_by_token(attributes={})
|
||||
recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
|
||||
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) if recoverable.persisted?
|
||||
if recoverable.persisted?
|
||||
if recoverable.reset_password_period_valid?
|
||||
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
|
||||
else
|
||||
recoverable.errors.add(:reset_password_token, :expired)
|
||||
end
|
||||
end
|
||||
recoverable
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :reset_password_keys)
|
||||
Devise::Models.config(self, :reset_password_keys, :reset_password_within)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,12 +54,14 @@ module Devise
|
||||
save(:validate => false)
|
||||
end
|
||||
|
||||
# Removes the remember token only if it exists, and save the record
|
||||
# without validations.
|
||||
# If the record is persisted, remove the remember token (but only if
|
||||
# it exists), and save the record without validations.
|
||||
def forget_me!
|
||||
self.remember_token = nil if respond_to?(:remember_token=)
|
||||
self.remember_created_at = nil
|
||||
save(:validate => false)
|
||||
if persisted?
|
||||
self.remember_token = nil if respond_to?(:remember_token=)
|
||||
self.remember_created_at = nil
|
||||
save(:validate => false)
|
||||
end
|
||||
end
|
||||
|
||||
# Remember token should be expired if expiration time not overpass now.
|
||||
|
||||
43
lib/devise/models/serializable.rb
Normal file
43
lib/devise/models/serializable.rb
Normal file
@@ -0,0 +1,43 @@
|
||||
module Devise
|
||||
module Models
|
||||
# This module redefine to_xml and serializable_hash in models for more
|
||||
# secure defaults. By default, it removes from the serializable model
|
||||
# all attributes that are *not* accessible. You can remove this default
|
||||
# by using :force_except and passing a new list of attributes you want
|
||||
# to exempt. All attributes given to :except will simply add names to
|
||||
# exempt to Devise internal list.
|
||||
module Serializable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# TODO: to_xml does not call serializable_hash. Hopefully someone will fix this in AR.
|
||||
%w(to_xml serializable_hash).each do |method|
|
||||
class_eval <<-RUBY, __FILE__, __LINE__
|
||||
def #{method}(options=nil)
|
||||
options ||= {}
|
||||
if options.key?(:force_except)
|
||||
options[:except] = options.delete(:force_except)
|
||||
super(options)
|
||||
elsif self.class.blacklist_keys?
|
||||
except = Array(options[:except])
|
||||
super(options.merge(:except => except + self.class.blacklist_keys))
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
# Return true if we can retrieve blacklist keys from the record.
|
||||
def blacklist_keys?
|
||||
@has_except_keys ||= respond_to?(:accessible_attributes) && !accessible_attributes.to_a.empty?
|
||||
end
|
||||
|
||||
# Returns keys that should be removed when serializing the record.
|
||||
def blacklist_keys
|
||||
@blacklist_keys ||= to_adapter.column_names.map(&:to_s) - accessible_attributes.to_a.map(&:to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -23,18 +23,21 @@ module Devise
|
||||
# Checks whether the user session has expired based on configured time.
|
||||
def timedout?(last_access)
|
||||
return false if remember_exists_and_not_expired?
|
||||
|
||||
last_access && last_access <= self.class.timeout_in.ago
|
||||
|
||||
timeout_in = self.class.timeout_in
|
||||
timeout_in = timeout_in.call(self) if timeout_in.respond_to?(:call)
|
||||
|
||||
!timeout_in.nil? && last_access && last_access <= timeout_in.ago
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def remember_exists_and_not_expired?
|
||||
return false unless respond_to?(:remember_expired?)
|
||||
|
||||
|
||||
remember_created_at && !remember_expired?
|
||||
end
|
||||
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :timeout_in)
|
||||
end
|
||||
|
||||
@@ -5,18 +5,18 @@ module Devise
|
||||
# Track information about your user sign in. It tracks the following columns:
|
||||
#
|
||||
# * sign_in_count - Increased every time a sign in is made (by form, openid, oauth)
|
||||
# * current_sign_in_at - A tiemstamp updated when the user signs in
|
||||
# * current_sign_in_at - A timestamp updated when the user signs in
|
||||
# * last_sign_in_at - Holds the timestamp of the previous sign in
|
||||
# * current_sign_in_ip - The remote ip updated when the user sign in
|
||||
# * last_sign_in_at - Holds the remote ip of the previous sign in
|
||||
# * last_sign_in_ip - Holds the remote ip of the previous sign in
|
||||
#
|
||||
module Trackable
|
||||
def update_tracked_fields!(request)
|
||||
old_current, new_current = self.current_sign_in_at, Time.now
|
||||
old_current, new_current = self.current_sign_in_at, Time.now.utc
|
||||
self.last_sign_in_at = old_current || new_current
|
||||
self.current_sign_in_at = new_current
|
||||
|
||||
old_current, new_current = self.current_sign_in_ip, request.remote_ip
|
||||
old_current, new_current = self.current_sign_in_ip, request.ip
|
||||
self.last_sign_in_ip = old_current || new_current
|
||||
self.current_sign_in_ip = new_current
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ module Devise
|
||||
module Models
|
||||
# Validatable creates all needed validations for a user email and password.
|
||||
# It's optional, given you may want to create the validations by yourself.
|
||||
# Automatically validate if the email is present, unique and it's format is
|
||||
# Automatically validate if the email is present, unique and its format is
|
||||
# valid. Also tests presence of password, confirmation and length.
|
||||
#
|
||||
# == Options
|
||||
@@ -10,7 +10,7 @@ module Devise
|
||||
# Validatable adds the following options to devise_for:
|
||||
#
|
||||
# * +email_regexp+: the regular expression used to validate e-mails;
|
||||
# * +password_length+: a range expressing password length. Defaults to 6..20.
|
||||
# * +password_length+: a range expressing password length. Defaults to 6..128.
|
||||
#
|
||||
module Validatable
|
||||
# All validations used by this module.
|
||||
@@ -23,15 +23,12 @@ module Devise
|
||||
|
||||
base.class_eval do
|
||||
validates_presence_of :email, :if => :email_required?
|
||||
validates_uniqueness_of :email, :scope => authentication_keys[1..-1],
|
||||
:case_sensitive => case_insensitive_keys.exclude?(:email), :allow_blank => true
|
||||
validates_format_of :email, :with => email_regexp, :allow_blank => true
|
||||
validates_uniqueness_of :email, :case_sensitive => (case_insensitive_keys != false), :allow_blank => true, :if => :email_changed?
|
||||
validates_format_of :email, :with => email_regexp, :allow_blank => true, :if => :email_changed?
|
||||
|
||||
with_options :if => :password_required? do |v|
|
||||
v.validates_presence_of :password
|
||||
v.validates_confirmation_of :password
|
||||
v.validates_length_of :password, :within => password_length, :allow_blank => true
|
||||
end
|
||||
validates_presence_of :password, :if => :password_required?
|
||||
validates_confirmation_of :password, :if => :password_required?
|
||||
validates_length_of :password, :within => password_length, :allow_blank => true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Devise.with_options :model => true do |d|
|
||||
d.with_options :strategy => true do |s|
|
||||
routes = [nil, :new, :destroy]
|
||||
s.add_module :database_authenticatable, :controller => :sessions, :route => { :session => routes }
|
||||
s.add_module :token_authenticatable, :controller => :sessions, :route => { :session => routes }
|
||||
s.add_module :token_authenticatable
|
||||
s.add_module :rememberable
|
||||
end
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
begin
|
||||
require "omniauth/core"
|
||||
require "omniauth"
|
||||
require "omniauth/version"
|
||||
rescue LoadError => e
|
||||
warn "Could not load 'omniauth/core'. Please ensure you have the oa-core gem installed and listed in your Gemfile."
|
||||
warn "Could not load 'omniauth'. Please ensure you have the omniauth gem >= 1.0.0 installed and listed in your Gemfile."
|
||||
raise
|
||||
end
|
||||
|
||||
unless OmniAuth.config.respond_to? :test_mode
|
||||
raise "You are using an old OmniAuth version, please ensure you have 0.2.0.beta version or later installed."
|
||||
unless OmniAuth::VERSION =~ /^1\./
|
||||
raise "You are using an old OmniAuth version, please ensure you have 1.0.0.pr2 version or later installed."
|
||||
end
|
||||
|
||||
# Clean up the default path_prefix. It will be automatically set by Devise.
|
||||
@@ -14,19 +15,14 @@ OmniAuth.config.path_prefix = nil
|
||||
|
||||
OmniAuth.config.on_failure = Proc.new do |env|
|
||||
env['devise.mapping'] = Devise::Mapping.find_by_path!(env['PATH_INFO'], :path)
|
||||
controller_klass = "#{env['devise.mapping'].controllers[:omniauth_callbacks].camelize}Controller"
|
||||
controller_klass.constantize.action(:failure).call(env)
|
||||
controller_name = ActiveSupport::Inflector.camelize(env['devise.mapping'].controllers[:omniauth_callbacks])
|
||||
controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
|
||||
controller_klass.action(:failure).call(env)
|
||||
end
|
||||
|
||||
module Devise
|
||||
module OmniAuth
|
||||
autoload :Config, "devise/omniauth/config"
|
||||
autoload :UrlHelpers, "devise/omniauth/url_helpers"
|
||||
autoload :TestHelpers, "devise/omniauth/test_helpers"
|
||||
|
||||
class << self
|
||||
delegate :short_circuit_authorizers!, :unshort_circuit_authorizers!,
|
||||
:test_mode!, :stub!, :reset_stubs!, :to => "Devise::OmniAuth::TestHelpers"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,30 +1,45 @@
|
||||
module Devise
|
||||
module OmniAuth
|
||||
class StrategyNotFound < NameError
|
||||
def initialize(strategy)
|
||||
@strategy = strategy
|
||||
super("Could not find a strategy with name `#{strategy}'. " \
|
||||
"Please ensure it is required or explicitly set it using the :strategy_class option.")
|
||||
end
|
||||
end
|
||||
|
||||
class Config
|
||||
attr_accessor :strategy
|
||||
attr_reader :args
|
||||
attr_reader :args, :options, :provider, :strategy_name
|
||||
|
||||
def initialize(provider, args)
|
||||
@provider = provider
|
||||
@args = args
|
||||
@strategy = nil
|
||||
@provider = provider
|
||||
@args = args
|
||||
@options = @args.last.is_a?(Hash) ? @args.last : {}
|
||||
@strategy = nil
|
||||
@strategy_name = options[:name] || @provider
|
||||
@strategy_class = options.delete(:strategy_class)
|
||||
end
|
||||
|
||||
def strategy_class
|
||||
::OmniAuth::Strategies.const_get("#{::OmniAuth::Utils.camelize(@provider.to_s)}")
|
||||
@strategy_class ||= find_strategy || autoload_strategy
|
||||
end
|
||||
|
||||
def check_if_allow_stubs!
|
||||
raise "OmniAuth strategy for #{@provider} does not allow stubs, only OAuth2 ones do." unless allow_stubs?
|
||||
def find_strategy
|
||||
::OmniAuth.strategies.find do |strategy_class|
|
||||
strategy_class.to_s =~ /#{::OmniAuth::Utils.camelize(strategy_name)}$/ ||
|
||||
strategy_class.default_options[:name] == strategy_name
|
||||
end
|
||||
end
|
||||
|
||||
def allow_stubs?
|
||||
defined?(::OmniAuth::Strategies::OAuth2) && strategy.is_a?(::OmniAuth::Strategies::OAuth2)
|
||||
end
|
||||
|
||||
def build_connection(&block)
|
||||
strategy.client.connection.build(&block)
|
||||
def autoload_strategy
|
||||
name = ::OmniAuth::Utils.camelize(provider.to_s)
|
||||
if ::OmniAuth::Strategies.const_defined?(name)
|
||||
::OmniAuth::Strategies.const_get(name)
|
||||
else
|
||||
raise StrategyNotFound, name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
module Devise
|
||||
module OmniAuth
|
||||
module TestHelpers
|
||||
DEPRECATION_MESSAGE = "Faraday changed the way mocks work in a way incompatible to Devise. Luckily, Omniauth now supports a new test mode, please use it in your tests instead: https://github.com/intridea/omniauth/wiki/Integration-Testing"
|
||||
|
||||
DeprecationError = Class.new(StandardError)
|
||||
|
||||
def self.stub!(*args)
|
||||
raise DeprecationError, DEPRECATION_MESSAGE
|
||||
end
|
||||
|
||||
def self.reset_stubs!(*args)
|
||||
raise DeprecationError, DEPRECATION_MESSAGE
|
||||
end
|
||||
|
||||
def self.test_mode!
|
||||
warn DEPRECATION_MESSAGE
|
||||
end
|
||||
|
||||
def self.short_circuit_authorizers!
|
||||
::OmniAuth.config.test_mode = true
|
||||
warn DEPRECATION_MESSAGE
|
||||
end
|
||||
|
||||
def self.unshort_circuit_authorizers!
|
||||
::OmniAuth.config.test_mode = false
|
||||
warn DEPRECATION_MESSAGE
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
41
lib/devise/param_filter.rb
Normal file
41
lib/devise/param_filter.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
module Devise
|
||||
class ParamFilter
|
||||
def initialize(case_insensitive_keys, strip_whitespace_keys)
|
||||
@case_insensitive_keys = case_insensitive_keys || []
|
||||
@strip_whitespace_keys = strip_whitespace_keys || []
|
||||
end
|
||||
|
||||
def filter(conditions)
|
||||
conditions = stringify_params(conditions.dup)
|
||||
|
||||
@case_insensitive_keys.each do |k|
|
||||
value = conditions[k]
|
||||
next unless value.respond_to?(:downcase)
|
||||
conditions[k] = value.downcase
|
||||
end
|
||||
|
||||
@strip_whitespace_keys.each do |k|
|
||||
value = conditions[k]
|
||||
next unless value.respond_to?(:strip)
|
||||
conditions[k] = value.strip
|
||||
end
|
||||
|
||||
conditions
|
||||
end
|
||||
|
||||
# Force keys to be string to avoid injection on mongoid related database.
|
||||
def stringify_params(conditions)
|
||||
return conditions unless conditions.is_a?(Hash)
|
||||
conditions.each do |k, v|
|
||||
conditions[k] = v.to_s if param_requires_string_conversion?(v)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determine which values should be transformed to string or passed as-is to the query builder underneath
|
||||
def param_requires_string_conversion?(value)
|
||||
true unless value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(Fixnum)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -29,21 +29,16 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
initializer "devise.encryptor_check" do
|
||||
case Devise.encryptor
|
||||
when :bcrypt
|
||||
puts "[DEVISE] From version 1.2, there is no need to set your encryptor to bcrypt " <<
|
||||
"since encryptors are only enabled if you include :encryptable in your models. " <<
|
||||
"With this change, we can integrate better with bcrypt and get rid of the " <<
|
||||
"password_salt column (since bcrypt stores the salt with password). " <<
|
||||
"Please comment config.encryptor in your initializer to get rid of this warning."
|
||||
when nil
|
||||
# Nothing to say
|
||||
else
|
||||
puts "[DEVISE] You are using #{Devise.encryptor} as encryptor. From version 1.2, " <<
|
||||
"you need to explicitly add `devise :encryptable, :encryptor => :#{Devise.encryptor}` " <<
|
||||
"to your models and comment the current value in the config/initializers/devise.rb. " <<
|
||||
"You must also add t.encryptable to your existing migrations."
|
||||
initializer "devise.mongoid_version_warning" do
|
||||
if defined?(Mongoid)
|
||||
require 'mongoid/version'
|
||||
if Mongoid::VERSION.to_f < 2.1
|
||||
puts "\n[DEVISE] Please note that Mongoid versions prior to 2.1 handle dirty model " \
|
||||
"object attributes in such a way that the Devise `validatable` module will not apply " \
|
||||
"its usual uniqueness and format validations for the email field. It is recommended " \
|
||||
"that you upgrade to Mongoid 2.1+ for this and other fixes, but if for some reason you " \
|
||||
"are unable to do so, you should add these validations manually.\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,12 @@ module ActionDispatch::Routing
|
||||
# need devise_for mappings already declared to create filters and helpers.
|
||||
def finalize_with_devise!
|
||||
finalize_without_devise!
|
||||
Devise.configure_warden!
|
||||
|
||||
@devise_finalized ||= begin
|
||||
Devise.configure_warden!
|
||||
Devise.regenerate_helpers!
|
||||
true
|
||||
end
|
||||
end
|
||||
alias_method_chain :finalize!, :devise
|
||||
end
|
||||
@@ -44,23 +49,23 @@ module ActionDispatch::Routing
|
||||
#
|
||||
# You can configure your routes with some options:
|
||||
#
|
||||
# * :class_name => setup a different class to be looked up by devise,
|
||||
# if it cannot be correctly find by the route name.
|
||||
# * :class_name => setup a different class to be looked up by devise, if it cannot be
|
||||
# properly found by the route name.
|
||||
#
|
||||
# devise_for :users, :class_name => 'Account'
|
||||
#
|
||||
# * :path => allows you to setup path name that will be used, as rails routes does.
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
# The following route configuration would setup your route as /accounts instead of /users:
|
||||
#
|
||||
# devise_for :users, :path => 'accounts'
|
||||
#
|
||||
# * :singular => setup the singular name for the given resource. This is used as the instance variable name in
|
||||
# controller, as the name in routes and the scope given to warden.
|
||||
# * :singular => setup the singular name for the given resource. This is used as the instance variable
|
||||
# name in controller, as the name in routes and the scope given to warden.
|
||||
#
|
||||
# devise_for :users, :singular => :user
|
||||
#
|
||||
# * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up,
|
||||
# :password, :confirmation, :unlock.
|
||||
# :password, :confirmation, :unlock.
|
||||
#
|
||||
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
|
||||
#
|
||||
@@ -69,6 +74,9 @@ module ActionDispatch::Routing
|
||||
#
|
||||
# devise_for :users, :controllers => { :sessions => "users/sessions" }
|
||||
#
|
||||
# * :failure_app => a rack app which is invoked whenever there is a failure. Strings representing a given
|
||||
# are also allowed as parameter.
|
||||
#
|
||||
# * :sign_out_via => the HTTP method(s) accepted for the :sign_out action (default: :get),
|
||||
# if you wish to restrict this to accept only :post or :delete requests you should do:
|
||||
#
|
||||
@@ -93,12 +101,32 @@ module ActionDispatch::Routing
|
||||
#
|
||||
# Also pay attention that when you use a namespace it will affect all the helpers and methods for controllers
|
||||
# and views. For example, using the above setup you'll end with following methods:
|
||||
# current_publisher_account, authenticate_publisher_account!, pusblisher_account_signed_in, etc.
|
||||
# current_publisher_account, authenticate_publisher_account!, publisher_account_signed_in, etc.
|
||||
#
|
||||
# * :skip => tell which controller you want to skip routes from being created:
|
||||
#
|
||||
# devise_for :users, :skip => :sessions
|
||||
#
|
||||
# * :only => the opposite of :skip, tell which controllers only to generate routes to:
|
||||
#
|
||||
# devise_for :users, :only => :sessions
|
||||
#
|
||||
# * :skip_helpers => skip generating Devise url helpers like new_session_path(@user).
|
||||
# This is useful to avoid conflicts with previous routes and is false by default.
|
||||
# It accepts true as option, meaning it will skip all the helpers for the controllers
|
||||
# given in :skip but it also accepts specific helpers to be skipped:
|
||||
#
|
||||
# devise_for :users, :skip => [:registrations, :confirmations], :skip_helpers => true
|
||||
# devise_for :users, :skip_helpers => [:registrations, :confirmations]
|
||||
#
|
||||
# * :format => include "(.:format)" in the generated routes? true by default, set to false to disable:
|
||||
#
|
||||
# devise_for :users, :format => false
|
||||
#
|
||||
# * :constraints => works the same as Rails' contraints
|
||||
#
|
||||
# * :defaults => works the same as Rails' defaults
|
||||
#
|
||||
# ==== Scoping
|
||||
#
|
||||
# Following Rails 3 routes DSL, you can nest devise_for calls inside a scope:
|
||||
@@ -124,9 +152,9 @@ module ActionDispatch::Routing
|
||||
# end
|
||||
#
|
||||
# ==== Adding custom actions to override controllers
|
||||
#
|
||||
# You can pass a block to devise_for that will add any routes defined in the block to Devise's
|
||||
# list of known actions. This is important if you add a custom action to a controller that
|
||||
#
|
||||
# You can pass a block to devise_for that will add any routes defined in the block to Devise's
|
||||
# list of known actions. This is important if you add a custom action to a controller that
|
||||
# overrides an out of the box Devise controller.
|
||||
# For example:
|
||||
#
|
||||
@@ -148,12 +176,16 @@ module ActionDispatch::Routing
|
||||
# end
|
||||
#
|
||||
def devise_for(*resources)
|
||||
@devise_finalized = false
|
||||
options = resources.extract_options!
|
||||
|
||||
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] || {})
|
||||
options[:constraints] = (@scope[:constraints] || {}).merge(options[:constraints] || {})
|
||||
options[:defaults] = (@scope[:defaults] || {}).merge(options[:defaults] || {})
|
||||
@scope[:options] = (@scope[:options] || {}).merge({:format => false}) if options[:format] == false
|
||||
|
||||
resources.map!(&:to_sym)
|
||||
|
||||
@@ -172,12 +204,11 @@ module ActionDispatch::Routing
|
||||
raise_no_devise_method_error!(mapping.class_name)
|
||||
end
|
||||
|
||||
routes = mapping.routes
|
||||
routes -= Array(options.delete(:skip)).map { |s| s.to_s.singularize.to_sym }
|
||||
routes = mapping.used_routes
|
||||
|
||||
devise_scope mapping.name do
|
||||
yield if block_given?
|
||||
with_devise_exclusive_scope mapping.fullpath, mapping.name do
|
||||
with_devise_exclusive_scope mapping.fullpath, mapping.name, mapping.constraints, mapping.defaults do
|
||||
routes.each { |mod| send("devise_#{mod}", mapping, mapping.controllers) }
|
||||
end
|
||||
end
|
||||
@@ -186,11 +217,15 @@ module ActionDispatch::Routing
|
||||
|
||||
# Allow you to add authentication request from the router:
|
||||
#
|
||||
# authenticate(:user) do
|
||||
# authenticate do
|
||||
# resources :post
|
||||
# end
|
||||
#
|
||||
def authenticate(scope)
|
||||
# authenticate(:admin) do
|
||||
# resources :users
|
||||
# end
|
||||
#
|
||||
def authenticate(scope=nil)
|
||||
constraint = lambda do |request|
|
||||
request.env["warden"].authenticate!(:scope => scope)
|
||||
end
|
||||
@@ -200,6 +235,50 @@ module ActionDispatch::Routing
|
||||
end
|
||||
end
|
||||
|
||||
# Allow you to route based on whether a scope is authenticated. You
|
||||
# can optionally specify which scope.
|
||||
#
|
||||
# authenticated :admin do
|
||||
# root :to => 'admin/dashboard#show'
|
||||
# end
|
||||
#
|
||||
# authenticated do
|
||||
# root :to => 'dashboard#show'
|
||||
# end
|
||||
#
|
||||
# root :to => 'landing#show'
|
||||
#
|
||||
def authenticated(scope=nil)
|
||||
constraint = lambda do |request|
|
||||
request.env["warden"].authenticate? :scope => scope
|
||||
end
|
||||
|
||||
constraints(constraint) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
# Allow you to route based on whether a scope is *not* authenticated.
|
||||
# You can optionally specify which scope.
|
||||
#
|
||||
# unauthenticated do
|
||||
# as :user do
|
||||
# root :to => 'devise/registrations#new'
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# root :to => 'dashboard#show'
|
||||
#
|
||||
def unauthenticated(scope=nil)
|
||||
constraint = lambda do |request|
|
||||
not request.env["warden"].authenticate? :scope => scope
|
||||
end
|
||||
|
||||
constraints(constraint) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the devise scope to be used in the controller. If you have custom routes,
|
||||
# you are required to call this method (also aliased as :as) in order to specify
|
||||
# to which controller it is targetted.
|
||||
@@ -211,6 +290,17 @@ module ActionDispatch::Routing
|
||||
# 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.
|
||||
#
|
||||
# Also be aware of that 'devise_scope' and 'as' use the singular form of the
|
||||
# noun where other devise route commands expect the plural form. This would be a
|
||||
# good and working example.
|
||||
#
|
||||
# devise_scope :user do
|
||||
# match "/some/route" => "some_devise_controller"
|
||||
# end
|
||||
# devise_for :users
|
||||
#
|
||||
# Notice and be aware of the differences above between :user and :users
|
||||
def devise_scope(scope)
|
||||
constraint = lambda do |request|
|
||||
request.env["devise.mapping"] = Devise.mappings[scope]
|
||||
@@ -256,36 +346,39 @@ module ActionDispatch::Routing
|
||||
:cancel => mapping.path_names[:cancel]
|
||||
}
|
||||
|
||||
resource :registration, :except => :show, :path => mapping.path_names[:registration],
|
||||
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => mapping.path_names[:registration],
|
||||
:path_names => path_names, :controller => controllers[:registrations] do
|
||||
get :cancel
|
||||
end
|
||||
end
|
||||
|
||||
def devise_omniauth_callback(mapping, controllers) #:nodoc:
|
||||
path_prefix = "/#{mapping.path}/auth"
|
||||
path, @scope[:path] = @scope[:path], nil
|
||||
path_prefix = "/#{mapping.path}/auth".squeeze("/")
|
||||
|
||||
if ::OmniAuth.config.path_prefix && ::OmniAuth.config.path_prefix != path_prefix
|
||||
warn "[DEVISE] You can only add :omniauthable behavior to one model."
|
||||
raise "You can only add :omniauthable behavior to one Devise model"
|
||||
else
|
||||
::OmniAuth.config.path_prefix = path_prefix
|
||||
end
|
||||
|
||||
match "/auth/:action/callback", :action => Regexp.union(mapping.to.omniauth_providers.map(&:to_s)),
|
||||
match "#{path_prefix}/:action/callback", :constraints => { :action => Regexp.union(mapping.to.omniauth_providers.map(&:to_s)) },
|
||||
:to => controllers[:omniauth_callbacks], :as => :omniauth_callback
|
||||
ensure
|
||||
@scope[:path] = path
|
||||
end
|
||||
|
||||
def with_devise_exclusive_scope(new_path, new_as) #:nodoc:
|
||||
old_as, old_path, old_module = @scope[:as], @scope[:path], @scope[:module]
|
||||
@scope[:as], @scope[:path], @scope[:module] = new_as, new_path, nil
|
||||
def with_devise_exclusive_scope(new_path, new_as, new_constraints, new_defaults) #:nodoc:
|
||||
old_as, old_path, old_module, old_constraints, old_defaults = @scope[:as], @scope[:path], @scope[:module], @scope[:constraints], @scope[:defaults]
|
||||
@scope[:as], @scope[:path], @scope[:module], @scope[:constraints], @scope[:defaults] = new_as, new_path, nil, new_constraints, new_defaults
|
||||
yield
|
||||
ensure
|
||||
@scope[:as], @scope[:path], @scope[:module] = old_as, old_path, old_module
|
||||
@scope[:as], @scope[:path], @scope[:module], @scope[:constraints], @scope[:defaults] = old_as, old_path, old_module, old_constraints, old_defaults
|
||||
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' " <<
|
||||
raise "#{klass} does not respond to 'devise' method. This usually means you haven't " \
|
||||
"loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " \
|
||||
"inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,21 +15,16 @@ end
|
||||
|
||||
class Warden::SessionSerializer
|
||||
def serialize(record)
|
||||
[record.class.name, record.to_key, record.authenticatable_salt]
|
||||
klass = record.class
|
||||
array = klass.serialize_into_session(record)
|
||||
array.unshift(klass.name)
|
||||
end
|
||||
|
||||
def deserialize(keys)
|
||||
if keys.size == 2
|
||||
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 or cleaning up your " <<
|
||||
"database sessions if you are using a db store."
|
||||
end
|
||||
|
||||
klass, id, salt = keys
|
||||
klass, *args = keys
|
||||
|
||||
begin
|
||||
record = klass.constantize.to_adapter.get(id)
|
||||
record if record && record.authenticatable_salt == salt
|
||||
ActiveSupport::Inflector.constantize(klass).serialize_from_session(*args)
|
||||
rescue NameError => e
|
||||
if e.message =~ /uninitialized constant/
|
||||
Rails.logger.debug "[Devise] Trying to deserialize invalid class #{klass}"
|
||||
|
||||
@@ -3,11 +3,12 @@ module Devise
|
||||
# and overwrite the apply_schema method.
|
||||
module Schema
|
||||
|
||||
# Creates email when enabled (on by default), encrypted_password and password_salt.
|
||||
# Creates encrypted_password, and email when it is used as an authentication
|
||||
# key (default).
|
||||
#
|
||||
# == Options
|
||||
# * :null - When true, allow columns to be null.
|
||||
# * :default - Should be set to "" when :null is false.
|
||||
# * :default - Set to "" when :null is false, unless overridden.
|
||||
#
|
||||
# == Notes
|
||||
# For Datamapper compatibility, we explicitly hardcode the limit for the
|
||||
@@ -15,13 +16,14 @@ module Devise
|
||||
def database_authenticatable(options={})
|
||||
null = options[:null] || false
|
||||
default = options.key?(:default) ? options[:default] : ("" if null == false)
|
||||
include_email = !self.respond_to?(:authentication_keys) || self.authentication_keys.include?(:email)
|
||||
include_email = !respond_to?(:authentication_keys) || self.authentication_keys.include?(:email)
|
||||
|
||||
apply_devise_schema :email, String, :null => null, :default => default if include_email
|
||||
apply_devise_schema :encrypted_password, String, :null => null, :default => default, :limit => 128
|
||||
end
|
||||
|
||||
# Creates password salt for encryption support.
|
||||
# Creates password salt for encryption support when using encryptors other
|
||||
# than the database_authenticable default of bcrypt.
|
||||
def encryptable
|
||||
apply_devise_schema :password_salt, String
|
||||
end
|
||||
@@ -38,9 +40,14 @@ module Devise
|
||||
apply_devise_schema :confirmation_sent_at, DateTime
|
||||
end
|
||||
|
||||
# Creates reset_password_token.
|
||||
def recoverable
|
||||
# Creates reset_password_token and reset_password_sent_at.
|
||||
#
|
||||
# == Options
|
||||
# * :reset_within - When true, adds a column that reset passwords within some date
|
||||
def recoverable(options={})
|
||||
use_within = options.fetch(:reset_within, Devise.reset_password_within.present?)
|
||||
apply_devise_schema :reset_password_token, String
|
||||
apply_devise_schema :reset_password_sent_at, DateTime if use_within
|
||||
end
|
||||
|
||||
# Creates remember_token and remember_created_at.
|
||||
|
||||
@@ -85,17 +85,7 @@ module Devise
|
||||
|
||||
# By default, a request is valid if the controller is allowed and the VERB is POST.
|
||||
def valid_request?
|
||||
valid_controller? && valid_verb?
|
||||
end
|
||||
|
||||
# Check if the controller is the one registered for authentication.
|
||||
def valid_controller?
|
||||
mapping.controllers[:sessions] == params[:controller]
|
||||
end
|
||||
|
||||
# Check if it was a POST request.
|
||||
def valid_verb?
|
||||
request.post?
|
||||
!!env["devise.allow_params_authentication"]
|
||||
end
|
||||
|
||||
# If the request is valid, finally check if params_auth_hash returns a hash.
|
||||
@@ -157,7 +147,8 @@ module Devise
|
||||
# becomes simply :database.
|
||||
def authenticatable_name
|
||||
@authenticatable_name ||=
|
||||
self.class.name.split("::").last.underscore.sub("_authenticatable", "").to_sym
|
||||
ActiveSupport::Inflector.underscore(self.class.name.split("::").last).
|
||||
sub("_authenticatable", "").to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,7 @@ module Devise
|
||||
class Rememberable < Authenticatable
|
||||
# A valid strategy for rememberable needs a remember token in the cookies.
|
||||
def valid?
|
||||
@remember_cookie = nil
|
||||
remember_cookie.present?
|
||||
end
|
||||
|
||||
@@ -41,10 +42,10 @@ module Devise
|
||||
"remember_#{scope}_token"
|
||||
end
|
||||
|
||||
# Accessor for remember cookie
|
||||
def remember_cookie
|
||||
@remember_cookie ||= cookies.signed[remember_key]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,7 +39,11 @@ module Devise
|
||||
|
||||
# Try both scoped and non scoped keys.
|
||||
def params_auth_hash
|
||||
params[scope] || params
|
||||
if params[scope].kind_of?(Hash) && params[scope].has_key?(authentication_keys.first)
|
||||
params[scope]
|
||||
else
|
||||
params
|
||||
end
|
||||
end
|
||||
|
||||
# Overwrite authentication keys to use token_authentication_key.
|
||||
|
||||
@@ -13,48 +13,11 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# This is a Warden::Proxy customized for functional tests. It's meant to
|
||||
# some of Warden::Manager responsibilities, as retrieving configuration
|
||||
# options and calling the FailureApp.
|
||||
class TestWarden < Warden::Proxy #:nodoc:
|
||||
attr_reader :controller
|
||||
|
||||
def initialize(controller)
|
||||
@controller = controller
|
||||
manager = Warden::Manager.new(nil) do |config|
|
||||
config.merge! Devise.warden_config
|
||||
end
|
||||
super(controller.request.env, manager)
|
||||
end
|
||||
|
||||
def authenticate!(*args)
|
||||
catch_with_redirect { super }
|
||||
end
|
||||
|
||||
def user(*args)
|
||||
catch_with_redirect { super }
|
||||
end
|
||||
|
||||
def catch_with_redirect(&block)
|
||||
result = catch(:warden, &block)
|
||||
|
||||
if result.is_a?(Hash) && !custom_failure? && !@controller.send(:performed?)
|
||||
result[:action] ||= :unauthenticated
|
||||
|
||||
env = @controller.request.env
|
||||
env["PATH_INFO"] = "/#{result[:action]}"
|
||||
env["warden.options"] = result
|
||||
Warden::Manager._run_callbacks(:before_failure, env, result)
|
||||
|
||||
status, headers, body = Devise.warden_config[:failure_app].call(env).to_a
|
||||
@controller.send :render, :status => status, :text => body,
|
||||
:content_type => headers["Content-Type"], :location => headers["Location"]
|
||||
|
||||
nil
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
# Override process to consider warden.
|
||||
def process(*)
|
||||
result = nil
|
||||
_catch_warden { result = super }
|
||||
result
|
||||
end
|
||||
|
||||
# We need to setup the environment variables and the response in the controller.
|
||||
@@ -64,7 +27,12 @@ module Devise
|
||||
|
||||
# Quick access to Warden::Proxy.
|
||||
def warden #:nodoc:
|
||||
@warden ||= (@request.env['warden'] = TestWarden.new(@controller))
|
||||
@warden ||= begin
|
||||
manager = Warden::Manager.new(nil) do |config|
|
||||
config.merge! Devise.warden_config
|
||||
end
|
||||
@request.env['warden'] = Warden::Proxy.new(@request.env, manager)
|
||||
end
|
||||
end
|
||||
|
||||
# sign_in a given resource by storing its keys in the session.
|
||||
@@ -96,5 +64,27 @@ module Devise
|
||||
warden.session_serializer.delete(scope, user)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def _catch_warden(&block)
|
||||
result = catch(:warden, &block)
|
||||
|
||||
if result.is_a?(Hash) && !warden.custom_failure? && !@controller.send(:performed?)
|
||||
result[:action] ||= :unauthenticated
|
||||
|
||||
env = @controller.request.env
|
||||
env["PATH_INFO"] = "/#{result[:action]}"
|
||||
env["warden.options"] = result
|
||||
Warden::Manager._run_callbacks(:before_failure, env, result)
|
||||
|
||||
status, headers, body = Devise.warden_config[:failure_app].call(env).to_a
|
||||
@controller.send :render, :status => status, :text => body,
|
||||
:content_type => headers["Content-Type"], :location => headers["Location"]
|
||||
|
||||
nil
|
||||
else
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Devise
|
||||
VERSION = "1.2.rc2".freeze
|
||||
VERSION = "1.5.2".freeze
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'rails/generators/active_record'
|
||||
require 'generators/devise/orm_helpers'
|
||||
|
||||
|
||||
module ActiveRecord
|
||||
module Generators
|
||||
class DeviseGenerator < ActiveRecord::Generators::Base
|
||||
@@ -9,14 +10,18 @@ module ActiveRecord
|
||||
include Devise::Generators::OrmHelpers
|
||||
source_root File.expand_path("../templates", __FILE__)
|
||||
|
||||
def copy_devise_migration
|
||||
if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
||||
migration_template "migration_existing.rb", "db/migrate/add_devise_to_#{table_name}"
|
||||
else
|
||||
migration_template "migration.rb", "db/migrate/devise_create_#{table_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def generate_model
|
||||
invoke "active_record:model", [name], :migration => false unless model_exists? && behavior == :invoke
|
||||
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) if model_exists?
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
|
||||
<% if ::Rails::VERSION::MAJOR == 3 && ::Rails::VERSION::MINOR >= 1 -%>
|
||||
def change
|
||||
<% else -%>
|
||||
def self.up
|
||||
<% end -%>
|
||||
create_table(:<%= table_name %>) do |t|
|
||||
t.database_authenticatable :null => false
|
||||
t.recoverable
|
||||
@@ -11,7 +15,7 @@ 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 -%>
|
||||
<% attributes.each do |attribute| -%>
|
||||
t.<%= attribute.type %> :<%= attribute.name %>
|
||||
<% end -%>
|
||||
|
||||
@@ -25,7 +29,9 @@ class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration
|
||||
# add_index :<%= table_name %>, :authentication_token, :unique => true
|
||||
end
|
||||
|
||||
<% unless ::Rails::VERSION::MAJOR == 3 && ::Rails::VERSION::MINOR >= 1 -%>
|
||||
def self.down
|
||||
drop_table :<%= table_name %>
|
||||
end
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
34
lib/generators/active_record/templates/migration_existing.rb
Normal file
34
lib/generators/active_record/templates/migration_existing.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
class AddDeviseTo<%= table_name.camelize %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
change_table(:<%= table_name %>) do |t|
|
||||
t.database_authenticatable :null => false
|
||||
t.recoverable
|
||||
t.rememberable
|
||||
t.trackable
|
||||
|
||||
# t.encryptable
|
||||
# t.confirmable
|
||||
# t.lockable :lock_strategy => :<%= Devise.lock_strategy %>, :unlock_strategy => :<%= Devise.unlock_strategy %>
|
||||
# t.token_authenticatable
|
||||
|
||||
<% attributes.each do |attribute| -%>
|
||||
t.<%= attribute.type %> :<%= attribute.name %>
|
||||
<% end -%>
|
||||
|
||||
# Uncomment below if timestamps were not included in your original model.
|
||||
# t.timestamps
|
||||
end
|
||||
|
||||
add_index :<%= table_name %>, :email, :unique => true
|
||||
add_index :<%= table_name %>, :reset_password_token, :unique => true
|
||||
# add_index :<%= table_name %>, :confirmation_token, :unique => true
|
||||
# add_index :<%= table_name %>, :unlock_token, :unique => true
|
||||
# add_index :<%= table_name %>, :authentication_token, :unique => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
# By default, we don't want to make any assumption about how to roll back a migration when your
|
||||
# model already existed. Please edit below which fields you would like to remove in this migration.
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
||||
@@ -9,9 +9,12 @@ module Devise
|
||||
|
||||
hook_for :orm
|
||||
|
||||
class_option :routes, :desc => "Generate routes", :type => :boolean, :default => true
|
||||
|
||||
def add_devise_routes
|
||||
devise_route = "devise_for :#{plural_name}"
|
||||
devise_route += %Q(, :class_name => "#{class_name}") if class_name.include?("::")
|
||||
devise_route << %Q(, :class_name => "#{class_name}") if class_name.include?("::")
|
||||
devise_route << %Q(, :skip => :all) unless options.routes?
|
||||
route devise_route
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require 'active_support/secure_random'
|
||||
require 'securerandom'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
@@ -21,4 +21,4 @@ module Devise
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,6 +14,14 @@ CONTENT
|
||||
def model_exists?
|
||||
File.exists?(File.join(destination_root, model_path))
|
||||
end
|
||||
|
||||
def migration_exists?(table_name)
|
||||
Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_to_#{table_name}.rb$/).first
|
||||
end
|
||||
|
||||
def migration_path
|
||||
@migration_path ||= File.join("db", "migrate")
|
||||
end
|
||||
|
||||
def model_path
|
||||
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
||||
|
||||
@@ -1,26 +1,98 @@
|
||||
require 'tmpdir'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
# Include this module in your generator to generate Devise views.
|
||||
# `copy_views` is the main method and by default copies all views
|
||||
# with forms.
|
||||
module ViewPathTemplates #:nodoc:
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
public_task :copy_views
|
||||
end
|
||||
|
||||
def copy_views
|
||||
view_directory :confirmations
|
||||
view_directory :passwords
|
||||
view_directory :registrations
|
||||
view_directory :sessions
|
||||
view_directory :unlocks
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def view_directory(name, _target_path = nil)
|
||||
directory name.to_s, _target_path || "#{target_path}/#{name}"
|
||||
end
|
||||
|
||||
def target_path
|
||||
@target_path ||= "app/views/#{scope || :devise}"
|
||||
end
|
||||
end
|
||||
|
||||
class SharedViewsGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
desc "Copies shared Devise views to your application."
|
||||
|
||||
# Override copy_views to just copy mailer and shared.
|
||||
def copy_views
|
||||
view_directory :shared
|
||||
end
|
||||
end
|
||||
|
||||
class FormForGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
desc "Copies default Devise views to your application."
|
||||
end
|
||||
|
||||
class SimpleFormForGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../templates/simple_form_for", __FILE__)
|
||||
desc "Copies simple form enabled views to your application."
|
||||
end
|
||||
|
||||
class ErbGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
||||
desc "Copies Devise mail erb views to your application."
|
||||
|
||||
def copy_views
|
||||
view_directory :mailer
|
||||
end
|
||||
end
|
||||
|
||||
class MarkerbGenerator < Rails::Generators::Base #:nodoc:
|
||||
include ViewPathTemplates
|
||||
source_root File.expand_path("../../templates", __FILE__)
|
||||
desc "Copies Devise mail markerb views to your application."
|
||||
|
||||
def copy_views
|
||||
view_directory :markerb, target_path
|
||||
end
|
||||
|
||||
def target_path
|
||||
"app/views/#{scope || :devise}/mailer"
|
||||
end
|
||||
end
|
||||
|
||||
class ViewsGenerator < Rails::Generators::Base
|
||||
source_root File.expand_path("../../../../app/views", __FILE__)
|
||||
desc "Copies all Devise views to your application."
|
||||
desc "Copies Devise views to your application."
|
||||
|
||||
argument :scope, :required => false, :default => nil,
|
||||
:desc => "The scope to copy views to"
|
||||
|
||||
class_option :template_engine, :type => :string, :aliases => "-t",
|
||||
:desc => "Template engine for the views. Available options are 'erb', 'haml' and 'slim'."
|
||||
invoke SharedViewsGenerator
|
||||
hook_for :form_builder, :aliases => "-b",
|
||||
:desc => "Form builder to be used",
|
||||
:default => defined?(SimpleForm) ? "simple_form_for" : "form_for"
|
||||
|
||||
def copy_views
|
||||
template = options[:template_engine].to_s
|
||||
case template
|
||||
when "haml", "slim"
|
||||
warn "#{template} templates have been removed from Devise gem"
|
||||
else
|
||||
directory "devise", "app/views/#{scope || :devise}"
|
||||
end
|
||||
end
|
||||
hook_for :markerb, :desc => "Generate markerb instead of erb mail views",
|
||||
:default => defined?(Markerb) ? :markerb : :erb,
|
||||
:type => :boolean
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,4 +22,11 @@ Some setup you must do manually if you haven't yet:
|
||||
<p class="notice"><%= notice %></p>
|
||||
<p class="alert"><%= alert %></p>
|
||||
|
||||
4. If you are deploying Rails 3.1 on Heroku, you may want to set:
|
||||
|
||||
config.assets.initialize_on_precompile = false
|
||||
|
||||
On config/application.rb forcing your application to not access the DB
|
||||
or load models when precompiling your assets.
|
||||
|
||||
===============================================================================
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# 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.
|
||||
# Use this hook to configure devise mailer, warden hooks and so forth.
|
||||
# Many of these configuration options can be set straight in your model.
|
||||
Devise.setup do |config|
|
||||
# ==> Mailer Configuration
|
||||
# Configure the e-mail address which will be shown in DeviseMailer.
|
||||
config.mailer_sender = "please-change-me@config-initializers-devise.com"
|
||||
# Configure the e-mail address which will be shown in Devise::Mailer,
|
||||
# note that it will be overwritten if you use your own mailer class with default "from" parameter.
|
||||
config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
|
||||
|
||||
# Configure the class responsible to send e-mails.
|
||||
# config.mailer = "Devise::Mailer"
|
||||
@@ -36,6 +37,11 @@ Devise.setup do |config|
|
||||
# to authenticate or find a user. Default is :email.
|
||||
config.case_insensitive_keys = [ :email ]
|
||||
|
||||
# Configure which authentication keys should have whitespace stripped.
|
||||
# These keys will have whitespace before and after removed upon creating or
|
||||
# modifying a user and when used to authenticate or find a user. Default is :email.
|
||||
config.strip_whitespace_keys = [ :email ]
|
||||
|
||||
# Tell if authentication through request.params is enabled. True by default.
|
||||
# config.params_authenticatable = true
|
||||
|
||||
@@ -48,21 +54,29 @@ Devise.setup do |config|
|
||||
# The realm used in Http Basic Authentication. "Application" by default.
|
||||
# config.http_authentication_realm = "Application"
|
||||
|
||||
# It will change confirmation, password recovery and other workflows
|
||||
# to behave the same regardless if the e-mail provided was right or wrong.
|
||||
# Does not affect registerable.
|
||||
# config.paranoid = true
|
||||
|
||||
# ==> 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
|
||||
#
|
||||
# Limiting the stretches to just one in testing will increase the performance of
|
||||
# your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
|
||||
# a value less than 10 in other environments.
|
||||
config.stretches = Rails.env.test? ? 1 : 10
|
||||
|
||||
# Setup a pepper to generate the encrypted password.
|
||||
# config.pepper = <%= ActiveSupport::SecureRandom.hex(64).inspect %>
|
||||
# config.pepper = <%= SecureRandom.hex(64).inspect %>
|
||||
|
||||
# ==> Configuration for :confirmable
|
||||
# The time you want to give your user to confirm his account. During this time
|
||||
# he will be able to access your application without confirming. Default is 0.days
|
||||
# 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).
|
||||
# A period that the user is allowed to access the website even without
|
||||
# confirming his account. For instance, if set to 2.days, the user will be
|
||||
# able to access the website for two days without confirming his account,
|
||||
# access will be blocked just in the third day. Default is 0.days, meaning
|
||||
# the user cannot access the website without confirming his account.
|
||||
# config.confirm_within = 2.days
|
||||
|
||||
# Defines which key will be used when confirming an account
|
||||
@@ -82,12 +96,18 @@ Devise.setup do |config|
|
||||
# to false if you are not using database authenticatable.
|
||||
config.use_salt_as_remember_token = true
|
||||
|
||||
# ==> Configuration for :validatable
|
||||
# Range for password length. Default is 6..20.
|
||||
# config.password_length = 6..20
|
||||
# Options to be passed to the created cookie. For instance, you can set
|
||||
# :secure => true in order to force SSL only cookies.
|
||||
# config.cookie_options = {}
|
||||
|
||||
# Regex to use to validate the email address
|
||||
# config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
|
||||
# ==> Configuration for :validatable
|
||||
# Range for password length. Default is 6..128.
|
||||
# config.password_length = 6..128
|
||||
|
||||
# Email regex used to validate email formats. It simply asserts that
|
||||
# an one (and only one) @ exists in the given string. This is mainly
|
||||
# to give user feedback and not to assert the e-mail validity.
|
||||
# config.email_regexp = /\A[^@]+@[^@]+\z/
|
||||
|
||||
# ==> Configuration for :timeoutable
|
||||
# The time you want to timeout the user session without activity. After this
|
||||
@@ -122,6 +142,11 @@ Devise.setup do |config|
|
||||
# Defines which key will be used when recovering the password for an account
|
||||
# config.reset_password_keys = [ :email ]
|
||||
|
||||
# Time interval you can reset your password with a reset password key.
|
||||
# Don't put a too small interval or your users won't have the time to
|
||||
# change their passwords.
|
||||
config.reset_password_within = 2.hours
|
||||
|
||||
# ==> Configuration for :encryptable
|
||||
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
|
||||
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
|
||||
@@ -165,8 +190,8 @@ Devise.setup do |config|
|
||||
# Explorer requests.
|
||||
# config.navigational_formats = [:"*/*", "*/*", :html]
|
||||
|
||||
# The default HTTP method used to sign out a resource. Default is :get.
|
||||
# config.sign_out_via = :get
|
||||
# The default HTTP method used to sign out a resource. Default is :delete.
|
||||
config.sign_out_via = :delete
|
||||
|
||||
# ==> OmniAuth
|
||||
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
||||
@@ -178,7 +203,6 @@ Devise.setup do |config|
|
||||
# change the failure app, you can configure them inside the config.warden block.
|
||||
#
|
||||
# config.warden do |manager|
|
||||
# manager.failure_app = AnotherApp
|
||||
# manager.intercept_401 = false
|
||||
# manager.default_strategies(:scope => :user).unshift :some_external_strategy
|
||||
# end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Welcome <%= @resource.email %>!
|
||||
|
||||
You can confirm your account through the link below:
|
||||
|
||||
<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
|
||||
@@ -0,0 +1,8 @@
|
||||
Hello <%= @resource.email %>!
|
||||
|
||||
Someone has requested a link to change your password, and you can do this through the link below.
|
||||
|
||||
<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>
|
||||
|
||||
If you didn't request this, please ignore this email.
|
||||
Your password won't change until you access the link above and create a new one.
|
||||
@@ -0,0 +1,7 @@
|
||||
Hello <%= @resource.email %>!
|
||||
|
||||
Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
|
||||
|
||||
Click the link below to unlock your account:
|
||||
|
||||
<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>
|
||||
@@ -0,0 +1,15 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Resend confirmation instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -0,0 +1,19 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<%= f.input :reset_password_token, :as => :hidden %>
|
||||
<%= f.full_error :reset_password_token %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :password, :label => "New password", :required => true %>
|
||||
<%= f.input :password_confirmation, :label => "Confirm your new password", :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Change my password" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -0,0 +1,15 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Send me reset password instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -0,0 +1,22 @@
|
||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => true, :autofocus => true %>
|
||||
<%= f.input :password, :hint => "leave it blank if you don't want to change it", :required => false %>
|
||||
<%= f.input :password_confirmation, :required => false %>
|
||||
<%= f.input :current_password, :hint => "we need your current password to confirm your changes", :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Update" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3>Cancel my account</h3>
|
||||
|
||||
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
|
||||
|
||||
<%= link_to "Back", :back %>
|
||||
@@ -0,0 +1,17 @@
|
||||
<h2>Sign up</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => true, :autofocus => true %>
|
||||
<%= f.input :password, :required => true %>
|
||||
<%= f.input :password_confirmation, :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Sign up" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -0,0 +1,15 @@
|
||||
<h2>Sign in</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => false, :autofocus => true %>
|
||||
<%= f.input :password, :required => false %>
|
||||
<%= f.input :remember_me, :as => :boolean if devise_mapping.rememberable? %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Sign in" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -0,0 +1,15 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= simple_form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
|
||||
<%= f.error_notification %>
|
||||
|
||||
<div class="inputs">
|
||||
<%= f.input :email, :required => true %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.button :submit, "Resend unlock instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "devise/shared/links" %>
|
||||
@@ -45,6 +45,11 @@ class ControllerAuthenticatableTest < ActionController::TestCase
|
||||
@controller.authenticate_user!
|
||||
end
|
||||
|
||||
test 'proxy authenticate_user! options to authenticate with user scope' do
|
||||
@mock_warden.expects(:authenticate!).with(:scope => :user, :recall => "foo")
|
||||
@controller.authenticate_user!(:recall => "foo")
|
||||
end
|
||||
|
||||
test 'proxy authenticate_admin! to authenticate with admin scope' do
|
||||
@mock_warden.expects(:authenticate!).with(:scope => :admin)
|
||||
@controller.authenticate_admin!
|
||||
@@ -106,7 +111,7 @@ class ControllerAuthenticatableTest < ActionController::TestCase
|
||||
user = User.new
|
||||
@mock_warden.expects(:user).returns(user)
|
||||
@mock_warden.expects(:set_user).never
|
||||
@controller.sign_in(user)
|
||||
assert @controller.sign_in(user)
|
||||
end
|
||||
|
||||
test 'sign in again when the user is already in only if force is given' do
|
||||
@@ -123,6 +128,26 @@ class ControllerAuthenticatableTest < ActionController::TestCase
|
||||
@controller.sign_in(user, :bypass => true)
|
||||
end
|
||||
|
||||
test 'sign out clears up any signed in user from all scopes' do
|
||||
user = User.new
|
||||
@mock_warden.expects(:user).times(Devise.mappings.size)
|
||||
@mock_warden.expects(:logout).with().returns(true)
|
||||
@controller.instance_variable_set(:@current_user, user)
|
||||
@controller.instance_variable_set(:@current_admin, user)
|
||||
@controller.sign_out
|
||||
assert_equal nil, @controller.instance_variable_get(:@current_user)
|
||||
assert_equal nil, @controller.instance_variable_get(:@current_admin)
|
||||
end
|
||||
|
||||
test 'sign out clears up any signed in user by scope' do
|
||||
user = User.new
|
||||
@mock_warden.expects(:user).with(:user).returns(user)
|
||||
@mock_warden.expects(:logout).with(:user).returns(true)
|
||||
@controller.instance_variable_set(:@current_user, user)
|
||||
@controller.sign_out(:user)
|
||||
assert_equal nil, @controller.instance_variable_get(:@current_user)
|
||||
end
|
||||
|
||||
test 'sign out proxy to logout on warden' do
|
||||
@mock_warden.expects(:user).with(:user).returns(true)
|
||||
@mock_warden.expects(:logout).with(:user).returns(true)
|
||||
@@ -203,17 +228,6 @@ class ControllerAuthenticatableTest < ActionController::TestCase
|
||||
@controller.sign_in_and_redirect(admin)
|
||||
end
|
||||
|
||||
test 'redirect_location returns the stored location if set' do
|
||||
user = User.new
|
||||
@controller.session[:"user_return_to"] = "/foo.bar"
|
||||
assert_equal '/foo.bar', @controller.redirect_location('user', user)
|
||||
end
|
||||
|
||||
test 'redirect_location returns the after sign in path by default' do
|
||||
user = User.new
|
||||
assert_equal @controller.after_sign_in_path_for(:user), @controller.redirect_location('user', user)
|
||||
end
|
||||
|
||||
test 'sign out and redirect uses the configured after sign out path when signing out only the current scope' do
|
||||
swap Devise, :sign_out_all_scopes => false do
|
||||
@mock_warden.expects(:user).with(:admin).returns(true)
|
||||
|
||||
@@ -39,12 +39,27 @@ class HelpersTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
test 'require no authentication tests current mapping' do
|
||||
@mock_warden.expects(:authenticated?).with(:user).returns(true)
|
||||
@mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
|
||||
@mock_warden.expects(:user).with(:user).returns(User.new)
|
||||
@controller.expects(:redirect_to).with(root_path)
|
||||
@controller.send :require_no_authentication
|
||||
end
|
||||
|
||||
test 'require no authentication skips if no inputs are available' do
|
||||
Devise.mappings[:user].expects(:no_input_strategies).returns([])
|
||||
@mock_warden.expects(:authenticate?).never
|
||||
@controller.expects(:redirect_to).never
|
||||
@controller.send :require_no_authentication
|
||||
end
|
||||
|
||||
test 'require no authentication sets a flash message' do
|
||||
@mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
|
||||
@mock_warden.expects(:user).with(:user).returns(User.new)
|
||||
@controller.expects(:redirect_to).with(root_path)
|
||||
@controller.send :require_no_authentication
|
||||
assert flash[:alert] == I18n.t("devise.failure.already_authenticated")
|
||||
end
|
||||
|
||||
test 'signed in resource returns signed in resource for current scope' do
|
||||
@mock_warden.expects(:authenticate).with(:scope => :user).returns(User.new)
|
||||
assert_kind_of User, @controller.signed_in_resource
|
||||
@@ -69,4 +84,11 @@ class HelpersTest < ActionController::TestCase
|
||||
assert flash[:notice] == 'non-blank'
|
||||
MyController.send(:protected, :set_flash_message)
|
||||
end
|
||||
|
||||
test 'navigational_formats not returning a wild card' do
|
||||
MyController.send(:public, :navigational_formats)
|
||||
Devise.navigational_formats = [:"*/*", :html]
|
||||
assert_not @controller.navigational_formats.include?(:"*/*")
|
||||
MyController.send(:protected, :navigational_formats)
|
||||
end
|
||||
end
|
||||
|
||||
16
test/controllers/sessions_controller_test.rb
Normal file
16
test/controllers/sessions_controller_test.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require 'test_helper'
|
||||
|
||||
class SessionsControllerTest < ActionController::TestCase
|
||||
tests Devise::SessionsController
|
||||
include Devise::TestHelpers
|
||||
|
||||
test "#create doesn't raise exception after Warden authentication fails when TestHelpers included" do
|
||||
request.env["devise.mapping"] = Devise.mappings[:user]
|
||||
post :create, :user => {
|
||||
:email => "nosuchuser@example.com",
|
||||
:password => "wevdude"
|
||||
}
|
||||
assert_equal 200, @response.status
|
||||
assert_template "devise/sessions/new"
|
||||
end
|
||||
end
|
||||
@@ -25,7 +25,7 @@ class DeviseTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'stores warden configuration' do
|
||||
assert_equal Devise::FailureApp, Devise.warden_config.failure_app
|
||||
assert_kind_of Devise::Delegator, Devise.warden_config.failure_app
|
||||
assert_equal :user, Devise.warden_config.default_scope
|
||||
end
|
||||
|
||||
@@ -58,9 +58,6 @@ class DeviseTest < ActiveSupport::TestCase
|
||||
assert_equal :fruits, Devise::CONTROLLERS[:kivi]
|
||||
Devise::ALL.delete(:kivi)
|
||||
Devise::CONTROLLERS.delete(:kivi)
|
||||
|
||||
assert_nothing_raised(Exception) { Devise.add_module(:authenticatable_again, :model => 'devise/model/authenticatable') }
|
||||
assert defined?(Devise::Models::AuthenticatableAgain)
|
||||
end
|
||||
|
||||
test 'should complain when comparing empty or different sized passes' do
|
||||
|
||||
@@ -2,6 +2,10 @@ require 'test_helper'
|
||||
require 'ostruct'
|
||||
|
||||
class FailureTest < ActiveSupport::TestCase
|
||||
class RootFailureApp < Devise::FailureApp
|
||||
undef_method :new_user_session_path
|
||||
end
|
||||
|
||||
def self.context(name, &block)
|
||||
instance_eval(&block)
|
||||
end
|
||||
@@ -18,27 +22,31 @@ class FailureTest < ActiveSupport::TestCase
|
||||
'warden' => OpenStruct.new(:message => nil)
|
||||
}.merge!(env_params)
|
||||
|
||||
@response = Devise::FailureApp.call(env).to_a
|
||||
@response = (env.delete(:app) || Devise::FailureApp).call(env).to_a
|
||||
@request = ActionDispatch::Request.new(env)
|
||||
end
|
||||
|
||||
context 'When redirecting' do
|
||||
test 'return 302 status' do
|
||||
call_failure
|
||||
assert_equal 302, @response.first
|
||||
end
|
||||
|
||||
test 'return 302 status for wildcard requests' do
|
||||
call_failure 'action_dispatch.request.formats' => nil, 'HTTP_ACCEPT' => '*/*'
|
||||
assert_equal 302, @response.first
|
||||
end
|
||||
|
||||
test 'return to the default redirect location' do
|
||||
call_failure
|
||||
assert_equal 302, @response.first
|
||||
assert_equal 'You need to sign in or sign up before continuing.', @request.flash[:alert]
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second['Location']
|
||||
end
|
||||
|
||||
test 'return to the default redirect location for wildcard requests' do
|
||||
call_failure 'action_dispatch.request.formats' => nil, 'HTTP_ACCEPT' => '*/*'
|
||||
assert_equal 302, @response.first
|
||||
assert_equal 'http://test.host/users/sign_in', @response.second['Location']
|
||||
end
|
||||
|
||||
test 'return to the root path if no session path is available' do
|
||||
call_failure :app => RootFailureApp
|
||||
assert_equal 302, @response.first
|
||||
assert_equal 'You need to sign in or sign up before continuing.', @request.flash[:alert]
|
||||
assert_equal 'http://test.host/', @response.second['Location']
|
||||
end
|
||||
|
||||
test 'uses the proxy failure message as symbol' do
|
||||
call_failure('warden' => OpenStruct.new(:message => :test))
|
||||
assert_equal 'test', @request.flash[:alert]
|
||||
@@ -69,7 +77,7 @@ class FailureTest < ActiveSupport::TestCase
|
||||
assert_equal 302, @response.first
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test 'redirects the correct format if it is a non-html format request' do
|
||||
swap Devise, :navigational_formats => [:js] do
|
||||
call_failure('formats' => :js)
|
||||
@@ -84,6 +92,18 @@ class FailureTest < ActiveSupport::TestCase
|
||||
assert_equal 401, @response.first
|
||||
end
|
||||
|
||||
test 'return appropriate body for xml' do
|
||||
call_failure('formats' => :xml)
|
||||
result = %(<?xml version="1.0" encoding="UTF-8"?>\n<errors>\n <error>You need to sign in or sign up before continuing.</error>\n</errors>\n)
|
||||
assert_equal result, @response.last.body
|
||||
end
|
||||
|
||||
test 'return appropriate body for json' do
|
||||
call_failure('formats' => :json)
|
||||
result = %({"error":"You need to sign in or sign up before continuing."})
|
||||
assert_equal result, @response.last.body
|
||||
end
|
||||
|
||||
test 'return 401 status for unknown formats' do
|
||||
call_failure 'formats' => []
|
||||
assert_equal 401, @response.first
|
||||
@@ -161,7 +181,7 @@ class FailureTest < ActiveSupport::TestCase
|
||||
assert @response.third.body.include?('<h2>Sign in</h2>')
|
||||
assert @response.third.body.include?('Invalid email or password.')
|
||||
end
|
||||
|
||||
|
||||
test 'calls the original controller if not confirmed email' do
|
||||
env = {
|
||||
"warden.options" => { :recall => "devise/sessions#new", :attempted_path => "/users/sign_in", :message => :unconfirmed },
|
||||
@@ -170,9 +190,9 @@ class FailureTest < ActiveSupport::TestCase
|
||||
}
|
||||
call_failure(env)
|
||||
assert @response.third.body.include?('<h2>Sign in</h2>')
|
||||
assert @response.third.body.include?('You have to confirm your account before continuing.')
|
||||
assert @response.third.body.include?('You have to confirm your account before continuing.')
|
||||
end
|
||||
|
||||
|
||||
test 'calls the original controller if inactive account' do
|
||||
env = {
|
||||
"warden.options" => { :recall => "devise/sessions#new", :attempted_path => "/users/sign_in", :message => :inactive },
|
||||
@@ -181,7 +201,7 @@ class FailureTest < ActiveSupport::TestCase
|
||||
}
|
||||
call_failure(env)
|
||||
assert @response.third.body.include?('<h2>Sign in</h2>')
|
||||
assert @response.third.body.include?('Your account was not activated yet.')
|
||||
assert @response.third.body.include?('Your account was not activated yet.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,15 +7,38 @@ if DEVISE_ORM == :active_record
|
||||
tests ActiveRecord::Generators::DeviseGenerator
|
||||
destination File.expand_path("../../tmp", __FILE__)
|
||||
setup :prepare_destination
|
||||
|
||||
|
||||
test "all files are properly created" do
|
||||
run_generator %w(monster)
|
||||
assert_file "app/models/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
|
||||
assert_migration "db/migrate/devise_create_monsters.rb"
|
||||
with_rails_version :MAJOR => 3, :MINOR => 0 do
|
||||
run_generator %w(monster)
|
||||
assert_file "app/models/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
|
||||
assert_migration "db/migrate/devise_create_monsters.rb", /def self\.up/
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
test "all files are properly created with rails31 migration syntax" do
|
||||
with_rails_version :MAJOR => 3, :MINOR => 1 do
|
||||
run_generator %w(monster)
|
||||
assert_file "app/models/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
|
||||
assert_migration "db/migrate/devise_create_monsters.rb", /def change/
|
||||
end
|
||||
end
|
||||
|
||||
test "update model migration when model exists" do
|
||||
run_generator %w(monster)
|
||||
assert_file "app/models/monster.rb"
|
||||
run_generator %w(monster)
|
||||
assert_migration "db/migrate/add_devise_to_monsters.rb"
|
||||
end
|
||||
|
||||
test "all files are properly deleted" do
|
||||
run_generator %w(monster)
|
||||
run_generator %w(monster)
|
||||
assert_migration "db/migrate/devise_create_monsters.rb"
|
||||
assert_migration "db/migrate/add_devise_to_monsters.rb"
|
||||
run_generator %w(monster), :behavior => :revoke
|
||||
assert_no_migration "db/migrate/add_devise_to_monsters.rb"
|
||||
assert_migration "db/migrate/devise_create_monsters.rb"
|
||||
run_generator %w(monster), :behavior => :revoke
|
||||
assert_no_file "app/models/monster.rb"
|
||||
assert_no_migration "db/migrate/devise_create_monsters.rb"
|
||||
|
||||
@@ -22,6 +22,12 @@ class DeviseGeneratorTest < Rails::Generators::TestCase
|
||||
assert_file "config/routes.rb", match
|
||||
end
|
||||
|
||||
test "route generation with skip routes" do
|
||||
run_generator %w(monster name:string --skip-routes)
|
||||
match = /devise_for :monsters, :skip => :all/
|
||||
assert_file "config/routes.rb", match
|
||||
end
|
||||
|
||||
def copy_routes
|
||||
routes = File.expand_path("../../rails_app/config/routes.rb", __FILE__)
|
||||
destination = File.join(destination_root, "config")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
if DEVISE_ORM == :mongo_id
|
||||
require "generators/mongo_id/devise_generator"
|
||||
if DEVISE_ORM == :mongoid
|
||||
require "generators/mongoid/devise_generator"
|
||||
|
||||
class MongoidGeneratorTest < Rails::Generators::TestCase
|
||||
tests Mongoid::Generators::DeviseGenerator
|
||||
@@ -19,4 +19,5 @@ if DEVISE_ORM == :mongo_id
|
||||
assert_no_file "app/models/monster.rb"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -18,12 +18,29 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
|
||||
assert_files "admins"
|
||||
end
|
||||
|
||||
def assert_files(scope = nil, template_engine = nil)
|
||||
test "Assert views with simple form" do
|
||||
run_generator %w(-b simple_form_for)
|
||||
assert_files
|
||||
assert_file "app/views/devise/confirmations/new.html.erb", /simple_form_for/
|
||||
|
||||
run_generator %w(users -b simple_form_for)
|
||||
assert_files "users"
|
||||
assert_file "app/views/users/confirmations/new.html.erb", /simple_form_for/
|
||||
end
|
||||
|
||||
test "Assert views with markerb" do
|
||||
run_generator %w(--markerb)
|
||||
assert_files nil, :mail_template_engine => "markerb"
|
||||
end
|
||||
|
||||
def assert_files(scope = nil, options={})
|
||||
scope = "devise" if scope.nil?
|
||||
mail_template_engine = options[:mail_template_engine] || "html.erb"
|
||||
|
||||
assert_file "app/views/#{scope}/confirmations/new.html.erb"
|
||||
assert_file "app/views/#{scope}/mailer/confirmation_instructions.html.erb"
|
||||
assert_file "app/views/#{scope}/mailer/reset_password_instructions.html.erb"
|
||||
assert_file "app/views/#{scope}/mailer/unlock_instructions.html.erb"
|
||||
assert_file "app/views/#{scope}/mailer/confirmation_instructions.#{mail_template_engine}"
|
||||
assert_file "app/views/#{scope}/mailer/reset_password_instructions.#{mail_template_engine}"
|
||||
assert_file "app/views/#{scope}/mailer/unlock_instructions.#{mail_template_engine}"
|
||||
assert_file "app/views/#{scope}/passwords/edit.html.erb"
|
||||
assert_file "app/views/#{scope}/passwords/new.html.erb"
|
||||
assert_file "app/views/#{scope}/registrations/new.html.erb"
|
||||
|
||||
51
test/helpers/devise_helper_test.rb
Normal file
51
test/helpers/devise_helper_test.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
require 'test_helper'
|
||||
|
||||
class DeviseHelperTest < ActionController::IntegrationTest
|
||||
setup do
|
||||
model_labels = { :models => { :user => "utilisateur" } }
|
||||
|
||||
I18n.backend.store_translations :fr,
|
||||
{
|
||||
:errors => { :messages => { :not_saved => {
|
||||
:one => "Erreur lors de l'enregistrement de '%{resource}': 1 erreur.",
|
||||
:other => "Erreur lors de l'enregistrement de '%{resource}': %{count} erreurs."
|
||||
} } },
|
||||
:activerecord => model_labels,
|
||||
:mongoid => model_labels
|
||||
}
|
||||
|
||||
I18n.locale = 'fr'
|
||||
end
|
||||
|
||||
teardown do
|
||||
I18n.locale = 'en'
|
||||
end
|
||||
|
||||
test 'test errors.messages.not_saved with single error from i18n' do
|
||||
get new_user_registration_path
|
||||
|
||||
fill_in 'password', :with => 'new_user123'
|
||||
fill_in 'password confirmation', :with => 'new_user123'
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain "Erreur lors de l'enregistrement de 'utilisateur': 1 erreur"
|
||||
end
|
||||
|
||||
test 'test errors.messages.not_saved with multiple errors from i18n' do
|
||||
# Dirty tracking behavior prevents email validations from being applied:
|
||||
# https://github.com/mongoid/mongoid/issues/756
|
||||
(pending "Fails on Mongoid < 2.1"; break) if defined?(Mongoid) && Mongoid::VERSION.to_f < 2.1
|
||||
|
||||
get new_user_registration_path
|
||||
|
||||
fill_in 'email', :with => 'invalid_email'
|
||||
fill_in 'password', :with => 'new_user123'
|
||||
fill_in 'password confirmation', :with => 'new_user321'
|
||||
click_button 'Sign up'
|
||||
|
||||
assert_have_selector '#error_explanation'
|
||||
assert_contain "Erreur lors de l'enregistrement de 'utilisateur': 2 erreurs"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -101,6 +101,54 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
assert_contain 'Private!'
|
||||
end
|
||||
|
||||
test 'signed in as admin should get admin dashboard' do
|
||||
sign_in_as_admin
|
||||
assert warden.authenticated?(:admin)
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
get dashboard_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'home/admin'
|
||||
assert_contain 'Admin dashboard'
|
||||
end
|
||||
|
||||
test 'signed in as user should get user dashboard' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
|
||||
get dashboard_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'home/user'
|
||||
assert_contain 'User dashboard'
|
||||
end
|
||||
|
||||
test 'not signed in should get no dashboard' do
|
||||
assert_raises ActionController::RoutingError do
|
||||
get dashboard_path
|
||||
end
|
||||
end
|
||||
|
||||
test 'signed in user should not see unauthenticated page' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
|
||||
assert_raises ActionController::RoutingError do
|
||||
get join_path
|
||||
end
|
||||
end
|
||||
|
||||
test 'not signed in users should see unautheticated page' do
|
||||
get join_path
|
||||
|
||||
assert_response :success
|
||||
assert_template 'home/join'
|
||||
assert_contain 'Join'
|
||||
end
|
||||
|
||||
test 'signed in as user should not be able to access admins actions' do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
@@ -152,6 +200,12 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
|
||||
get root_path
|
||||
assert_not_contain 'Signed out successfully'
|
||||
end
|
||||
|
||||
test 'scope uses custom failure app' do
|
||||
put "/en/accounts/management"
|
||||
assert_equal "Oops, not found", response.body
|
||||
assert_equal 404, response.status
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationRedirectTest < ActionController::IntegrationTest
|
||||
@@ -205,17 +259,16 @@ class AuthenticationRedirectTest < ActionController::IntegrationTest
|
||||
assert_nil session[:"user_return_to"]
|
||||
end
|
||||
|
||||
test 'sign in with xml format returns xml response' do
|
||||
create_user
|
||||
post user_session_path(:format => 'xml', :user => {:email => "user@test.com", :password => '123456'})
|
||||
assert_response :success
|
||||
assert_match /<\?xml version="1.0" encoding="UTF-8"\?>/, response.body
|
||||
end
|
||||
|
||||
test 'redirect to configured home path for a given scope after sign in' do
|
||||
sign_in_as_admin
|
||||
assert_equal "/admin_area/home", @request.path
|
||||
end
|
||||
|
||||
test 'require_no_authentication should set the already_authenticated flash message' do
|
||||
sign_in_as_user
|
||||
visit new_user_session_path
|
||||
assert_equal flash[:alert], I18n.t("devise.failure.already_authenticated")
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationSessionTest < ActionController::IntegrationTest
|
||||
@@ -265,7 +318,7 @@ class AuthenticationSessionTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationWithScopesTest < ActionController::IntegrationTest
|
||||
class AuthenticationWithScopedViewsTest < ActionController::IntegrationTest
|
||||
test 'renders the scoped view if turned on and view is available' do
|
||||
swap Devise, :scoped_views => true do
|
||||
assert_raise Webrat::NotFoundError do
|
||||
@@ -307,6 +360,20 @@ class AuthenticationWithScopesTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
class AuthenticationOthersTest < ActionController::IntegrationTest
|
||||
test 'handles unverified requests gets rid of caches' do
|
||||
swap UsersController, :allow_forgery_protection => true do
|
||||
post exhibit_user_url(1)
|
||||
assert_not warden.authenticated?(:user)
|
||||
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
|
||||
post exhibit_user_url(1)
|
||||
assert_not warden.authenticated?(:user)
|
||||
assert_equal "User is not authenticated", response.body
|
||||
end
|
||||
end
|
||||
|
||||
test 'uses the custom controller with the custom controller view' do
|
||||
get '/admin_area/sign_in'
|
||||
assert_contain 'Sign in'
|
||||
@@ -315,8 +382,9 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
test 'render 404 on roles without routes' do
|
||||
get '/admin_area/password/new'
|
||||
assert_equal 404, response.status
|
||||
assert_raise ActionController::RoutingError do
|
||||
get '/admin_area/password/new'
|
||||
end
|
||||
end
|
||||
|
||||
test 'does not intercept Rails 401 responses' do
|
||||
@@ -337,9 +405,24 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
test 'registration in xml format works when recognizing path' do
|
||||
assert_nothing_raised do
|
||||
post user_registration_path(:format => 'xml', :user => {:email => "test@example.com", :password => "invalid"} )
|
||||
test 'sign in stub in xml format' do
|
||||
get new_user_session_path(:format => 'xml')
|
||||
assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>\n <email></email>\n <password nil=\"true\"></password>\n</user>\n", response.body
|
||||
end
|
||||
|
||||
test 'sign in stub in json format' do
|
||||
get new_user_session_path(:format => 'json')
|
||||
assert_match '{"user":{', response.body
|
||||
assert_match '"email":""', response.body
|
||||
assert_match '"password":null', response.body
|
||||
end
|
||||
|
||||
test 'sign in stub in json with non attribute key' do
|
||||
swap Devise, :authentication_keys => [:other_key] do
|
||||
get new_user_session_path(:format => 'json')
|
||||
assert_match '{"user":{', response.body
|
||||
assert_match '"other_key":null', response.body
|
||||
assert_match '"password":null', response.body
|
||||
end
|
||||
end
|
||||
|
||||
@@ -354,6 +437,60 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
|
||||
assert warden.authenticated?(:user)
|
||||
assert_not warden.authenticated?(:admin)
|
||||
end
|
||||
|
||||
test 'sign in with xml format returns xml response' do
|
||||
create_user
|
||||
post user_session_path(:format => 'xml'), :user => {:email => "user@test.com", :password => '123456'}
|
||||
assert_response :success
|
||||
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
|
||||
end
|
||||
|
||||
test 'sign in with xml format is idempotent' do
|
||||
get new_user_session_path(:format => 'xml')
|
||||
assert_response :success
|
||||
|
||||
create_user
|
||||
post user_session_path(:format => 'xml'), :user => {:email => "user@test.com", :password => '123456'}
|
||||
assert_response :success
|
||||
|
||||
get new_user_session_path(:format => 'xml')
|
||||
assert_response :success
|
||||
|
||||
post user_session_path(:format => 'xml'), :user => {:email => "user@test.com", :password => '123456'}
|
||||
assert_response :success
|
||||
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
|
||||
end
|
||||
|
||||
test 'sign out with xml format returns ok response' do
|
||||
sign_in_as_user
|
||||
get destroy_user_session_path(:format => 'xml')
|
||||
assert_response :ok
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'sign out with json format returns empty json response' do
|
||||
sign_in_as_user
|
||||
get destroy_user_session_path(:format => 'json')
|
||||
assert_response :ok
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationKeysTest < ActionController::IntegrationTest
|
||||
test 'missing authentication keys cause authentication to abort' do
|
||||
swap Devise, :authentication_keys => [:subdomain] do
|
||||
sign_in_as_user
|
||||
assert_contain "Invalid email or password."
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'missing authentication keys cause authentication to abort unless marked as not required' do
|
||||
swap Devise, :authentication_keys => { :email => true, :subdomain => false } do
|
||||
sign_in_as_user
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AuthenticationRequestKeysTest < ActionController::IntegrationTest
|
||||
@@ -411,7 +548,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
|
||||
|
||||
test 'do not allow sign out via get when sign_out_via provides only delete' do
|
||||
sign_in!(:sign_out_via_delete)
|
||||
get destroy_sign_out_via_delete_session_path
|
||||
assert_raise ActionController::RoutingError do
|
||||
get destroy_sign_out_via_delete_session_path
|
||||
end
|
||||
assert warden.authenticated?(:sign_out_via_delete)
|
||||
end
|
||||
|
||||
@@ -423,7 +562,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
|
||||
|
||||
test 'do not allow sign out via get when sign_out_via provides only post' do
|
||||
sign_in!(:sign_out_via_post)
|
||||
get destroy_sign_out_via_delete_session_path
|
||||
assert_raise ActionController::RoutingError do
|
||||
get destroy_sign_out_via_delete_session_path
|
||||
end
|
||||
assert warden.authenticated?(:sign_out_via_post)
|
||||
end
|
||||
|
||||
@@ -441,7 +582,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
|
||||
|
||||
test 'do not allow sign out via get when sign_out_via provides delete and post' do
|
||||
sign_in!(:sign_out_via_delete_or_post)
|
||||
get destroy_sign_out_via_delete_or_post_session_path
|
||||
assert_raise ActionController::RoutingError do
|
||||
get destroy_sign_out_via_delete_or_post_session_path
|
||||
end
|
||||
assert warden.authenticated?(:sign_out_via_delete_or_post)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
visit user_confirmation_path(:confirmation_token => confirmation_token)
|
||||
end
|
||||
|
||||
test 'user should be able to request a new confirmation' do
|
||||
def resend_confirmation
|
||||
user = create_user(:confirm => false)
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
@@ -15,10 +15,23 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend confirmation instructions'
|
||||
end
|
||||
|
||||
test 'user should be able to request a new confirmation' do
|
||||
resend_confirmation
|
||||
|
||||
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
|
||||
assert_equal ['please-change-me@config-initializers-devise.com'], ActionMailer::Base.deliveries.first.from
|
||||
end
|
||||
|
||||
test 'user should receive a confirmation from a custom mailer' do
|
||||
User.any_instance.stubs(:devise_mailer).returns(Users::Mailer)
|
||||
|
||||
resend_confirmation
|
||||
|
||||
assert_equal ['custom@example.com'], ActionMailer::Base.deliveries.first.from
|
||||
end
|
||||
|
||||
test 'user with invalid confirmation token should not be able to confirm an account' do
|
||||
@@ -37,6 +50,15 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
assert user.reload.confirmed?
|
||||
end
|
||||
|
||||
test 'user should be redirected to a custom path after confirmation' do
|
||||
Devise::ConfirmationsController.any_instance.stubs(:after_confirmation_path_for).returns("/?custom=1")
|
||||
|
||||
user = create_user(:confirm => false)
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
assert_current_url "/?custom=1"
|
||||
end
|
||||
|
||||
test 'already confirmed user should not be able to confirm the account again' do
|
||||
user = create_user(:confirm => false)
|
||||
user.confirmed_at = Time.now
|
||||
@@ -60,7 +82,7 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
assert_contain 'already confirmed'
|
||||
end
|
||||
|
||||
test 'sign in user automatically after confirming it\'s email' do
|
||||
test 'sign in user automatically after confirming its email' do
|
||||
user = create_user(:confirm => false)
|
||||
visit_user_confirmation_with_token(user.confirmation_token)
|
||||
|
||||
@@ -84,6 +106,17 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
test 'not confirmed user should not see confirmation message if invalid credentials are given' do
|
||||
swap Devise, :confirm_within => 0.days do
|
||||
sign_in_as_user(:confirm => false) do
|
||||
fill_in 'password', :with => 'invalid'
|
||||
end
|
||||
|
||||
assert_contain 'Invalid email or password'
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'not confirmed user but configured with some days to confirm should be able to sign in' do
|
||||
swap Devise, :confirm_within => 1.day do
|
||||
sign_in_as_user(:confirm => false)
|
||||
@@ -101,4 +134,70 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
assert_contain 'Not confirmed user'
|
||||
end
|
||||
end
|
||||
|
||||
test 'resent confirmation token with valid E-Mail in XML format should return valid response' do
|
||||
user = create_user(:confirm => false)
|
||||
post user_confirmation_path(:format => 'xml'), :user => { :email => user.email }
|
||||
assert_response :success
|
||||
assert_equal response.body, {}.to_xml
|
||||
end
|
||||
|
||||
test 'resent confirmation token with invalid E-Mail in XML format should return invalid response' do
|
||||
user = create_user(:confirm => false)
|
||||
post user_confirmation_path(:format => 'xml'), :user => { :email => 'invalid.test@test.com' }
|
||||
assert_response :unprocessable_entity
|
||||
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<errors>)
|
||||
end
|
||||
|
||||
test 'confirm account with valid confirmation token in XML format should return valid response' do
|
||||
user = create_user(:confirm => false)
|
||||
get user_confirmation_path(:confirmation_token => user.confirmation_token, :format => 'xml')
|
||||
assert_response :success
|
||||
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
|
||||
end
|
||||
|
||||
test 'confirm account with invalid confirmation token in XML format should return invalid response' do
|
||||
user = create_user(:confirm => false)
|
||||
get user_confirmation_path(:confirmation_token => 'invalid_confirmation', :format => 'xml')
|
||||
assert_response :unprocessable_entity
|
||||
assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<errors>)
|
||||
end
|
||||
|
||||
test 'request an account confirmation account with JSON, should return an empty JSON' do
|
||||
user = create_user(:confirm => false)
|
||||
|
||||
post user_confirmation_path, :user => { :email => user.email }, :format => :json
|
||||
assert_response :success
|
||||
assert_equal response.body, {}.to_json
|
||||
end
|
||||
|
||||
test "when in paranoid mode and with a valid e-mail, should not say that the e-mail is valid" do
|
||||
swap Devise, :paranoid => true do
|
||||
user = create_user(:confirm => false)
|
||||
visit new_user_session_path
|
||||
|
||||
click_link "Didn't receive confirmation instructions?"
|
||||
fill_in 'email', :with => user.email
|
||||
click_button 'Resend confirmation instructions'
|
||||
|
||||
assert_contain "If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes."
|
||||
assert_current_url "/users/sign_in"
|
||||
end
|
||||
end
|
||||
|
||||
test "when in paranoid mode and with a invalid e-mail, should not say that the e-mail is invalid" do
|
||||
swap Devise, :paranoid => true do
|
||||
visit new_user_session_path
|
||||
|
||||
click_link "Didn't receive confirmation instructions?"
|
||||
fill_in 'email', :with => "idonthavethisemail@gmail.com"
|
||||
click_button 'Resend confirmation instructions'
|
||||
|
||||
assert_not_contain "1 error prohibited this user from being saved:"
|
||||
assert_not_contain "Email not found"
|
||||
|
||||
assert_contain "If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes."
|
||||
assert_current_url "/users/sign_in"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,6 +22,28 @@ class DatabaseAuthenticationTest < ActionController::IntegrationTest
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'sign in with email including extra spaces should succeed when email is in the list of strip whitespace keys' do
|
||||
create_user(:email => ' foo@bar.com ')
|
||||
|
||||
sign_in_as_user do
|
||||
fill_in 'email', :with => 'foo@bar.com'
|
||||
end
|
||||
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'sign in with email including extra spaces should fail when email is NOT the list of strip whitespace keys' do
|
||||
swap Devise, :strip_whitespace_keys => [] do
|
||||
create_user(:email => 'foo@bar.com')
|
||||
|
||||
sign_in_as_user do
|
||||
fill_in 'email', :with => ' foo@bar.com '
|
||||
end
|
||||
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
end
|
||||
|
||||
test 'sign in should not authenticate if not using proper authentication keys' do
|
||||
swap Devise, :authentication_keys => [:username] do
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user