Compare commits

..

7 Commits
v2.1.0 ... v2.0

Author SHA1 Message Date
José Valim
b78519e154 Release 2.0.6 2013-08-18 10:43:33 +02:00
Rafael Mendonça França
0430689b01 Use the Ruby 1.8 hash syntax.
Yes we still support Ruby 1.8 😢

Conflicts:
	Gemfile.lock
2013-01-28 13:26:29 -02:00
José Valim
bc82165ee3 Release v2.0.5 2013-01-26 11:53:34 -07:00
José Valim
eecb2c1695 Require string conversion for all values 2013-01-26 11:52:15 -07:00
José Valim
8fc18b49eb Release 2.0.4 2012-02-17 12:49:21 +01:00
José Valim
b4af49cc38 Update CHANGELOG. 2012-02-17 12:49:14 +01:00
José Valim
4c654e71be Fix regression where warden was being configured too early. 2012-02-17 12:49:07 +01:00
108 changed files with 901 additions and 935 deletions

View File

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

View File

@@ -1,43 +1,16 @@
== trunk (2.1.0.rc2)
* enhancements
* Devise model generator now works with engines
* Devise encryptable was moved to its new gem (http://github.com/plataformatec/devise-encryptable)
* deprecations
* Deprecations warnings added on Devise 2.0 are now removed with their features
* use_salt_as_remember_token and apply_schema does not have any effect since 2.0 and are now deprecated
* valid_for_authentication? must now return a boolean
== 2.0.6
* bug fix
* Ensure the failure app still respects config.relative_url_root
* `/users/sign_in` doesn't choke on protected attributes used to select sign in scope (by @Paymium)
* `failed_attempts` is set to zero after any sign in (including via reset password) (by @rodrigoflores)
* Added token expiration on timeout (by @antiarchitect)
* Do not accidentally mark `_prefixes` as private
* Better support for custom strategies on test helpers (by @mattconnolly)
* Return `head :no_content` in SessionsController now that most JS libraries handle it (by @julianvargasalvarez)
* Do not confirm account after reset password
== 2.1.0.rc
* 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
== 2.0.5
* 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
* Fixed redirect when authenticated mounted apps (by @hakanensari)
* deprecation
* All devise modules should have a required_fields(klass) module method to help gathering missing attributes
* Require string conversion for all values
== 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)
@@ -93,7 +66,6 @@ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.
* Move devise/shared/_links.erb to devise/_links.erb
* Deprecated support of nested devise_for blocks
* Deprecated support to devise.registrations.reasons and devise.registrations.inactive_signed_up in favor of devise.registrations.signed_up_but_*
* Protected method render_with_scope was removed.
== 1.5.3

View File

@@ -25,7 +25,7 @@ platforms :jruby do
end
platforms :ruby do
gem "sqlite3"
gem "sqlite3-ruby"
group :mongoid do
gem "mongo", "~> 1.3.0"

View File

@@ -1,9 +1,9 @@
PATH
remote: .
specs:
devise (2.1.0)
devise (2.0.6)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.7)
orm_adapter (~> 0.0.3)
railties (~> 3.1)
warden (~> 1.1.1)
@@ -39,7 +39,7 @@ GEM
multi_json (~> 1.0)
addressable (2.2.6)
arel (3.0.0)
bcrypt-ruby (3.0.1)
bcrypt-ruby (3.1.1)
bson (1.5.1)
bson_ext (1.3.1)
builder (3.0.0)
@@ -129,6 +129,8 @@ GEM
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.5)
sqlite3-ruby (1.3.3)
sqlite3 (>= 1.3.3)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
@@ -161,5 +163,5 @@ DEPENDENCIES
rails (~> 3.2.0)
rdoc
ruby-debug (>= 0.10.3)
sqlite3
sqlite3-ruby
webrat (= 0.7.2)

View File

@@ -1,4 +1,4 @@
Copyright 2009-2012 Plataformatec. http://plataformatec.com.br
Copyright 2009-2012 Plataforma Tecnologia. http://blog.plataformatec.com.br
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,6 +1,4 @@
*IMPORTANT:* Devise 2.1 is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.1
*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
*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
## Devise
@@ -17,17 +15,18 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
It's comprised of 12 modules:
* [Database Authenticatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/DatabaseAuthenticatable): 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](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/TokenAuthenticatable): 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.
* [Omniauthable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Omniauthable): adds Omniauth (github.com/intridea/omniauth) support;
* [Confirmable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
* [Recoverable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Recoverable): resets the user password and sends reset instructions.
* [Registerable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Registerable): handles signing up users through a registration process, also allowing them to edit and destroy their account.
* [Rememberable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Rememberable): manages generating and clearing a token for remembering the user from a saved cookie.
* [Trackable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Trackable): tracks sign in count, timestamps and IP address.
* [Timeoutable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Timeoutable): expires sessions that have no activity in a specified period of time.
* [Validatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
* [Lockable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
* 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.
* Omniauthable: adds Omniauth (github.com/intridea/omniauth) support;
* Confirmable: sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
* Recoverable: resets the user password and sends reset instructions.
* Registerable: handles signing up users through a registration process, also allowing them to edit and destroy their account.
* Rememberable: manages generating and clearing a token for remembering the user from a saved cookie.
* Trackable: tracks sign in count, timestamps and IP address.
* Timeoutable: expires sessions that have no activity in a specified period of time.
* Validatable: provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
* Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
* Encryptable: adds support of other authentication mechanisms besides the built-in Bcrypt (the default).
## Information
@@ -43,7 +42,7 @@ If you discover a problem with Devise, we would like to know about it. However,
https://github.com/plataformatec/devise/wiki/Bug-reports
If you found a security bug, do *NOT* use the GitHub issue tracker. Send an email to the maintainers listed at the bottom of the README.
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.
### Mailing list
@@ -92,9 +91,7 @@ Once you have solidified your understanding of Rails and authentication mechanis
Devise 2.0 works with Rails 3.1 onwards. You can add it to your Gemfile with:
```ruby
gem 'devise'
```
gem 'devise'
Run the bundle command to install it.
@@ -112,8 +109,6 @@ 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:
@@ -140,13 +135,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":
@@ -252,9 +247,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
@@ -262,7 +257,15 @@ 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` in your router.
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!
### I18n
@@ -324,7 +327,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|
@@ -382,4 +385,4 @@ https://github.com/plataformatec/devise/contributors
## License
MIT License. Copyright 2012 Plataformatec. http://plataformatec.com.br
MIT License. Copyright 2012 Plataforma Tecnologia. http://blog.plataformatec.com.br

View File

@@ -1,5 +1,5 @@
# encoding: UTF-8
require "bundler/gem_tasks"
require 'rake/testtask'
require 'rdoc/task'

View File

@@ -6,7 +6,7 @@ class Devise::ConfirmationsController < DeviseController
# POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
if successfully_sent?(resource)
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))

View File

@@ -8,7 +8,7 @@ class Devise::PasswordsController < DeviseController
# POST /resource/password
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
@@ -25,7 +25,7 @@ class Devise::PasswordsController < DeviseController
# PUT /resource/password
def update
self.resource = resource_class.reset_password_by_token(resource_params)
self.resource = resource_class.reset_password_by_token(params[resource_name])
if resource.errors.empty?
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active

View File

@@ -39,7 +39,7 @@ class Devise::RegistrationsController < DeviseController
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
if resource.update_with_password(resource_params)
if resource.update_with_password(params[resource_name])
if is_navigational_format?
if resource.respond_to?(:pending_reconfirmation?) && resource.pending_reconfirmation?
flash_key = :update_needs_confirmation
@@ -77,7 +77,7 @@ class Devise::RegistrationsController < DeviseController
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
hash ||= resource_params || {}
hash ||= params[resource_name] || {}
self.resource = resource_class.new_with_session(hash, session)
end

View File

@@ -4,7 +4,7 @@ class Devise::SessionsController < DeviseController
# GET /resource/sign_in
def new
resource = build_resource(nil, :unsafe => true)
resource = build_resource
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
@@ -28,7 +28,9 @@ class Devise::SessionsController < DeviseController
respond_to do |format|
format.any(*navigational_formats) { redirect_to redirect_path }
format.all do
head :no_content
method = "to_#{request_format}"
text = {}.respond_to?(method) ? {}.send(method) : ""
render :text => text, :status => :ok
end
end
end

View File

@@ -8,10 +8,10 @@ class Devise::UnlocksController < DeviseController
# POST /resource/unlock
def create
self.resource = resource_class.send_unlock_instructions(resource_params)
self.resource = resource_class.send_unlock_instructions(params[resource_name])
if successfully_sent?(resource)
respond_with({}, :location => after_sending_unlock_instructions_path_for(resource))
respond_with({}, :location => new_session_path(resource_name))
else
respond_with(resource)
end
@@ -23,22 +23,9 @@ class Devise::UnlocksController < DeviseController
if resource.errors.empty?
set_flash_message :notice, :unlocked if is_navigational_format?
respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
respond_with_navigational(resource){ redirect_to new_session_path(resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
protected
# The path used after sending unlock password instructions
def after_sending_unlock_instructions_path_for(resource)
new_session_path(resource)
end
# The path used after unlocking the resource
def after_unlock_path_for(resource)
new_session_path(resource)
end
end

View File

@@ -5,7 +5,7 @@ class DeviseController < Devise.parent_controller.constantize
helper DeviseHelper
helpers = %w(resource scope_name resource_name signed_in_resource
resource_class resource_params devise_mapping)
resource_class devise_mapping)
hide_action *helpers
helper_method *helpers
@@ -28,10 +28,6 @@ class DeviseController < Devise.parent_controller.constantize
devise_mapping.to
end
def resource_params
params[resource_name]
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
@@ -42,17 +38,6 @@ class DeviseController < Devise.parent_controller.constantize
@devise_mapping ||= request.env["devise.mapping"]
end
# Override prefixes to consider the scoped view.
def _prefixes #:nodoc:
@_prefixes ||= if self.class.scoped_views? && devise_mapping
super.unshift("#{devise_mapping.scoped_path}/#{controller_name}")
else
super
end
end
hide_action :_prefixes
protected
# Checks whether it's a devise mapped resource or not.
@@ -83,20 +68,9 @@ MESSAGE
end
# Build a devise resource.
# Assignment bypasses attribute protection when :unsafe option is passed
def build_resource(hash = nil, options = {})
hash ||= resource_params || {}
if options[:unsafe]
self.resource = resource_class.new.tap do |resource|
hash.each do |key, value|
setter = :"#{key}="
resource.send(setter, value) if resource.respond_to?(setter)
end
end
else
self.resource = resource_class.new(hash)
end
def build_resource(hash=nil)
hash ||= params[resource_name] || {}
self.resource = resource_class.new(hash)
end
# Helper for use in before_filters where no authentication is required.
@@ -115,7 +89,8 @@ 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
@@ -178,4 +153,13 @@ MESSAGE
def is_navigational_format?
Devise.navigational_formats.include?(request.format.try(:ref))
end
end
# Override prefixes to consider the scoped view.
def _prefixes #:nodoc:
@_prefixes ||= if self.class.scoped_views? && devise_mapping
super.unshift("#{devise_mapping.scoped_path}/#{controller_name}")
else
super
end
end
end

View File

@@ -1,3 +1,25 @@
<% ActiveSupport::Deprecation.warn "Rendering partials devise/_links.erb is deprecated" \
"please use devise/shared/_links.erb instead."%>
<%= render "shared/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 confirmation instructions" %></div>
<% end %>
<%= render :partial => "devise/shared/links" %>
<%= render "links" %>

View File

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

View File

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

View File

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

View File

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

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/shared/_links.erb is deprecated" \
"please use devise/_links.erb instead." %>
<%= render "links" %>

View File

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

View File

@@ -28,10 +28,10 @@ en:
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 email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
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 email address exists in our database, 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.'
@@ -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 authenticated from %{kind} account.'
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
success: 'Successfully authorized from %{kind} account.'
failure: 'Could not authorize you from %{kind} because "%{reason}".'
mailer:
confirmation_instructions:
subject: 'Confirmation instructions'

View File

@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
s.require_paths = ["lib"]
s.add_dependency("warden", "~> 1.1.1")
s.add_dependency("orm_adapter", "~> 0.0.7")
s.add_dependency("orm_adapter", "~> 0.0.3")
s.add_dependency("bcrypt-ruby", "~> 3.0")
s.add_dependency("railties", "~> 3.1")
end

View File

@@ -25,7 +25,7 @@ platforms :jruby do
end
platforms :ruby do
gem "sqlite3"
gem "sqlite3-ruby"
group :mongoid do
gem "mongo", "~> 1.3.0"

View File

@@ -1,46 +1,46 @@
PATH
remote: ..
specs:
devise (2.1.0.rc2)
devise (2.0.6)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.7)
orm_adapter (~> 0.0.3)
railties (~> 3.1)
warden (~> 1.1.1)
GEM
remote: http://rubygems.org/
specs:
actionmailer (3.1.4)
actionpack (= 3.1.4)
actionmailer (3.1.3)
actionpack (= 3.1.3)
mail (~> 2.3.0)
actionpack (3.1.4)
activemodel (= 3.1.4)
activesupport (= 3.1.4)
actionpack (3.1.3)
activemodel (= 3.1.3)
activesupport (= 3.1.3)
builder (~> 3.0.0)
erubis (~> 2.7.0)
i18n (~> 0.6)
rack (~> 1.3.6)
rack (~> 1.3.5)
rack-cache (~> 1.1)
rack-mount (~> 0.8.2)
rack-test (~> 0.6.1)
sprockets (~> 2.0.3)
activemodel (3.1.4)
activesupport (= 3.1.4)
activemodel (3.1.3)
activesupport (= 3.1.3)
builder (~> 3.0.0)
i18n (~> 0.6)
activerecord (3.1.4)
activemodel (= 3.1.4)
activesupport (= 3.1.4)
arel (~> 2.2.3)
activerecord (3.1.3)
activemodel (= 3.1.3)
activesupport (= 3.1.3)
arel (~> 2.2.1)
tzinfo (~> 0.3.29)
activeresource (3.1.4)
activemodel (= 3.1.4)
activesupport (= 3.1.4)
activesupport (3.1.4)
activeresource (3.1.3)
activemodel (= 3.1.3)
activesupport (= 3.1.3)
activesupport (3.1.3)
multi_json (~> 1.0)
addressable (2.2.7)
arel (2.2.3)
bcrypt-ruby (3.0.1)
arel (2.2.1)
bcrypt-ruby (3.1.1)
bson (1.5.2)
bson_ext (1.3.1)
builder (3.0.0)
@@ -53,15 +53,15 @@ GEM
hashie (1.2.0)
hike (1.2.1)
i18n (0.6.0)
json (1.7.0)
json (1.6.5)
linecache (0.46)
rbx-require-relative (> 0.0.4)
mail (2.3.3)
mail (2.3.0)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metaclass (0.0.1)
mime-types (1.18)
mime-types (1.17.2)
mocha (0.10.4)
metaclass (~> 0.0.1)
mongo (1.3.1)
@@ -70,7 +70,7 @@ GEM
activemodel (~> 3.1)
mongo (~> 1.3)
tzinfo (~> 0.3.22)
multi_json (1.3.4)
multi_json (1.0.4)
multipart-post (1.1.5)
nokogiri (1.5.0)
oauth2 (0.5.2)
@@ -90,7 +90,7 @@ GEM
orm_adapter (0.0.7)
polyglot (0.3.3)
rack (1.3.6)
rack-cache (1.2)
rack-cache (1.1)
rack (>= 0.4)
rack-mount (0.8.3)
rack (>= 1.0.0)
@@ -101,17 +101,17 @@ GEM
rack
rack-test (0.6.1)
rack (>= 1.0)
rails (3.1.4)
actionmailer (= 3.1.4)
actionpack (= 3.1.4)
activerecord (= 3.1.4)
activeresource (= 3.1.4)
activesupport (= 3.1.4)
rails (3.1.3)
actionmailer (= 3.1.3)
actionpack (= 3.1.3)
activerecord (= 3.1.3)
activeresource (= 3.1.3)
activesupport (= 3.1.3)
bundler (~> 1.0)
railties (= 3.1.4)
railties (3.1.4)
actionpack (= 3.1.4)
activesupport (= 3.1.4)
railties (= 3.1.3)
railties (3.1.3)
actionpack (= 3.1.3)
activesupport (= 3.1.3)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
@@ -126,17 +126,19 @@ GEM
ruby-debug-base (0.10.4)
linecache (>= 0.3)
ruby-openid (2.1.8)
sprockets (2.0.4)
sprockets (2.0.3)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.5)
sqlite3-ruby (1.3.3)
sqlite3 (>= 1.3.3)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.33)
tzinfo (0.3.31)
warden (1.1.1)
rack (>= 1.0)
webrat (0.7.2)
@@ -163,5 +165,5 @@ DEPENDENCIES
rails (~> 3.1.0)
rdoc
ruby-debug (>= 0.10.3)
sqlite3
sqlite3-ruby
webrat (= 0.7.2)

View File

@@ -20,6 +20,15 @@ module Devise
autoload :UrlHelpers, 'devise/controllers/url_helpers'
end
module Encryptors
autoload :Base, 'devise/encryptors/base'
autoload :AuthlogicSha512, 'devise/encryptors/authlogic_sha512'
autoload :ClearanceSha1, 'devise/encryptors/clearance_sha1'
autoload :RestfulAuthenticationSha1, 'devise/encryptors/restful_authentication_sha1'
autoload :Sha512, 'devise/encryptors/sha512'
autoload :Sha1, 'devise/encryptors/sha1'
end
module Mailers
autoload :Helpers, 'devise/mailers/helpers'
end
@@ -43,6 +52,15 @@ module Devise
# True values used to check params
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE']
# Declare encryptors length which are used in migrations.
ENCRYPTORS_LENGTH = {
:sha1 => 40,
:sha512 => 128,
:clearance_sha1 => 40,
:restful_authentication_sha1 => 40,
:authlogic_sha512 => 128
}
# Custom domain for cookies. Not set by default
mattr_accessor :rememberable_options
@@rememberable_options = {}
@@ -60,12 +78,14 @@ module Devise
@@request_keys = []
# Keys that should be case-insensitive.
# False by default for backwards compatibility.
mattr_accessor :case_insensitive_keys
@@case_insensitive_keys = [ :email ]
@@case_insensitive_keys = false
# Keys that should have whitespace stripped.
# False by default for backwards compatibility.
mattr_accessor :strip_whitespace_keys
@@strip_whitespace_keys = []
@@strip_whitespace_keys = false
# If http authentication is enabled by default.
mattr_accessor :http_authenticatable
@@ -118,14 +138,14 @@ module Devise
mattr_accessor :timeout_in
@@timeout_in = 30.minutes
# Authentication token expiration on timeout
mattr_accessor :expire_auth_token_on_timeout
@@expire_auth_token_on_timeout = false
# Used to encrypt password. Please generate one with rake secret.
mattr_accessor :pepper
@@pepper = nil
# Used to define the password encryption algorithm.
mattr_accessor :encryptor
@@encryptor = nil
# Scoped views. Since it relies on fallbacks to render default views, it's
# turned off by default.
mattr_accessor :scoped_views
@@ -158,8 +178,9 @@ module Devise
@@reset_password_keys = [ :email ]
# Time interval you can reset your password with a reset password key
# Nil by default for backwards compatibility.
mattr_accessor :reset_password_within
@@reset_password_within = 6.hours
@@reset_password_within = nil
# The default scope which is used by warden.
mattr_accessor :default_scope
@@ -201,16 +222,36 @@ module Devise
mattr_accessor :router_name
@@router_name = nil
def self.encryptor=(value)
warn "\n[DEVISE] To select a encryption which isn't bcrypt, you should use devise-encryptable gem.\n"
# DEPRECATED CONFIG
# If true, uses salt as remember token and does not create it in the database.
# By default is false for backwards compatibility.
mattr_accessor :use_salt_as_remember_token
@@use_salt_as_remember_token = false
# Tells if devise should apply the schema in ORMs where devise declaration
# and schema belongs to the same class (as Datamapper and Mongoid).
mattr_accessor :apply_schema
@@apply_schema = true
def self.remember_across_browsers=(value)
warn "\n[DEVISE] Devise.remember_across_browsers is deprecated and has no effect. Please remove it.\n"
end
def self.use_salt_as_remember_token=(value)
warn "\n[DEVISE] Devise.use_salt_as_remember_token is deprecated and has no effect. Please remove it.\n"
def self.confirm_within=(value)
warn "\n[DEVISE] Devise.confirm_within= is deprecated. Please set Devise.allow_unconfirmed_access_for= instead.\n"
Devise.allow_unconfirmed_access_for = value
end
def self.apply_schema=(value)
warn "\n[DEVISE] Devise.apply_schema is deprecated and has no effect. Please remove it.\n"
def self.cookie_options=(value)
warn "\n[DEVISE] Devise.cookie_options= is deprecated. Please set Devise.rememberable_options= instead.\n"
Devise.rememberable_options = value
end
def self.stateless_token=(value)
warn "\n[DEVISE] Devise.stateless_token= is deprecated. Please append :token_auth to Devise.skip_session_storage " \
"instead, for example: Devise.skip_session_storage << :token_auth\n"
Devise.skip_session_storage << :token_auth
end
# PRIVATE CONFIGURATION

View File

@@ -208,7 +208,7 @@ module Devise
# if resource.is_a?(User) && resource.can_publish?
# publisher_url
# else
# super
# signed_in_root_path(resource)
# end
# end
#
@@ -237,6 +237,11 @@ module Devise
redirect_to after_sign_in_path_for(resource)
end
def redirect_location(scope, resource) #:nodoc:
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

View File

@@ -0,0 +1,19 @@
require "digest/sha2"
module Devise
module Encryptors
# = AuthlogicSha512
# Simulates Authlogic's default encryption mechanism.
# 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
# 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('')
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
digest
end
end
end
end

View File

@@ -0,0 +1,20 @@
module Devise
# Implements a way of adding different encryptions.
# The class should implement a self.digest method that taks the following params:
# - password
# - stretches: the number of times the encryption will be applied
# - salt: the password salt as defined by devise
# - pepper: Devise config option
#
module Encryptors
class Base
def self.digest
raise NotImplemented
end
def self.salt(stretches)
Devise.friendly_token[0,20]
end
end
end
end

View File

@@ -0,0 +1,17 @@
require "digest/sha1"
module Devise
module Encryptors
# = ClearanceSha1
# Simulates Clearance's default encryption mechanism.
# 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
# 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}--")
end
end
end
end

View File

@@ -0,0 +1,22 @@
require "digest/sha1"
module Devise
module Encryptors
# = RestfulAuthenticationSha1
# Simulates Restful Authentication's default encryption mechanism.
# 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. Should be set to 10 in
# the initializer to simulate the default behavior.
class RestfulAuthenticationSha1 < Base
# Generates a default password digest based on salt, pepper and the
# incoming password.
def self.digest(password, stretches, salt, pepper)
digest = pepper
stretches.times { digest = Digest::SHA1.hexdigest([digest, salt, password, pepper].flatten.join('--')) }
digest
end
end
end
end

View File

@@ -0,0 +1,25 @@
require "digest/sha1"
module Devise
module Encryptors
# = Sha1
# Uses the Sha1 hash algorithm to encrypt passwords.
class Sha1 < Base
# Generates a default password digest based on stretches, salt, pepper and the
# incoming password.
def self.digest(password, stretches, salt, pepper)
digest = pepper
stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
digest
end
private
# Generate a SHA1 digest joining args. Generated token is something like
# --arg1--arg2--arg3--argN--
def self.secure_digest(*tokens)
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
end
end
end
end

View File

@@ -0,0 +1,25 @@
require "digest/sha2"
module Devise
module Encryptors
# = Sha512
# Uses the Sha512 hash algorithm to encrypt passwords.
class Sha512 < Base
# Generates a default password digest based on salt, pepper and the
# incoming password.
def self.digest(password, stretches, salt, pepper)
digest = pepper
stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
digest
end
private
# Generate a Sha512 digest joining args. Generated token is something like
# --arg1--arg2--arg3--argN--
def self.secure_digest(*tokens)
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
end
end
end
end

View File

@@ -89,9 +89,6 @@ module Devise
route = :"new_#{scope}_session_path"
opts[:format] = request_format unless skip_format?
config = Rails.application.config
opts[:script_name] = (config.relative_url_root if config.respond_to?(:relative_url_root))
context = send(Devise.available_router_name)
if context.respond_to?(route)

View File

@@ -1,7 +0,0 @@
# After each sign in, if resource responds to failed_attempts, sets it to 0
# This is only triggered when the user is explicitly set (with set_user)
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
record.update_attribute(:failed_attempts, 0)
end
end

View File

@@ -11,7 +11,6 @@ Warden::Manager.after_set_user do |record, warden, options|
if record.timedout?(last_request_at)
warden.logout(scope)
record.reset_authentication_token! if record.respond_to?(:reset_authentication_token!) && record.expire_auth_token_on_timeout
throw :warden, :scope => scope, :message => :timeout
end

View File

@@ -1,15 +1,5 @@
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)
@@ -49,28 +39,6 @@ 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
@@ -89,10 +57,6 @@ module Devise
devise_modules_hook! do
include Devise::Models::Authenticatable
selected_modules.each do |m|
if m == :encryptable && !(defined?(Devise::Models::Encryptable))
warn "[DEVISE] You're trying to include :encryptable in your model but it is not bundled with the Devise gem anymore. Please add `devise-encryptable` to your Gemfile to proceed.\n"
end
mod = Devise::Models.const_get(m.to_s.classify)
if mod.const_defined?("ClassMethods")
@@ -102,7 +66,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
@@ -116,12 +80,12 @@ module Devise
end
end
# The hook which is called inside devise.
# So your ORM can include devise compatibility stuff.
# The hook which is called inside devise. So your ORM can include devise
# compatibility stuff.
def devise_modules_hook!
yield
end
end
end
require 'devise/models/authenticatable'
require 'devise/models/authenticatable'

View File

@@ -54,7 +54,7 @@ module Devise
BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at, :authentication_token]
:unconfirmed_email, :failed_attempts, :unlock_token, :locked_at, :authentication_token]
included do
class_attribute :devise_modules, :instance_writer => false
@@ -64,10 +64,6 @@ 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.
@@ -78,10 +74,6 @@ module Devise
block_given? ? yield : true
end
def unauthenticated_message
:invalid
end
def active_for_authentication?
true
end
@@ -102,11 +94,11 @@ module Devise
end
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!) }
(self.class.strip_whitespace_keys || []).each { |k| self[k].try(:strip!) }
end
array = %w(serializable_hash)
@@ -158,31 +150,24 @@ module Devise
end
# Find first record based on conditions given (ie by the sign in form).
# This method is always called during an authentication process but
# it may be wrapped as well. For instance, database authenticatable
# provides a `find_for_database_authentication` that wraps a call to
# this method. This allows you to customize both database authenticatable
# or the whole authenticate stack by customize `find_for_authentication.`
#
# Overwrite to add customized conditions, create a join, or maybe use a
# namedscope to filter records while authenticating.
# Example:
#
# def self.find_for_authentication(conditions={})
# conditions[:active] = true
# super
# def self.find_for_authentication(tainted_conditions)
# find_first_by_auth_conditions(tainted_conditions, :active => true)
# end
#
# Finally, notice that Devise also queries for users in other scenarios
# besides authentication, for example when retrieving an user to send
# an e-mail for password reset. In such cases, find_for_authentication
# is not called.
def find_for_authentication(conditions)
find_first_by_auth_conditions(conditions)
def find_for_authentication(tainted_conditions)
find_first_by_auth_conditions(tainted_conditions)
end
def find_first_by_auth_conditions(conditions)
to_adapter.find_first devise_param_filter.filter(conditions)
def find_first_by_auth_conditions(tainted_conditions, opts={})
to_adapter.find_first(devise_param_filter.filter(tainted_conditions).merge(opts))
end
# Find an initialize a record setting an error if it can't be found.

View File

@@ -33,13 +33,7 @@ module Devise
before_create :generate_confirmation_token, :if => :confirmation_required?
after_create :send_on_create_confirmation_instructions, :if => :confirmation_required?
before_update :postpone_email_change_until_confirmation, :if => :postpone_email_change?
after_update :send_confirmation_instructions, :if => :reconfirmation_required?
end
def self.required_fields(klass)
required_methods = [:confirmation_token, :confirmed_at, :confirmation_sent_at]
required_methods << :unconfirmed_email if klass.reconfirmable
required_methods
after_update :send_confirmation_instructions, :if => :reconfirmation_required?
end
# Confirm a user by setting it's confirmed_at to actual time. If the user
@@ -51,7 +45,7 @@ module Devise
self.confirmed_at = Time.now.utc
if self.class.reconfirmable && unconfirmed_email.present?
skip_reconfirmation!
@bypass_postpone = true
self.email = unconfirmed_email
self.unconfirmed_email = nil
@@ -105,12 +99,6 @@ 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?
@@ -177,11 +165,6 @@ module Devise
generate_confirmation_token && save(:validate => false)
end
def after_password_reset
super
confirm! unless confirmed?
end
def postpone_email_change_until_confirmation
@reconfirmation_required = true
self.unconfirmed_email = self.email

View File

@@ -27,10 +27,6 @@ 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
@@ -40,9 +36,9 @@ 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(encrypted_password)
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
Devise.secure_compare(password, encrypted_password)
Devise.secure_compare(password, self.encrypted_password)
end
# Set password and password confirmation to nil
@@ -100,7 +96,7 @@ module Devise
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
encrypted_password[0,29] if encrypted_password
self.encrypted_password[0,29] if self.encrypted_password
end
protected

View File

@@ -0,0 +1,72 @@
require 'devise/strategies/database_authenticatable'
module Devise
module Models
# Encryptable Module adds support to several encryptors.
#
# == Options
#
# Encryptable adds the following options to devise_for:
#
# * +pepper+: a random string used to provide a more secure hash.
#
# * +encryptor+: the encryptor going to be used. By default is nil.
#
# == Examples
#
# User.find(1).valid_password?('password123') # returns true/false
#
module Encryptable
extend ActiveSupport::Concern
included do
attr_reader :password, :current_password
attr_accessor :password_confirmation
end
# Generates password salt.
def password=(new_password)
self.password_salt = self.class.password_salt if new_password.present?
super
end
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)
end
end
module ClassMethods
Devise::Models.config(self, :encryptor)
# Returns the class for the configured encryptor.
def encryptor_class
@encryptor_class ||= case encryptor
when :bcrypt
raise "In order to use bcrypt as encryptor, simply remove :encryptable from your devise model"
when nil
raise "You need to give an :encryptor as option in order to use :encryptable"
else
::Devise::Encryptors.const_get(encryptor.to_s.classify)
end
end
def password_salt
self.encryptor_class.salt(self.stretches)
end
end
end
end
end

View File

@@ -1,5 +1,3 @@
require "devise/hooks/lockable"
module Devise
module Models
# Handles blocking a user access after a certain number of attempts.
@@ -24,15 +22,6 @@ 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
@@ -45,7 +34,7 @@ module Devise
save(:validate => false)
end
# Unlock a user by cleaning locked_at and failed_attempts.
# Unlock a user by cleaning locket_at and failed_attempts.
def unlock_access!
self.locked_at = nil
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
@@ -91,12 +80,15 @@ module Devise
unlock_access! if lock_expired?
if super && !access_locked?
self.failed_attempts = 0
save(:validate => false)
true
else
self.failed_attempts ||= 0
self.failed_attempts += 1
if attempts_exceeded?
lock_access! unless access_locked?
return :locked
else
save(:validate => false)
end
@@ -104,14 +96,6 @@ module Devise
end
end
def unauthenticated_message
if lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
:locked
else
super
end
end
protected
def attempts_exceeded?
@@ -149,9 +133,9 @@ module Devise
# with an email not found error.
# Options must contain the user email
def send_unlock_instructions(attributes={})
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
lockable.resend_unlock_token if lockable.persisted?
lockable
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
lockable.resend_unlock_token if lockable.persisted?
lockable
end
# Find a user by its unlock token and try to unlock it.

View File

@@ -15,10 +15,6 @@ 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,10 +24,6 @@ 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,10 +5,6 @@ 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.
#
# * +rememberable_options+: configuration options passed to the created cookie.
# * +cookie_options+: configuration options passed to the created cookie.
#
# == Examples
#
@@ -41,10 +41,6 @@ module Devise
attr_accessor :remember_me, :extend_remember_period
def self.required_fields(klass)
[:remember_created_at]
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)
@@ -75,7 +71,7 @@ module Devise
def rememberable_value
if respond_to?(:remember_token)
remember_token
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
elsif salt = authenticatable_salt
salt
else
raise "authenticable_salt returned nil for the #{self.class.name} model. " \
@@ -91,7 +87,7 @@ module Devise
protected
def generate_remember_token? #:nodoc:
def generate_remember_token?
respond_to?(:remember_token) && remember_expired?
end
@@ -114,7 +110,7 @@ module Devise
end
# Generate a token checking if one does not already exist in the database.
def remember_token #:nodoc:
def remember_token
generate_token(:remember_token)
end

View File

@@ -20,10 +20,6 @@ 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,10 +27,6 @@ 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
@@ -56,10 +52,6 @@ module Devise
def after_token_authentication
end
def expire_auth_token_on_timeout
self.class.expire_auth_token_on_timeout
end
module ClassMethods
def find_for_token_authentication(conditions)
find_for_authentication(:authentication_token => conditions[token_authentication_key])
@@ -70,7 +62,7 @@ module Devise
generate_token(:authentication_token)
end
Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)
::Devise::Models.config(self, :token_authentication_key)
end
end
end

View File

@@ -11,10 +11,6 @@ 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,10 +17,6 @@ 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

@@ -10,6 +10,7 @@ Devise.with_options :model => true do |d|
end
# Other authentications
d.add_module :encryptable
d.add_module :omniauthable, :controller => :omniauth_callbacks, :route => :omniauth_callback
# Misc after

View File

@@ -1,3 +1,44 @@
require 'orm_adapter/adapters/active_record'
ActiveRecord::Base.extend Devise::Models
module Devise
module Orm
# This module contains some helpers and handle schema (migrations):
#
# create_table :accounts do |t|
# t.database_authenticatable
# t.confirmable
# t.recoverable
# t.rememberable
# t.trackable
# t.lockable
# t.timestamps
# end
#
# However this method does not add indexes. If you need them, here is the declaration:
#
# add_index "accounts", ["email"], :name => "email", :unique => true
# add_index "accounts", ["confirmation_token"], :name => "confirmation_token", :unique => true
# add_index "accounts", ["reset_password_token"], :name => "reset_password_token", :unique => true
#
module ActiveRecord
module Schema
include Devise::Schema
# Tell how to apply schema methods.
def apply_devise_schema(name, type, options={})
@__devise_warning_raised ||= begin
$stderr.puts "\n[DEVISE] You are using t.database_authenticatable and others in your migration " \
"and this feature is deprecated. Please simply use Rails helpers instead as mentioned here:\n" \
"https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0-migration-schema-style\n\n"
true
end
column name, type.to_s.downcase.to_sym, options
end
end
end
end
end
ActiveRecord::Base.extend Devise::Models
ActiveRecord::ConnectionAdapters::Table.send :include, Devise::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise::Orm::ActiveRecord::Schema

View File

@@ -1,3 +1,31 @@
require 'orm_adapter/adapters/mongoid'
Mongoid::Document::ClassMethods.send :include, Devise::Models
module Devise
module Orm
module Mongoid
module Hook
def devise_modules_hook!
extend Schema
yield
return unless Devise.apply_schema
devise_modules.each { |m| send(m) if respond_to?(m, true) }
end
end
module Schema
include Devise::Schema
# Tell how to apply schema methods
def apply_devise_schema(name, type, options={})
type = Time if type == DateTime
field name, { :type => type }.merge!(options)
end
end
end
end
end
Mongoid::Document::ClassMethods.class_eval do
include Devise::Models
include Devise::Orm::Mongoid::Hook
end

View File

@@ -33,9 +33,8 @@ module Devise
private
# Determine which values should be transformed to string or passed as-is to the query builder underneath
def param_requires_string_conversion?(value)
[Fixnum, TrueClass, FalseClass, Regexp].none? {|clz| value.is_a? clz }
true
end
end
end

View File

@@ -43,12 +43,69 @@ module Devise
end
initializer "devise.fix_routes_proxy_missing_respond_to_bug" do
# We can get rid of this once we support only Rails > 3.2
# We can get rid of this once we support Rails > 3.2
ActionDispatch::Routing::RoutesProxy.class_eval do
def respond_to?(method, include_private = false)
super || routes.url_helpers.respond_to?(method)
end
end
end
initializer "devise.deprecations" do
unless defined?(Rails::Generators)
if Devise.case_insensitive_keys == false
warn "\n[DEVISE] Devise.case_insensitive_keys is false which is no longer " \
"supported. Recent Devise versions automatically downcase the e-mail before " \
"saving it to the database but your app isn't using this feature. You can solve " \
"this issue by either:\n\n" \
"1) Setting config.case_insensitive_keys = [:email] in your Devise initializer and " \
"running a migration that will downcase all emails already in the database;\n\n" \
"2) Setting config.case_insensitive_keys = [] (so nothing will be downcased) and " \
"making sure you are not using Devise :validatable (since validatable assumes case" \
"insensitivity)\n"
end
if Devise.apply_schema && defined?(Mongoid)
warn "\n[DEVISE] Devise.apply_schema is true. This means Devise was " \
"automatically configuring your DB. This no longer happens. You should " \
"set Devise.apply_schema to false and manually set the fields used by Devise as shown here: " \
"https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0-migration-schema-style\n"
end
# TODO: Deprecate the true value of this option as well
if Devise.use_salt_as_remember_token == false
warn "\n[DEVISE] Devise.use_salt_as_remember_token is false which is no longer " \
"supported. Devise now only uses the salt as remember token and the remember_token " \
"column can be removed from your models.\n"
end
if Devise.reset_password_within.nil?
warn "\n[DEVISE] Devise.reset_password_within is nil. Please set this value to " \
"an interval (for example, 6.hours) and add a reset_password_sent_at field to " \
"your Devise models (if they don't have one already).\n"
end
end
config.after_initialize do
example = <<-YAML
en:
devise:
registrations:
signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'
YAML
if I18n.t(:"devise.registrations.reasons", :default => {}).present?
warn "\n[DEVISE] devise.registrations.reasons in yml files is deprecated, " \
"please use devise.registrations.signed_up_but_REASON instead. The default values are:\n\n#{example}\n"
end
if I18n.t(:"devise.registrations.inactive_signed_up", :default => "").present?
warn "\n[DEVISE] devise.registrations.inactive_signed_up in yml files is deprecated, " \
"please use devise.registrations.signed_up_but_REASON instead. The default values are:\n\n#{example}\n"
end
end
end
end
end

View File

@@ -136,7 +136,7 @@ module ActionDispatch::Routing
#
# devise_for :users, :format => false
#
# * :constraints => works the same as Rails' constraints
# * :constraints => works the same as Rails' contraints
#
# * :defaults => works the same as Rails' defaults
#
@@ -184,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_scope :owner do
# devise_for :owners, :controllers => { :registrations => "registrations" } do
# post "deactivate", :to => "registrations#deactivate", :as => "deactivate_registration"
# end
#
@@ -198,8 +198,7 @@ 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] || {}
options[:options][:format] = false if options[:format] == false
options[:options] = (@scope[:options] || {}).merge({:format => false}) if options[:format] == false
resources.map!(&:to_sym)

View File

@@ -21,23 +21,17 @@ class Warden::SessionSerializer
end
def deserialize(keys)
klass_name, *args = keys
klass, *args = keys
begin
klass = ActiveSupport::Inflector.constantize(klass_name)
if klass.respond_to? :serialize_from_session
klass.serialize_from_session(*args)
else
Rails.logger.warn "[Devise] Stored serialized class #{klass_name} seems not to be Devise enabled anymore. Did you do that on purpose?"
nil
end
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_name}"
Rails.logger.debug "[Devise] Trying to deserialize invalid class #{klass}"
nil
else
raise
end
end
end
end
end

109
lib/devise/schema.rb Normal file
View File

@@ -0,0 +1,109 @@
module Devise
# Holds devise schema information. To use it, just include its methods
# and overwrite the apply_schema method.
module Schema
# Creates encrypted_password, and email when it is used as an authentication
# key (default).
#
# == Options
# * :null - When true, allow columns to be null.
# * :default - Set to "" when :null is false, unless overridden.
#
# == Notes
# For Datamapper compatibility, we explicitly hardcode the limit for the
# encrypter password field in 128 characters.
def database_authenticatable(options={})
null = options[:null] || false
default = options.key?(:default) ? options[:default] : ("" if null == false)
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 when using encryptors other
# than the database_authenticable default of bcrypt.
def encryptable
apply_devise_schema :password_salt, String
end
# Creates authentication_token.
def token_authenticatable
apply_devise_schema :authentication_token, String
end
# Creates confirmation_token, confirmed_at and confirmation_sent_at.
def confirmable
apply_devise_schema :confirmation_token, String
apply_devise_schema :confirmed_at, DateTime
apply_devise_schema :confirmation_sent_at, DateTime
end
# Creates unconfirmed_email
def reconfirmable
apply_devise_schema :unconfirmed_email, String
end
# 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.
#
# == Options
# * :use_salt - When true, does not create a remember_token and use password_salt instead.
def rememberable(options={})
use_salt = options.fetch(:use_salt, Devise.use_salt_as_remember_token)
apply_devise_schema :remember_token, String unless use_salt
apply_devise_schema :remember_created_at, DateTime
end
# Creates sign_in_count, current_sign_in_at, last_sign_in_at,
# current_sign_in_ip, last_sign_in_ip.
def trackable
apply_devise_schema :sign_in_count, Integer, :default => 0
apply_devise_schema :current_sign_in_at, DateTime
apply_devise_schema :last_sign_in_at, DateTime
apply_devise_schema :current_sign_in_ip, String
apply_devise_schema :last_sign_in_ip, String
end
# Creates failed_attempts, unlock_token and locked_at depending on the options given.
#
# == Options
# * :unlock_strategy - The strategy used for unlock. Can be :time, :email, :both (default), :none.
# If :email or :both, creates a unlock_token field.
# * :lock_strategy - The strategy used for locking. Can be :failed_attempts (default) or :none.
def lockable(options={})
unlock_strategy = options[:unlock_strategy]
unlock_strategy ||= self.unlock_strategy if respond_to?(:unlock_strategy)
unlock_strategy ||= :both
lock_strategy = options[:lock_strategy]
lock_strategy ||= self.lock_strategy if respond_to?(:lock_strategy)
lock_strategy ||= :failed_attempts
if lock_strategy == :failed_attempts
apply_devise_schema :failed_attempts, Integer, :default => 0
end
if [:both, :email].include?(unlock_strategy)
apply_devise_schema :unlock_token, String
end
apply_devise_schema :locked_at, DateTime
end
# Overwrite with specific modification to create your own schema.
def apply_devise_schema(name, type, options={})
raise NotImplementedError
end
end
end

View File

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

View File

@@ -1,4 +1,4 @@
require 'devise/strategies/authenticatable'
require 'devise/strategies/base'
module Devise
module Strategies

View File

@@ -70,61 +70,22 @@ module Devise
def _catch_warden(&block)
result = catch(:warden, &block)
env = @controller.request.env
if result.is_a?(Hash) && !warden.custom_failure? && !@controller.send(:performed?)
result[:action] ||= :unauthenticated
result ||= {}
# Set the response. In production, the rack result is returned
# from Warden::Manager#call, which the following is modelled on.
case result
when Array
if result.first == 401 && intercept_401?(env) # does this happen during testing?
_process_unauthenticated(env)
else
result
end
when Hash
_process_unauthenticated(env, result)
else
result
end
end
def _process_unauthenticated(env, options = {})
options[:action] ||= :unauthenticated
proxy = env['warden']
result = options[:result] || proxy.result
ret = case result
when :redirect
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
[proxy.status, proxy.headers, [body]]
when :custom
proxy.custom_response
else
env["PATH_INFO"] = "/#{options[:action]}"
env["warden.options"] = options
Warden::Manager._run_callbacks(:before_failure, env, options)
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 # causes process return @response
end
# ensure that the controller response is set up. In production, this is
# not necessary since warden returns the results to rack. However, at
# testing time, we want the response to be available to the testing
# framework to verify what would be returned to rack.
if ret.is_a?(Array)
# ensure the controller response is set to our response.
@controller.response ||= @response
@response.status = ret.first
@response.headers = ret.second
@response.body = ret.third
nil
else
result
end
ret
end
end
end

View File

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

View File

@@ -22,17 +22,10 @@ module ActiveRecord
end
def inject_devise_content
content = model_contents + <<CONTENT
inject_into_class(model_path, class_name, model_contents + <<CONTENT) if model_exists?
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
CONTENT
class_path = class_name.to_s.split("::")
indent_depth = class_path.size - 1
content = content.split("\n").map { |line| " " * indent_depth + line } .join("\n") << "\n"
inject_into_class(model_path, class_path.last, content) if model_exists?
end
def migration_data
@@ -55,6 +48,9 @@ CONTENT
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Encryptable
# t.string :password_salt
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at

View File

@@ -4,8 +4,7 @@ module Devise
def model_contents
<<-CONTENT
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

View File

@@ -39,18 +39,6 @@ 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__)
@@ -92,12 +80,15 @@ 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."
argument :scope, :required => false, :default => nil,
:desc => "The scope to copy views to"
def copy_views
copy_file "_links.erb", "#{target_path}/_links.erb"
end
invoke SharedViewsGenerator
hook_for :form_builder, :aliases => "-b",
:desc => "Form builder to be used",
:default => defined?(SimpleForm) ? "simple_form_for" : "form_for"

View File

@@ -37,6 +37,9 @@ module Mongoid
field :current_sign_in_ip, :type => String
field :last_sign_in_ip, :type => String
## Encryptable
# field :password_salt, :type => String
## Confirmable
# field :confirmation_token, :type => String
# field :confirmed_at, :type => Time

View File

@@ -9,6 +9,9 @@ Devise.setup do |config|
# Configure the class responsible to send e-mails.
# config.mailer = "Devise::Mailer"
# Automatically apply schema changes in tableless databases
config.apply_schema = false
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
@@ -92,7 +95,7 @@ Devise.setup do |config|
# the user cannot access the website without confirming his account.
# config.allow_unconfirmed_access_for = 2.days
# If true, requires any email changes to be confirmed (exactly the same way as
# If true, requires any email changes to be confirmed (exctly the same way as
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field (see migrations). Until confirmed new email is stored in
# unconfirmed email column, and copied to email column on successful confirmation.
@@ -108,9 +111,13 @@ Devise.setup do |config|
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
# If true, uses the password salt as remember token. This should be turned
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
# Options to be passed to the created cookie. For instance, you can set
# :secure => true in order to force SSL only cookies.
# config.rememberable_options = {}
# config.cookie_options = {}
# ==> Configuration for :validatable
# Range for password length. Default is 6..128.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,62 +0,0 @@
require 'test_helper'
require 'ostruct'
require 'warden/strategies/base'
require 'devise/test_helpers'
class CustomStrategyController < ActionController::Base
def new
warden.authenticate!(:custom_strategy)
end
end
# These tests are to prove that a warden strategy can successfully
# return a custom response, including a specific status code and
# custom http response headers. This does work in production,
# however, at the time of writing this, the Devise test helpers do
# not recognise the custom response and proceed to calling the
# Failure App. This makes it impossible to write tests for a
# strategy that return a custom response with Devise.
class CustomStrategy < Warden::Strategies::Base
def authenticate!
custom_headers = { "X-FOO" => "BAR" }
response = Rack::Response.new("BAD REQUEST", 400, custom_headers)
custom! response.finish
end
end
class CustomStrategyTest < ActionController::TestCase
tests CustomStrategyController
include Devise::TestHelpers
setup do
Warden::Strategies.add(:custom_strategy, CustomStrategy)
end
teardown do
Warden::Strategies._strategies.delete(:custom_strategy)
end
test "custom strategy can return its own status code" do
ret = get :new
# check the returned rack array
assert ret.is_a?(Array)
assert_equal 400, ret.first
# check the saved response as well. This is purely so that the response is available to the testing framework
# for verification. In production, the above array would be delivered directly to Rack.
assert_response 400
end
test "custom strategy can return custom headers" do
ret = get :new
# check the returned rack array
assert ret.is_a?(Array)
assert_equal ret.third['X-FOO'], 'BAR'
# check the saved response headers as well.
assert_equal response.headers['X-FOO'], 'BAR'
end
end

View File

@@ -33,13 +33,6 @@ class HelpersTest < ActionController::TestCase
assert_equal user, @controller.instance_variable_get(:@user)
end
test 'get resource params from request params using resource name as key' do
user_params = {'name' => 'Shirley Templar'}
@controller.stubs(:params).returns(HashWithIndifferentAccess.new({'user' => user_params}))
assert_equal user_params, @controller.resource_params
end
test 'resources methods are not controller actions' do
assert @controller.class.action_methods.empty?
end

View File

@@ -13,24 +13,4 @@ class SessionsControllerTest < ActionController::TestCase
assert_equal 200, @response.status
assert_template "devise/sessions/new"
end
if defined?(ActiveRecord)
if ActiveRecord::Base.respond_to?(:mass_assignment_sanitizer)
test "#new doesn't raise mass-assignment exception even if sign-in key is attr_protected" do
request.env["devise.mapping"] = Devise.mappings[:user]
ActiveRecord::Base.mass_assignment_sanitizer = :strict
User.class_eval { attr_protected :email }
begin
assert_nothing_raised ActiveModel::MassAssignmentSecurity::Error do
get :new, :user => { :email => "allez viens!" }
end
ensure
ActiveRecord::Base.mass_assignment_sanitizer = :logger
User.class_eval { attr_accessible :email }
end
end
end
end
end
end

30
test/encryptors_test.rb Normal file
View File

@@ -0,0 +1,30 @@
require 'test_helper'
class Encryptors < ActiveSupport::TestCase
test 'should match a password created by authlogic' do
authlogic = "b623c3bc9c775b0eb8edb218a382453396fec4146422853e66ecc4b6bc32d7162ee42074dcb5f180a770dc38b5df15812f09bbf497a4a1b95fe5e7d2b8eb7eb4"
encryptor = Devise::Encryptors::AuthlogicSha512.digest('123mudar', 20, 'usZK_z_EAaF61Gwkw-ed', '')
assert_equal authlogic, encryptor
end
test 'should match a password created by restful_authentication' do
restful_authentication = "93110f71309ce91366375ea44e2a6f5cc73fa8d4"
encryptor = Devise::Encryptors::RestfulAuthenticationSha1.digest('123mudar', 10, '48901d2b247a54088acb7f8ea3e695e50fe6791b', 'fee9a51ec0a28d11be380ca6dee6b4b760c1a3bf')
assert_equal restful_authentication, encryptor
end
test 'should match a password created by clearance' do
clearance = "0f40bbae18ddefd7066276c3ef209d40729b0378"
encryptor = Devise::Encryptors::ClearanceSha1.digest('123mudar', nil, '65c58472c207c829f28c68619d3e3aefed18ab3f', nil)
assert_equal clearance, encryptor
end
Devise::ENCRYPTORS_LENGTH.each do |key, value|
test "should have length #{value} for #{key.inspect}" do
swap Devise, :encryptor => key do
encryptor = Devise::Encryptors.const_get(key.to_s.classify)
assert_equal value, encryptor.digest('a', 4, encryptor.salt(4), nil).size
end
end
end
end

View File

@@ -29,20 +29,20 @@ class FailureTest < ActiveSupport::TestCase
end
context 'When redirecting' do
test 'returns to the default redirect location' do
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 'returns to the default redirect location for wildcard requests' do
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 'returns to the root path if no session path is available' do
test 'return to the root path if no session path is available' do
swap Devise, :router_name => :fake_app do
call_failure :app => RootFailureApp
assert_equal 302, @response.first
@@ -51,16 +51,6 @@ class FailureTest < ActiveSupport::TestCase
end
end
if Rails.application.config.respond_to?(:relative_url_root)
test 'returns to the default redirect location considering the relative url root' do
swap Rails.application.config, :relative_url_root => "/sample" do
call_failure
assert_equal 302, @response.first
assert_equal 'http://test.host/sample/users/sign_in', @response.second['Location']
end
end
end
test 'uses the proxy failure message as symbol' do
call_failure('warden' => OpenStruct.new(:message => :invalid))
assert_equal 'Invalid email or password.', @request.flash[:alert]

View File

@@ -34,36 +34,4 @@ if DEVISE_ORM == :active_record
assert_no_migration "db/migrate/devise_create_monsters.rb"
end
end
module RailsEngine
class Engine < Rails::Engine
isolate_namespace RailsEngine
end
end
def simulate_inside_engine(engine, namespace)
if Rails::Generators.respond_to?(:namespace=)
swap Rails::Generators, :namespace => namespace do
yield
end
else
swap Rails, :application => engine.instance do
yield
end
end
end
class ActiveRecordEngineGeneratorTest < Rails::Generators::TestCase
tests ActiveRecord::Generators::DeviseGenerator
destination File.expand_path("../../tmp", __FILE__)
setup :prepare_destination
test "all files are properly created" do
simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
run_generator ["monster"]
assert_file "app/models/rails_engine/monster.rb", /devise/,/attr_accessible (:[a-z_]+(, )?)+/
end
end
end
end

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

@@ -461,14 +461,14 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
test 'sign out with xml format returns ok response' do
sign_in_as_user
get destroy_user_session_path(:format => 'xml')
assert_response :no_content
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 :no_content
assert_response :ok
assert_not warden.authenticated?(:user)
end
end

View File

@@ -180,7 +180,7 @@ class ConfirmationTest < ActionController::IntegrationTest
fill_in 'email', :with => user.email
click_button 'Resend confirmation instructions'
assert_contain "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes."
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
@@ -196,7 +196,7 @@ class ConfirmationTest < ActionController::IntegrationTest
assert_not_contain "1 error prohibited this user from being saved:"
assert_not_contain "Email not found"
assert_contain "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes."
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

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 authenticate you from Facebook because "Access denied".'
assert_contain 'Could not authorize 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 authenticate you from Facebook because "Invalid credentials".'
assert_contain 'Could not authorize you from Facebook because "Invalid credentials".'
end
end

View File

@@ -195,15 +195,6 @@ class PasswordTest < ActionController::IntegrationTest
assert !warden.authenticated?(:user)
end
test 'sign in user automatically and confirm after changing its password if it\'s not confirmed' do
user = create_user(:confirm => false)
request_forgot_password
reset_password :reset_password_token => user.reload.reset_password_token
assert warden.authenticated?(:user)
assert user.reload.confirmed?
end
test 'reset password request with valid E-Mail in XML format should return valid response' do
create_user
post user_password_path(:format => 'xml'), :user => {:email => "user@test.com"}
@@ -268,7 +259,7 @@ class PasswordTest < ActionController::IntegrationTest
assert_not_contain "1 error prohibited this user from being saved:"
assert_not_contain "Email not found"
assert_contain "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
assert_contain "If your e-mail exists on our database, you will receive a password recovery link on your e-mail"
assert_current_url "/users/sign_in"
end
end
@@ -280,21 +271,8 @@ class PasswordTest < ActionController::IntegrationTest
fill_in 'email', :with => user.email
click_button 'Send me reset password instructions'
assert_contain "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
assert_contain "If your e-mail exists on our database, you will receive a password recovery link on your e-mail"
assert_current_url "/users/sign_in"
end
end
test "after recovering a password, should set failed attempts to 0" do
user = create_user
user.update_attribute(:failed_attempts, 10)
assert_equal 10, user.failed_attempts
request_forgot_password
reset_password :reset_password_token => user.reload.reset_password_token
assert warden.authenticated?(:user)
user.reload
assert_equal 0, user.failed_attempts
end
end

View File

@@ -100,19 +100,6 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
end
end
test 'should reset token and not authenticate when expire_auth_token_on_timeout is set to true, timeoutable is enabled and we have a timed out session' do
swap Devise, :token_authentication_key => :secret_token, :expire_auth_token_on_timeout => true, :timeout_in => (-1).minute do
user = sign_in_as_new_user_with_token
assert warden.authenticated?(:user)
token = user.authentication_token
get_users_path_as_existing_user(user)
assert_not warden.authenticated?(:user)
user.reload
assert_not_equal token, user.authentication_token
end
end
test 'should not be subject to injection' do
swap Devise, :token_authentication_key => :secret_token do
user1 = create_user_with_authentication_token()

View File

@@ -1,7 +1,9 @@
require 'test_helper'
class AuthenticatableTest < ActiveSupport::TestCase
test 'required_fields should be an empty array' do
assert_equal Devise::Models::Validatable.required_fields(User), []
test 'find_first_by_auth_conditions allows custom filtering parameters' do
user = User.create!(:email => "example@example.com", :password => "123456")
assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }), user
assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }, :id => user.id + 1), nil
end
end
end

View File

@@ -252,15 +252,6 @@ 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!
@@ -337,21 +328,4 @@ 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 '
@@ -23,15 +23,9 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
end
test "param filter should not convert booleans and integer to strings" do
conditions = { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
conditions = { "login" => "foo@bar.com", "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
conditions = Devise::ParamFilter.new([], []).filter(conditions)
assert_equal( { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => "1..10" }, conditions)
end
test "param filter should not convert regular expressions to strings" do
conditions = { "regexp" => /expression/ }
conditions = Devise::ParamFilter.new([], []).filter(conditions)
assert_equal( { "regexp" => /expression/ }, conditions)
assert_equal( { "login" => "foo@bar.com", "bool1" => "true", "bool2" => "false", "fixnum" => "123", "will_be_converted" => "1..10" }, conditions)
end
test 'should respond to password and password confirmation' do
@@ -92,14 +86,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 +145,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,20 +164,4 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
user = User.create(:email => "HEllO@example.com", :password => "123456")
assert !user.valid?
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
end

View File

@@ -0,0 +1,67 @@
require 'test_helper'
class EncryptableTest < ActiveSupport::TestCase
def encrypt_password(admin, pepper=Admin.pepper, stretches=Admin.stretches, encryptor=Admin.encryptor_class)
encryptor.digest('123456', stretches, admin.password_salt, pepper)
end
def swap_with_encryptor(klass, encryptor, options={})
klass.instance_variable_set(:@encryptor_class, nil)
swap klass, options.merge(:encryptor => encryptor) do
begin
yield
ensure
klass.instance_variable_set(:@encryptor_class, nil)
end
end
end
test 'should generate salt while setting password' do
assert_present create_admin.password_salt
end
test 'should not change password salt when updating' do
admin = create_admin
salt = admin.password_salt
admin.expects(:password_salt=).never
admin.save!
assert_equal salt, admin.password_salt
end
test 'should generate a base64 hash using SecureRandom for password salt' do
swap_with_encryptor Admin, :sha1 do
SecureRandom.expects(:base64).with(15).returns('01lI').twice
salt = create_admin.password_salt
assert_not_equal '01lI', salt
assert_equal 4, salt.size
end
end
test 'should not generate salt if password is blank' do
assert_blank create_admin(:password => nil).password_salt
assert_blank create_admin(:password => '').password_salt
end
test 'should encrypt password again if password has changed' do
admin = create_admin
encrypted_password = admin.encrypted_password
admin.password = admin.password_confirmation = 'new_password'
admin.save!
assert_not_equal encrypted_password, admin.encrypted_password
end
test 'should respect encryptor configuration' do
swap_with_encryptor Admin, :sha512 do
admin = create_admin
assert_equal admin.encrypted_password, encrypt_password(admin, Admin.pepper, Admin.stretches, ::Devise::Encryptors::Sha512)
end
end
test 'should not validate password when salt is nil' do
admin = create_admin
admin.password_salt = nil
admin.save
assert_not admin.valid_password?('123456')
end
end

View File

@@ -14,6 +14,15 @@ class LockableTest < ActiveSupport::TestCase
end
end
test "should clear failed_attempts on successfull validation" do
user = create_user
user.confirm!
user.valid_for_authentication?{ false }
assert_equal 1, user.reload.failed_attempts
user.valid_for_authentication?{ true }
assert_equal 0, user.reload.failed_attempts
end
test "should increment failed_attempts on successfull validation if the user is already locked" do
user = create_user
user.confirm!
@@ -226,38 +235,4 @@ 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

@@ -1,7 +0,0 @@
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,11 +195,4 @@ class RecoverableTest < ActiveSupport::TestCase
assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
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
end

View File

@@ -1,7 +0,0 @@
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,10 +165,4 @@ 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
]
end
end

View File

@@ -39,8 +39,4 @@ 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,10 +46,4 @@ 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,13 +1,5 @@
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,13 +105,9 @@ class ValidatableTest < ActiveSupport::TestCase
assert_equal 'is too long (maximum is 128 characters)', user.errors[:password].join
end
test 'should not be included in objects with invalid API' do
test 'shuold 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

@@ -1,7 +1,7 @@
require 'test_helper'
class Configurable < User
devise :database_authenticatable, :confirmable, :rememberable, :timeoutable, :lockable,
devise :database_authenticatable, :encryptable, :confirmable, :rememberable, :timeoutable, :lockable,
:stretches => 15, :pepper => 'abcdef', :allow_unconfirmed_access_for => 5.days,
:remember_for => 7.days, :timeout_in => 15.minutes, :unlock_in => 10.days
end
@@ -39,7 +39,7 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
test 'can cherry pick modules' do
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :confirmable
assert_include_modules Admin, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable, :confirmable
end
test 'validations options are not applied too late' do
@@ -55,12 +55,12 @@ class ActiveRecordTest < ActiveSupport::TestCase
end
test 'chosen modules are inheritable' do
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :confirmable
assert_include_modules Inheritable, :database_authenticatable, :registerable, :timeoutable, :recoverable, :lockable, :encryptable, :confirmable
end
test 'order of module inclusion' do
correct_module_order = [:database_authenticatable, :recoverable, :registerable, :confirmable, :lockable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :confirmable]
correct_module_order = [:database_authenticatable, :encryptable, :recoverable, :registerable, :confirmable, :lockable, :timeoutable]
incorrect_module_order = [:database_authenticatable, :timeoutable, :registerable, :recoverable, :lockable, :encryptable, :confirmable]
assert_include_modules Admin, *incorrect_module_order
@@ -107,73 +107,3 @@ 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

@@ -22,6 +22,9 @@ class Admin
field :confirmation_sent_at, :type => Time
field :unconfirmed_email, :type => String # Only if using reconfirmable
## Encryptable
field :password_salt, :type => String
## Lockable
field :locked_at, :type => Time
end

Some files were not shown because too many files have changed in this diff Show More