Compare commits

...

76 Commits

Author SHA1 Message Date
Rodrigo Flores
91ba14e77e Bumping to 2.1.0.rc 2012-03-15 11:16:11 -03:00
José Valim
2cab75d72b Merge pull request #1719 from hakanensari/mounted-app-redirect
Fix redirect when authenticating mounted apps
2012-03-15 00:15:02 -07:00
Hakan Ensari
b37a74533d Fix redirect when authenticating mounted apps 2012-03-15 02:41:29 +00:00
Rodrigo Flores
939d0f25c5 Merge pull request #1716 from plataformatec/validate_symbol
Validate is now a boolean function and unautheticated_symbol returns the symbol
2012-03-13 12:07:13 -07:00
Rodrigo Flores
61929d2e2f Fixing lockable to use the correct method 2012-03-13 15:53:57 -03:00
Rodrigo Flores
a7658f9d75 Checking required fields on lockable 2012-03-13 15:50:13 -03:00
Rodrigo Flores
033e91b7b9 Adding symbols only on validate 2012-03-13 14:24:21 -03:00
José Valim
68de34c03e Move valid_password? up to database authenticatable. 2012-03-10 11:10:57 +01:00
José Valim
94c05e346d Merge pull request #1709 from plataformatec/extracting_bcrypt
Moved BCrypt logic to a Encryptor
2012-03-09 14:26:20 -08:00
Rodrigo Flores
45298c0a37 Fixing some arguments order 2012-03-09 19:19:20 -03:00
Rodrigo Flores
c12fc1afea The signature must be the same 2012-03-09 18:37:37 -03:00
Rodrigo Flores
136b5b0be9 Added compare to encryptors 2012-03-09 17:19:36 -03:00
Rodrigo Flores
9203651110 Moved BCrypt logic to a encryptor 2012-03-09 16:38:06 -03:00
José Valim
a394ceaef1 Update CHANGELOG. 2012-03-09 18:12:43 +01:00
José Valim
0ab28ef8ee Add skip_reconfirmation! , closes #1708 2012-03-09 18:12:30 +01:00
Rodrigo Flores
b928b8b3a2 Merge pull request #1700 from strzalek/patch-1
Fix formatting in README
2012-03-05 08:19:02 -08:00
Łukasz Strzałkowski
075fc96f10 Fix formatting in README 2012-03-05 17:01:46 +01:00
Rodrigo Flores
15f6255c7c Update CHANGELOG.rdoc 2012-03-03 16:41:24 -03:00
Rodrigo Flores
2b79519ad1 Changelog 2012-03-03 15:25:07 -03:00
Rodrigo Flores
617a8876a6 Merge branch 'deprecating-ausence-of-required-fields' 2012-03-03 15:16:07 -03:00
Rodrigo Flores
7b7af57813 Minor fixes on models_test 2012-03-03 15:10:17 -03:00
Rodrigo Flores
a12f6ec70c Failure is better than exceptions 2012-03-03 14:49:59 -03:00
Rodrigo Flores
fffc3b1e0e Moved a method to support 2012-03-03 14:41:22 -03:00
Rodrigo Flores
af12ec2b01 Fixing a deprecation warning 2012-03-03 14:32:53 -03:00
Rodrigo Flores
ecfc7d752a Deprecation warning on module doesn't have a required_fields method 2012-03-03 14:30:59 -03:00
Rodrigo Flores
bc096994b0 Merge pull request #1696 from plataformatec/reverting
Adding back links partial to shared
2012-03-03 07:05:04 -08:00
Rodrigo Flores
ba80074b7b Added a missing hide! 2012-03-03 11:32:58 -03:00
Rodrigo Flores
f04d883ac1 Deprecation warning 2012-03-03 11:12:30 -03:00
Rodrigo Flores
9bf718dd82 Revert "Move devise/shared/_links.erb to devise/_links.erb"
This reverts commit aa2d15aa33.

Conflicts:

	CHANGELOG.rdoc
2012-03-03 10:40:59 -03:00
Rodrigo Flores
643d5600b2 Changelog adjustments 2012-03-03 08:41:23 -03:00
Rodrigo Flores
1edae9c6c1 Changelog update 2012-03-03 08:39:24 -03:00
José Valim
b41e5f5bf6 Update CHANGELOG 2012-03-03 12:11:40 +01:00
José Valim
2f6ecc1328 Do not call after sign in hook without resource, closes #1666. 2012-03-03 12:09:26 +01:00
José Valim
b93288875f Update lib/devise/rails/routes.rb 2012-03-03 11:16:21 +01:00
Rodrigo Flores
bb4f699d03 Fixing two tests 2012-03-03 01:25:17 -03:00
Rodrigo Flores
f1d991fa8b Merge pull request #1681 from abevoelker/change-omniauth-flash-wording
Change OmniAuth flash wording (authorize->authenticate)
2012-03-02 20:16:54 -08:00
Rodrigo Flores
4ce7854f44 Changelog 2012-02-25 10:38:40 -02:00
Rodrigo Flores
5ef35ee1bd Adding required_fields to all modules 2012-02-24 20:57:58 -02:00
Rodrigo Flores
6d5bccc050 Added required fields to validatable 2012-02-24 20:57:58 -02:00
Abe Voelker
3ac2c1dd18 Change OmniAuth flash wording (authorize->authenticate) 2012-02-24 14:35:43 -06:00
Carlos Antonio da Silva
07a41ecf6f Merge pull request #1679 from codeodor/patch-1
Include note about restarting the rails app if it's already running
2012-02-23 15:57:44 -08:00
Sammy Larbi
61e85a578e Include note about restarting the rails app if it's already running, because the last 2 apps I used Devise with, I could not figure out why I was getting very strange errors, and finally today I figured out it was due to the fact that it needed to reload. 2012-02-23 17:37:13 -06:00
José Valim
88d68587e1 Update lib/devise/controllers/helpers.rb 2012-02-23 21:06:39 +01:00
Rodrigo Flores
23ae04e6cb Merge pull request #1675 from plataformatec/fix_assertion
Fix the assert_same_content assertion helper
2012-02-22 10:51:05 -08:00
Lucas Mazza
64c05f2ce9 Fix the assert_same_content assertion helper
and a broken confirmable test.
2012-02-22 16:49:09 -02:00
José Valim
c5cb60a752 Merge pull request #1673 from plataformatec/check_attributes_rebased
Check attributes on models
2012-02-22 08:07:16 -08:00
Rodrigo Flores
803e4f5524 Changed message and refactored exception to use a initializer 2012-02-22 13:55:06 -02:00
Rodrigo Flores
a909bfaf85 Added required_fields when reconfirmable 2012-02-22 13:55:06 -02:00
Rodrigo Flores
bc11e9f300 One exception to rule them all 2012-02-22 13:55:05 -02:00
Rodrigo Flores
e3412d4207 No need to sort anymore 2012-02-22 13:55:05 -02:00
Rodrigo Flores
faf8b01ecc Fixing some tests and adding an assert message 2012-02-22 13:55:05 -02:00
Rodrigo Flores
d7337c5b26 Added a missing test and asserting same content for 1.8 compatibility 2012-02-22 13:55:05 -02:00
Rodrigo Flores
2ab1086b80 Test, you shall pass! 2012-02-22 13:55:05 -02:00
Rodrigo Flores
85f2f88c59 Added required fields to lockable 2012-02-22 13:55:05 -02:00
Rodrigo Flores
ce3422e75a Added required_fields to recoverable 2012-02-22 13:55:04 -02:00
Rodrigo Flores
bee87843b4 Added required_fields to rememberable 2012-02-22 13:55:04 -02:00
Rodrigo Flores
18aef6ac33 Some refactor 2012-02-22 13:55:03 -02:00
Rodrigo Flores
890f6031c3 Required fields on trackable 2012-02-22 13:55:03 -02:00
Rodrigo Flores
f3bace570d Required fields on token_authenticatable 2012-02-22 13:55:02 -02:00
Rodrigo Flores
533511f8c3 Required fields on encryptable 2012-02-22 13:55:02 -02:00
Rodrigo Flores
6489354b0e Required fields on confirmable 2012-02-22 13:55:02 -02:00
Rodrigo Flores
1bbae013cc ✂️ whitespaces 2012-02-22 13:55:02 -02:00
Rodrigo Flores
8ac8129fe7 Added required_fields to database_authenticatable 2012-02-22 13:55:01 -02:00
Rodrigo Flores
9667a38bc9 Added check_model! method 2012-02-22 13:55:01 -02:00
José Valim
e3df7f033e Update .travis.yml 2012-02-21 08:47:28 +01:00
José Valim
989fd92b84 Merge pull request #1672 from RogerE/rememberable_options-in-initializer
Use rememberable_options instead of deprecated cookie_options in initializer
2012-02-20 23:10:57 -08:00
RogerE
de24170a79 Use rememberable_options instead of deprecated cookie_options in initializer 2012-02-21 08:01:17 +01:00
José Valim
5a0548621f Remove deprecated examples from README, closes #1669. 2012-02-20 18:53:45 +01:00
Rafael Mendonça França
0f8e472dab Update CHANGELOG.rdoc 2012-02-18 14:24:49 -02:00
George Guimarães
b190fa38c7 typo 2012-02-17 19:15:46 -02:00
José Valim
b0b01dae81 Update CHANGELOG. 2012-02-17 12:51:00 +01:00
José Valim
f2b4ba6110 Release 2.0.4 2012-02-17 12:46:31 +01:00
José Valim
d15d0ba6a5 Update CHANGELOG. 2012-02-17 12:46:31 +01:00
José Valim
fc3af50b55 Fix regression where warden was being configured too early. 2012-02-17 12:46:31 +01:00
José Valim
a0a141b457 Merge pull request #1661 from mreinsch/fix_subdomain_routing
fix for when using :host in routes
2012-02-17 02:31:14 -08:00
Michael Reinsch
0315ca2701 fix for :host getting overwritten in scope[:options] and thus not generating URLs with correct hostnames 2012-02-17 19:14:42 +09:00
65 changed files with 535 additions and 123 deletions

View File

@@ -1,5 +1,4 @@
script: "bundle exec rake test"
before_install: gem update --system
rvm:
- 1.8.7
- 1.9.2

View File

@@ -1,4 +1,25 @@
== 2.0.3
== 2.1.0.dev
* enhancements
* Add check_fields! method on Devise::Models to check if the model includes the fields that Devise uses
* Add `skip_reconfirmation!` to skip reconfirmation
* bug fix
* Ensure after sign in hook is not called without a resource
* Fix a term: now on Omniauth related flash messages, we say that we're authenticating from an omniauth provider instead of authorizing
* deprecation
* All devise modules should have a required_fields(klass) module method to help gathering missing attributes
== 2.0.4
Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
* bug fix
* Fix when :host is used with devise_for (by @mreinsch)
* Fix a regression that caused Warden to be initialized too late
== 2.0.3 (yanked)
* bug fix
* Ensure warning is not shown by mistake on apps with mounted engines
@@ -8,8 +29,6 @@
== 2.0.2
Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
* enhancements
* Add devise_i18n_options to customize I18n message
@@ -114,7 +133,7 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* bug fix
* Fix backward incompatible change from 1.4.6 for those using custom controllers
== 1.4.6
== 1.4.6 (yanked)
* enhancements
* Allow devise_for :skip => :all

View File

@@ -1,7 +1,7 @@
PATH
remote: .
specs:
devise (2.0.2)
devise (2.0.4)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.3)
railties (~> 3.1)

View File

@@ -1,4 +1,4 @@
*IMPORTANT:* Devise 2.0.0 is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
*IMPORTANT:* Devise 2.0 is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
## Devise
@@ -109,6 +109,8 @@ rails generate devise MODEL
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 "rake 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 to point to Devise controller.
Note that you should re-start your app here if you've already started it. Otherwise you'll run into strange errors like users being unable to login and the route helpers being undefined.
### Controller filters and helpers
Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_filter:
@@ -135,13 +137,13 @@ You can access the session for this scope:
user_session
```
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:
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:
```ruby
root :to => "home#index"
```
You can also overwrite +after_sign_in_path_for+ and +after_sign_out_path_for+ to customize your redirect hooks.
You can also overwrite `after_sign_in_path_for` and `after_sign_out_path_for` to customize your redirect hooks.
Finally, you need to set up default url options for the mailer in each environment. Here is the configuration for "config/environments/development.rb":
@@ -247,9 +249,9 @@ Devise also ships with default routes. If you need to customize them, you should
devise_for :users, :path => "usuarios", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification', :unlock => 'unblock', :registration => 'register', :sign_up => 'cmon_let_me_in' }
```
Be sure to check +devise_for+ documentation for details.
Be sure to check `devise_for` documentation for details.
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a +devise_scope+ block in the router:
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is to create your routes normally and wrap them in a `devise_scope` block in the router:
```ruby
devise_scope :user do
@@ -257,15 +259,7 @@ devise_scope :user do
end
```
This way you tell devise to use the scope :user when "/sign_in" is accessed. Notice +devise_scope+ is also aliased as +as+ and you can also give a block to +devise_for+, resulting in the same behavior:
```ruby
devise_for :users do
get "sign_in", :to => "devise/sessions#new"
end
```
Feel free to choose the one you prefer!
This way you tell devise to use the scope :user when "/sign_in" is accessed. Notice `devise_scope` is also aliased as `as` in your router.
### I18n
@@ -327,7 +321,7 @@ class ActionController::TestCase
end
```
If you're using RSpec and want the helpers automatically included within all +describe+ blocks, add a file called spec/support/devise.rb with the following contents:
If you're using RSpec and want the helpers automatically included within all `describe` blocks, add a file called spec/support/devise.rb with the following contents:
```ruby
RSpec.configure do |config|

View File

@@ -89,8 +89,7 @@ MESSAGE
warden.authenticated?(resource_name)
end
if authenticated
resource = warden.user(resource_name)
if authenticated && resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
redirect_to after_sign_in_path_for(resource)
end
@@ -162,4 +161,4 @@ MESSAGE
super
end
end
end
end

View File

@@ -1,25 +1,3 @@
<%- if controller_name != 'sessions' %>
<%= link_to "Sign in", new_session_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
<% end -%>
<% end -%>
<% ActiveSupport::Deprecation.warn "Rendering partials devise/_links.erb is deprecated" \
"please use devise/shared/_links.erb instead."%>
<%= render "shared/links" %>

View File

@@ -9,4 +9,4 @@
<div><%= f.submit "Resend confirmation instructions" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -13,4 +13,4 @@
<div><%= f.submit "Change my password" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -9,4 +9,4 @@
<div><%= f.submit "Send me reset password instructions" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -15,4 +15,4 @@
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -14,4 +14,4 @@
<div><%= f.submit "Sign in" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -1,3 +1,25 @@
<% ActiveSupport::Deprecation.warn "Rendering partials devise/shared/_links.erb is deprecated" \
"please use devise/_links.erb instead." %>
<%= render "links" %>
<%- if controller_name != 'sessions' %>
<%= link_to "Sign in", new_session_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end -%>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
<% end -%>
<% end -%>

View File

@@ -9,4 +9,4 @@
<div><%= f.submit "Resend unlock instructions" %></div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -46,8 +46,8 @@ en:
unlocked: 'Your account has been unlocked successfully. Please sign in to continue.'
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}".'
success: 'Successfully authenticated from %{kind} account.'
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
mailer:
confirmation_instructions:
subject: 'Confirmation instructions'

View File

@@ -23,6 +23,7 @@ module Devise
module Encryptors
autoload :Base, 'devise/encryptors/base'
autoload :AuthlogicSha512, 'devise/encryptors/authlogic_sha512'
autoload :BCrypt, 'devise/encryptors/bcrypt'
autoload :ClearanceSha1, 'devise/encryptors/clearance_sha1'
autoload :RestfulAuthenticationSha1, 'devise/encryptors/restful_authentication_sha1'
autoload :Sha512, 'devise/encryptors/sha512'

View File

@@ -208,7 +208,7 @@ module Devise
# if resource.is_a?(User) && resource.can_publish?
# publisher_url
# else
# signed_in_root_path(resource)
# super
# end
# end
#

View File

@@ -15,6 +15,10 @@ module Devise
def self.salt(stretches)
Devise.friendly_token[0,20]
end
def self.compare(encrypted_password, password, stretches, salt, pepper)
Devise.secure_compare(encrypted_password, digest(password, stretches, salt, pepper))
end
end
end
end
end

View File

@@ -0,0 +1,14 @@
module Devise
module Encryptors
class BCrypt < Base
def self.digest(password, stretches, salt, pepper)
::BCrypt::Engine.hash_secret("#{password}#{pepper}",salt, stretches)
end
def self.compare(encrypted_password, password, stretches, salt, pepper)
salt = ::BCrypt::Password.new(encrypted_password).salt
Devise.secure_compare(encrypted_password, digest(password, stretches, salt, pepper))
end
end
end
end

View File

@@ -88,6 +88,7 @@ module Devise
opts = {}
route = :"new_#{scope}_session_path"
opts[:format] = request_format unless skip_format?
opts[:script_name] = nil
context = send(Devise.available_router_name)

View File

@@ -1,5 +1,15 @@
module Devise
module Models
class MissingAttribute < StandardError
def initialize(attributes)
@attributes = attributes
end
def message
"The following attribute(s) is (are) missing on your model: #{@attributes.join(", ")}"
end
end
# Creates configuration values for Devise and for the given module.
#
# Devise::Models.config(Devise::Authenticatable, :stretches, 10)
@@ -39,6 +49,26 @@ module Devise
end
end
def self.check_fields!(klass)
failed_attributes = []
klass.devise_modules.each do |mod|
instance = klass.new
if const_get(mod.to_s.classify).respond_to?(:required_fields)
const_get(mod.to_s.classify).required_fields(klass).each do |field|
failed_attributes << field unless instance.respond_to?(field)
end
else
ActiveSupport::Deprecation.warn "The module #{mod} doesn't implement self.required_fields(klass). Devise uses required_fields to warn developers of any missing fields in their models. Please implement #{mod}.required_fields(klass) that returns an array of symbols with the required fields."
end
end
if failed_attributes.any?
fail Devise::Models::MissingAttribute.new(failed_attributes)
end
end
# Include the chosen devise modules in your model:
#
# devise :database_authenticatable, :confirmable, :recoverable
@@ -66,7 +96,7 @@ module Devise
if class_mod.respond_to?(:available_configs)
available_configs = class_mod.available_configs
available_configs.each do |config|
next unless options.key?(config)
next unless options.key?(config)
send(:"#{config}=", options.delete(config))
end
end
@@ -88,4 +118,4 @@ module Devise
end
end
require 'devise/models/authenticatable'
require 'devise/models/authenticatable'

View File

@@ -64,6 +64,10 @@ module Devise
before_validation :strip_whitespace
end
def self.required_fields(klass)
[]
end
# Check if the current object is valid for authentication. This method and
# find_for_authentication are the methods used in a Warden::Strategy to check
# if a model should be signed in or not.
@@ -74,6 +78,10 @@ module Devise
block_given? ? yield : true
end
def unauthenticated_message
:invalid
end
def active_for_authentication?
true
end
@@ -210,4 +218,4 @@ module Devise
end
end
end
end
end

View File

@@ -36,6 +36,15 @@ module Devise
after_update :send_confirmation_instructions, :if => :reconfirmation_required?
end
def self.required_fields(klass)
required_methods = [:confirmation_token, :confirmed_at, :confirmation_sent_at]
if klass.reconfirmable
required_methods << :unconfirmed_email
end
required_methods
end
# Confirm a user by setting it's confirmed_at to actual time. If the user
# is already confirmed, add an error to email field. If the user is invalid
# add errors
@@ -45,7 +54,7 @@ module Devise
self.confirmed_at = Time.now.utc
if self.class.reconfirmable && unconfirmed_email.present?
@bypass_postpone = true
skip_reconfirmation!
self.email = unconfirmed_email
self.unconfirmed_email = nil
@@ -99,6 +108,12 @@ module Devise
self.confirmed_at = Time.now.utc
end
# If you don't want reconfirmation to be sent, neither a code
# to be generated, call skip_reconfirmation!
def skip_reconfirmation!
@bypass_postpone = true
end
def headers_for(action)
headers = super
if action == :confirmation_instructions && pending_reconfirmation?

View File

@@ -27,6 +27,10 @@ module Devise
attr_accessor :password_confirmation
end
def self.required_fields(klass)
[:encrypted_password] + klass.authentication_keys
end
# Generates password encryption based on the given value.
def password=(new_password)
@password = new_password
@@ -36,9 +40,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)
encryptor_class.compare(encrypted_password, password, self.class.stretches, authenticatable_salt, self.class.pepper)
end
# Set password and password confirmation to nil
@@ -96,14 +98,18 @@ module Devise
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
self.encrypted_password[0,29] if self.encrypted_password
encrypted_password[0,29] if encrypted_password
end
protected
# Digests the password using bcrypt.
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
encryptor_class.digest(password, self.class.stretches, ::BCrypt::Engine.generate_salt, self.class.pepper)
end
def encryptor_class
Devise::Encryptors::BCrypt
end
module ClassMethods

View File

@@ -2,7 +2,8 @@ require 'devise/strategies/database_authenticatable'
module Devise
module Models
# Encryptable Module adds support to several encryptors.
# Encryptable module adds support to several encryptors wrapping
# them in a salt and pepper mechanism to increase security.
#
# == Options
#
@@ -24,30 +25,37 @@ module Devise
attr_accessor :password_confirmation
end
# Generates password salt.
def self.required_fields(klass)
[:password_salt]
end
# Generates password salt when setting the password.
def password=(new_password)
self.password_salt = self.class.password_salt if new_password.present?
super
end
# Overrides authenticatable salt to use the new password_salt
# column. authenticatable_salt is used by `valid_password?`
# and by other modules whenever there is a need for a random
# token based on the user password.
def authenticatable_salt
self.password_salt
end
# Verifies whether an incoming_password (ie from sign in) is the user password.
def valid_password?(incoming_password)
Devise.secure_compare(password_digest(incoming_password), self.encrypted_password)
end
protected
# Digests the password using the configured encryptor.
def password_digest(password)
if self.password_salt.present?
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
if password_salt.present?
encryptor_class.digest(password, self.class.stretches, authenticatable_salt, self.class.pepper)
end
end
def encryptor_class
self.class.encryptor_class
end
module ClassMethods
Devise::Models.config(self, :encryptor)

View File

@@ -22,6 +22,15 @@ module Devise
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
def self.required_fields(klass)
attributes = []
attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts)
attributes << :unlock_at if klass.unlock_strategy_enabled?(:time)
attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)
attributes
end
# Lock a user setting its locked_at to actual time.
def lock_access!
self.locked_at = Time.now.utc
@@ -88,7 +97,6 @@ module Devise
self.failed_attempts += 1
if attempts_exceeded?
lock_access! unless access_locked?
return :locked
else
save(:validate => false)
end
@@ -96,6 +104,14 @@ module Devise
end
end
def unauthenticated_message
if lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
:locked
else
super
end
end
protected
def attempts_exceeded?

View File

@@ -15,6 +15,10 @@ module Devise
module Omniauthable
extend ActiveSupport::Concern
def self.required_fields(klass)
[]
end
module ClassMethods
Devise::Models.config(self, :omniauth_providers)
end

View File

@@ -24,6 +24,10 @@ module Devise
module Recoverable
extend ActiveSupport::Concern
def self.required_fields(klass)
[:reset_password_sent_at, :reset_password_token]
end
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
def reset_password!(new_password, new_password_confirmation)

View File

@@ -5,6 +5,10 @@ module Devise
module Registerable
extend ActiveSupport::Concern
def self.required_fields(klass)
[]
end
module ClassMethods
# A convenience method that receives both parameters and session to
# initialize a user. This can be used by OAuth, for example, to send

View File

@@ -24,7 +24,7 @@ module Devise
# * +extend_remember_period+: if true, extends the user's remember period
# when remembered via cookie. False by default.
#
# * +cookie_options+: configuration options passed to the created cookie.
# * +rememberable_options+: configuration options passed to the created cookie.
#
# == Examples
#
@@ -41,6 +41,10 @@ module Devise
attr_accessor :remember_me, :extend_remember_period
def self.required_fields(klass)
[:remember_created_at, :remember_token]
end
# Generate a new remember token and save the record without validations
# unless remember_across_browsers is true and the user already has a valid token.
def remember_me!(extend_period=false)
@@ -71,7 +75,7 @@ module Devise
def rememberable_value
if respond_to?(:remember_token)
remember_token
elsif salt = authenticatable_salt
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
salt
else
raise "authenticable_salt returned nil for the #{self.class.name} model. " \

View File

@@ -20,6 +20,10 @@ module Devise
module Timeoutable
extend ActiveSupport::Concern
def self.required_fields(klass)
[]
end
# Checks whether the user session has expired based on configured time.
def timedout?(last_access)
return false if remember_exists_and_not_expired?

View File

@@ -27,6 +27,10 @@ module Devise
module TokenAuthenticatable
extend ActiveSupport::Concern
def self.required_fields(klass)
[:authentication_token]
end
# Generate new authentication token (a.k.a. "single access token").
def reset_authentication_token
self.authentication_token = self.class.authentication_token
@@ -52,6 +56,7 @@ module Devise
def after_token_authentication
end
module ClassMethods
def find_for_token_authentication(conditions)
find_for_authentication(:authentication_token => conditions[token_authentication_key])

View File

@@ -11,6 +11,10 @@ module Devise
# * last_sign_in_ip - Holds the remote ip of the previous sign in
#
module Trackable
def self.required_fields(klass)
[:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count]
end
def update_tracked_fields!(request)
old_current, new_current = self.current_sign_in_at, Time.now.utc
self.last_sign_in_at = old_current || new_current

View File

@@ -17,6 +17,10 @@ module Devise
VALIDATIONS = [ :validates_presence_of, :validates_uniqueness_of, :validates_format_of,
:validates_confirmation_of, :validates_length_of ].freeze
def self.required_fields(klass)
[]
end
def self.included(base)
base.extend ClassMethods
assert_validations_api!(base)

View File

@@ -87,8 +87,6 @@ module Devise
end
config.after_initialize do
Devise.configure_warden!
example = <<-YAML
en:
devise:

View File

@@ -7,11 +7,8 @@ module ActionDispatch::Routing
def finalize_with_devise!
result = finalize_without_devise!
# If @devise_finalized was defined, it means devise_for was invoked
# in this router, so we proceed to generate devise helpers unless
# they were already defined (which then @devise_finalizd would be true).
if defined?(@devise_finalized) && !@devise_finalized
if Devise.router_name.nil? && self != Rails.application.try(:routes)
@devise_finalized ||= begin
if Devise.router_name.nil? && defined?(@devise_finalized) && self != Rails.application.try(:routes)
warn "[DEVISE] We have detected that you are using devise_for inside engine routes. " \
"In this case, you probably want to set Devise.router_name = MOUNT_POINT, where " \
"MOUNT_POINT is a symbol representing where this engine will be mounted at. For " \
@@ -19,8 +16,9 @@ module ActionDispatch::Routing
" to :main_app as well in case you want to keep the current behavior."
end
Devise.configure_warden!
Devise.regenerate_helpers!
@devise_finalized = true
true
end
result
@@ -186,7 +184,7 @@ module ActionDispatch::Routing
#
# In order to get Devise to recognize the deactivate action, your devise_for entry should look like this,
#
# devise_for :owners, :controllers => { :registrations => "registrations" } do
# devise_scope :owner do
# post "deactivate", :to => "registrations#deactivate", :as => "deactivate_registration"
# end
#
@@ -200,7 +198,8 @@ module ActionDispatch::Routing
options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {})
options[:constraints] = (@scope[:constraints] || {}).merge(options[:constraints] || {})
options[:defaults] = (@scope[:defaults] || {}).merge(options[:defaults] || {})
options[:options] = (@scope[:options] || {}).merge({:format => false}) if options[:format] == false
options[:options] = @scope[:options] || {}
options[:options][:format] = false if options[:format] == false
resources.map!(&:to_sym)

View File

@@ -23,14 +23,20 @@ module Devise
result = resource && resource.valid_for_authentication?(&block)
case result
when String, Symbol
when Symbol, String
ActiveSupport::Deprecation.warn "valid_for_authentication should return a boolean value"
fail!(result)
false
when TrueClass
return false
end
if result
decorate(resource)
true
else
result
if resource
fail!(resource.unauthenticated_message)
end
false
end
end

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "2.0.3".freeze
VERSION = "2.1.0.rc".freeze
end

View File

@@ -39,6 +39,18 @@ module 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."
hide!
# 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__)
@@ -80,15 +92,12 @@ module Devise
end
class ViewsGenerator < Rails::Generators::Base
include ViewPathTemplates
source_root File.expand_path("../../../../app/views/devise", __FILE__)
desc "Copies Devise views to your application."
def copy_views
copy_file "_links.erb", "#{target_path}/_links.erb"
end
argument :scope, :required => false, :default => nil,
:desc => "The scope to copy views to"
invoke SharedViewsGenerator
hook_for :form_builder, :aliases => "-b",
:desc => "Form builder to be used",
:default => defined?(SimpleForm) ? "simple_form_for" : "form_for"

View File

@@ -117,7 +117,7 @@ Devise.setup do |config|
# 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 = {}
# config.rememberable_options = {}
# ==> Configuration for :validatable
# Range for password length. Default is 6..128.

View File

@@ -12,4 +12,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -16,4 +16,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -12,4 +12,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -14,4 +14,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -12,4 +12,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -12,4 +12,4 @@
</div>
<% end %>
<%= render "links" %>
<%= render :partial => "devise/shared/links" %>

View File

@@ -46,7 +46,7 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
assert_file "app/views/#{scope}/registrations/new.html.erb"
assert_file "app/views/#{scope}/registrations/edit.html.erb"
assert_file "app/views/#{scope}/sessions/new.html.erb"
assert_file "app/views/#{scope}/shared/_links.erb"
assert_file "app/views/#{scope}/unlocks/new.html.erb"
assert_file "app/views/#{scope}/_links.erb"
end
end

View File

@@ -118,7 +118,7 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
OmniAuth.config.mock_auth[:facebook] = :access_denied
visit "/users/auth/facebook/callback?error=access_denied"
assert_current_url "/users/sign_in"
assert_contain 'Could not authorize you from Facebook because "Access denied".'
assert_contain 'Could not authenticate you from Facebook because "Access denied".'
end
test "handles other exceptions from omniauth" do
@@ -128,6 +128,6 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
click_link "Sign in with Facebook"
assert_current_url "/users/sign_in"
assert_contain 'Could not authorize you from Facebook because "Invalid credentials".'
assert_contain 'Could not authenticate you from Facebook because "Invalid credentials".'
end
end

View File

@@ -0,0 +1,7 @@
require 'test_helper'
class AuthenticatableTest < ActiveSupport::TestCase
test 'required_fields should be an empty array' do
assert_equal Devise::Models::Validatable.required_fields(User), []
end
end

View File

@@ -252,6 +252,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
assert_not_nil admin.confirmation_token
end
test 'should not generate confirmation token if skipping reconfirmation after changing email' do
admin = create_admin
assert admin.confirm!
admin.skip_reconfirmation!
assert admin.update_attributes(:email => 'new_test@example.com')
assert_nil admin.confirmation_token
end
test 'should regenerate confirmation token after changing email' do
admin = create_admin
assert admin.confirm!
@@ -328,4 +337,21 @@ class ReconfirmableTest < ActiveSupport::TestCase
admin = Admin.find_by_unconfirmed_email_with_errors(:email => "new_test@email.com")
assert admin.persisted?
end
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Confirmable.required_fields(User), [
:confirmation_sent_at,
:confirmation_token,
:confirmed_at
]
end
test 'required_fields should also contain unconfirmable when reconfirmable_email is true' do
assert_same_content Devise::Models::Confirmable.required_fields(Admin), [
:confirmation_sent_at,
:confirmation_token,
:confirmed_at,
:unconfirmed_email
]
end
end

View File

@@ -11,7 +11,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
user.save!
assert_equal email.downcase, user.email
end
test 'should remove whitespace from strip whitespace keys when saving' do
# strip_whitespace_keys is set to :email by default.
email = ' foo@bar.com '
@@ -92,14 +92,14 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
:password => 'pass321', :password_confirmation => 'pass321')
assert user.reload.valid_password?('pass321')
end
test 'should update password with valid current password and :as option' do
user = create_user
assert user.update_with_password(:current_password => '123456',
:password => 'pass321', :password_confirmation => 'pass321', :as => :admin)
assert user.reload.valid_password?('pass321')
end
test 'should add an error to current password when it is invalid' do
user = create_user
assert_not user.update_with_password(:current_password => 'other',
@@ -151,7 +151,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
user.update_without_password(:email => 'new@example.com')
assert_equal 'new@example.com', user.email
end
test 'should update the user without password with :as option' do
user = create_user
user.update_without_password(:email => 'new@example.com', :as => :admin)
@@ -170,4 +170,20 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
user = User.create(:email => "HEllO@example.com", :password => "123456")
assert !user.valid?
end
end
test 'required_fiels should be encryptable_password and the email field by default' do
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
:email,
:encrypted_password
]
end
test 'required_fields should be encryptable_password and the login when the login is on authentication_keys' do
swap Devise, :authentication_keys => [:login] do
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
:encrypted_password,
:login
]
end
end
end

View File

@@ -64,4 +64,10 @@ class EncryptableTest < ActiveSupport::TestCase
admin.save
assert_not admin.valid_password?('123456')
end
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Encryptable.required_fields(User), [
:password_salt
]
end
end

View File

@@ -235,4 +235,38 @@ class LockableTest < ActiveSupport::TestCase
assert_nil user.locked_at
end
end
test 'required_fields should contain the all the fields when all the strategies are enabled' do
swap Devise, :unlock_strategy => :both do
swap Devise, :lock_strategy => :failed_attempts do
assert_same_content Devise::Models::Lockable.required_fields(User), [
:failed_attempts,
:unlock_at,
:unlock_token
]
end
end
end
test 'required_fields should contain only failed_attempts and unlock_at when the strategies are time and failed_attempts are enabled' do
swap Devise, :unlock_strategy => :time do
swap Devise, :lock_strategy => :failed_attempts do
assert_same_content Devise::Models::Lockable.required_fields(User), [
:failed_attempts,
:unlock_at
]
end
end
end
test 'required_fields should contain only failed_attempts and unlock_token when the strategies are token and failed_attempts are enabled' do
swap Devise, :unlock_strategy => :email do
swap Devise, :lock_strategy => :failed_attempts do
assert_same_content Devise::Models::Lockable.required_fields(User), [
:failed_attempts,
:unlock_token
]
end
end
end
end

View File

@@ -0,0 +1,7 @@
require 'test_helper'
class OmniauthableTest < ActiveSupport::TestCase
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Omniauthable.required_fields(User), []
end
end

View File

@@ -195,4 +195,11 @@ class RecoverableTest < ActiveSupport::TestCase
assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
end
end
end
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Recoverable.required_fields(User), [
:reset_password_sent_at,
:reset_password_token
]
end
end

View File

@@ -0,0 +1,7 @@
require 'test_helper'
class RegisterableTest < ActiveSupport::TestCase
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Registerable.required_fields(User), []
end
end

View File

@@ -54,7 +54,7 @@ class RememberableTest < ActiveSupport::TestCase
resource.forget_me!
assert resource.remember_created_at.nil?
end
test 'forget_me should not try to update resource if it has been destroyed' do
resource = create_resource
resource.destroy
@@ -165,4 +165,11 @@ class RememberableTest < ActiveSupport::TestCase
assert_not_equal old, resource.remember_created_at
end
end
test 'should have the required_fiels array' do
assert_same_content Devise::Models::Rememberable.required_fields(User), [
:remember_created_at,
:remember_token
]
end
end

View File

@@ -39,4 +39,8 @@ class TimeoutableTest < ActiveSupport::TestCase
assert user.timedout?(6.minutes.ago)
end
end
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Timeoutable.required_fields(User), []
end
end

View File

@@ -46,4 +46,10 @@ class TokenAuthenticatableTest < ActiveSupport::TestCase
user = User.find_for_token_authentication(:auth_token => {'$ne' => user1.authentication_token})
assert_nil user
end
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::TokenAuthenticatable.required_fields(User), [
:authentication_token
]
end
end

View File

@@ -1,5 +1,13 @@
require 'test_helper'
class TrackableTest < ActiveSupport::TestCase
test 'required_fields should contain the fields that Devise uses' do
assert_same_content Devise::Models::Trackable.required_fields(User), [
:current_sign_in_at,
:current_sign_in_ip,
:last_sign_in_at,
:last_sign_in_ip,
:sign_in_count
]
end
end

View File

@@ -105,9 +105,13 @@ class ValidatableTest < ActiveSupport::TestCase
assert_equal 'is too long (maximum is 128 characters)', user.errors[:password].join
end
test 'shuold not be included in objects with invalid API' do
test 'should not be included in objects with invalid API' do
assert_raise RuntimeError do
Class.new.send :include, Devise::Models::Validatable
end
end
test 'required_fields should be an empty array' do
assert_equal Devise::Models::Validatable.required_fields(User), []
end
end

View File

@@ -107,3 +107,73 @@ class ActiveRecordTest < ActiveSupport::TestCase
Admin.create!
end
end
class CheckFieldsTest < ActiveSupport::TestCase
test 'checks if the class respond_to the required fields' do
Player = Class.new do
extend Devise::Models
def self.before_validation(instance)
end
devise :database_authenticatable
attr_accessor :encrypted_password, :email
end
assert_nothing_raised Devise::Models::MissingAttribute do
Devise::Models.check_fields!(Player)
end
end
test 'raises Devise::Models::MissingAtrribute and shows the missing attribute if the class doesn\'t respond_to one of the attributes' do
Clown = Class.new do
extend Devise::Models
def self.before_validation(instance)
end
devise :database_authenticatable
attr_accessor :encrypted_password
end
assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: email" do
Devise::Models.check_fields!(Clown)
end
end
test 'raises Devise::Models::MissingAtrribute with all the missing attributes if there is more than one' do
Magician = Class.new do
extend Devise::Models
def self.before_validation(instance)
end
devise :database_authenticatable
end
exception = assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: encrypted_password, email" do
Devise::Models.check_fields!(Magician)
end
end
test "doesn't raise a NoMethodError exception when the module doesn't have a required_field(klass) class method" do
driver = Class.new do
extend Devise::Models
def self.before_validation(instance)
end
attr_accessor :encrypted_password, :email
devise :database_authenticatable
end
swap_module_method_existence Devise::Models::DatabaseAuthenticatable, :required_fields do
assert_deprecated do
Devise::Models.check_fields!(driver)
end
end
end
end

View File

@@ -58,6 +58,10 @@ Rails.application.routes.draw do
# Other routes for routing_test.rb
devise_for :reader, :class_name => "User", :only => :passwords
scope :host => "sub.example.com" do
devise_for :sub_admin, :class_name => "Admin"
end
namespace :publisher, :path_names => { :sign_in => "i_dont_care", :sign_out => "get_out" } do
devise_for :accounts, :class_name => "Admin", :path_names => { :sign_in => "get_in" }
end

View File

@@ -128,6 +128,10 @@ class CustomizedRoutingTest < ActionController::TestCase
end
end
test 'subdomain admin' do
assert_recognizes({"host"=>"sub.example.com", :controller => 'devise/sessions', :action => 'new'}, {:host => "sub.example.com", :path => '/sub_admin/sign_in', :method => :get})
end
test 'does only map reader password' do
assert_raise ActionController::RoutingError do
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, 'reader/sessions/new')

View File

@@ -24,4 +24,19 @@ class ActiveSupport::TestCase
def assert_email_not_sent(&block)
assert_no_difference('ActionMailer::Base.deliveries.size') { yield }
end
def assert_same_content(result, expected)
assert expected.size == result.size, "the arrays doesn't have the same size"
expected.each do |element|
assert result.include?(element), "The array doesn't include '#{element}'."
end
end
def assert_raise_with_message(exception_klass, message)
exception = assert_raise exception_klass do
yield
end
assert_equal exception.message, message, "The expected message was #{message} but your exception throwed #{exception.message}"
end
end

View File

@@ -67,4 +67,25 @@ class ActiveSupport::TestCase
end
end
end
def swap_module_method_existence(klass, method)
klass.module_eval %Q[
class << self
alias #{method}_referenced #{method}
undef #{method}
end
]
begin
yield if block_given?
ensure
klass.module_eval %Q[
class << self
alias #{method} #{method}_referenced
undef #{method}_referenced
end
]
end
end
end