Compare commits

...

27 Commits

Author SHA1 Message Date
José Valim
d36e1012f8 Release 1.0.4 with a couple bug fixes. 2010-03-03 12:24:29 +01:00
Lucas de Castro
5d187ff278 Fixing session controllers when within namespaces
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-03 12:16:24 +01:00
Cyril Mougel
a0220243c3 fix spec failed with mongo_mapper DEVISE_ORM
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:44:08 +01:00
José Valim
4c10f86e74 Do not forget frozen records.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:35:07 +01:00
Lucas Uyezu
cf66e935a9 SQLite requries a default value when the column is NOT NULL
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-25 08:34:47 +01:00
José Valim
fbe485f3df Update warden which fixes a security issue. 2010-02-23 19:52:53 +01:00
José Valim
545462e964 Bump to 1.0.3. 2010-02-23 15:45:07 +01:00
José Valim
42df192df8 Do not remove options from MongoMapper find. 2010-02-23 15:41:52 +01:00
Andre Arko
7f451ed9cc Add rails/init.rb to the gemspec
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 18:06:38 +01:00
Daniel Jagszent
27fe3023ae renamed init.rb -> rails/init.rb. So that rails can find and initalize the GemPlugin even without a config.gem "devise" line in environment.rb (for using with bundler)
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 17:10:03 +01:00
Paul Campbell
41d416a18e add paragraphs to html emails
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-19 10:18:00 +01:00
José Valim
c36cd84c31 Returns the proper response body based on the rquest for 401. 2010-02-18 19:52:37 +01:00
José Valim
fd96335d05 Autoload Devise::Models. 2010-02-18 07:22:26 +01:00
José Valim
23568bda82 Bump to 1.0.2. 2010-02-17 21:30:54 +01:00
José Valim
ee7f5270fc Uses the same content type as request on http authenticatable 401 responses 2010-02-17 21:25:31 +01:00
José Valim
f294700723 Update test files. 2010-02-17 21:15:11 +01:00
Glenn Roberts
c86ce298dc add content type test, update config doc
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-17 21:13:27 +01:00
Glenn Roberts
b0ff0d46dd add content_type config parameter
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-17 21:13:16 +01:00
José Valim
187ef5c452 Update README. 2010-02-17 13:56:00 +01:00
Paul Campbell
6d29bcc467 Add mention of flash[:notice] and flash[:alert] 2010-02-15 22:29:23 +08:00
José Valim
ee87ec398a Updated gemspec. 2010-02-15 14:23:00 +01:00
José Valim
3e37fe8d4d Bump to 1.0.1 2010-02-15 14:19:08 +01:00
José Valim
48a94cdece Avoid mass assignment error messages with current password. 2010-02-15 14:17:12 +01:00
José Valim
bdacffab58 Make HttpAuthenticatable opt-in. 2010-02-15 14:11:33 +01:00
José Valim
085b12a710 Add registerable to defaults. 2010-02-15 14:06:50 +01:00
Carlos Antonio da Silva
3435c53725 Fix typo: autoload Clearance encryptor and not Authlogic one. 2010-02-12 13:02:11 -02:00
Carlos Antonio da Silva
01dec7fc78 README and TODO minor updates. 2010-02-12 01:54:47 -02:00
30 changed files with 179 additions and 75 deletions

View File

@@ -1,3 +1,32 @@
== 1.0.4
* bug fix
* Fixed a bug when deleting an account with rememberable
* Fixed a bug with custom controllers
== 1.0.3
* enhancements
* HTML e-mails now have proper formatting
* Do not remove MongoMapper options in find
== 1.0.2
* enhancements
* Allows you set mailer content type (by github.com/glennr)
* bug fix
* Uses the same content type as request on http authenticatable 401 responses
== 1.0.1
* enhancements
* HttpAuthenticatable is not added by default automatically.
* Avoid mass assignment error messages with current password.
* bug fix
* Fixed encryptors autoload
== 1.0.0
* deprecation
@@ -8,6 +37,7 @@
* Added Http Basic Authentication support
* Allow scoped_views to be customized per controller/mailer class
* [#99] Allow authenticatable to used in change_table statements
* Add mailer_content_type configuration parameter (by github.com/glennr)
== 0.9.2

View File

@@ -7,16 +7,18 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
* Allows you to have multiple roles (or models/scopes) signed in at the same time;
* Is based on a modularity concept: use just what you really need.
Right now it's composed of ten modules:
Right now it's composed of 12 modules:
* Authenticatable: responsible for encrypting password and validating authenticity of a user while signing in.
* Token Authenticatable: validates authenticity of a user while signing in using an authentication token (also known as "single access token").
* HttpAuthenticatable: sign in users using basic HTTP authentication.
* Confirmable: responsible for verifying whether an account is already confirmed to sign in, and to send emails with confirmation instructions.
* Recoverable: takes care of reseting the user password and send reset instructions.
* Registerable: handles signing up users through a registration process.
* Rememberable: manages generating and clearing token for remember the user from a saved cookie.
* Trackable: tracks sign in count, timestamps and ip.
* Validatable: creates all needed validations for email and password. It's totally optional, so you're able to to customize validations by yourself.
* Timeoutable: expires sessions without activity in a certain period of time.
* Validatable: creates all needed validations for email and password. It's totally optional, so you're able to to customize validations by yourself.
* Lockable: takes care of locking an account based on the number of failed sign in attempts. Handles unlock via expire and email.
* Activatable: if you need to activate accounts by other means, which are not through confirmation, use this module.
@@ -28,17 +30,13 @@ Devise is based on Warden (http://github.com/hassox/warden), a Rack Authenticati
== Installation
All gems are on gemcutter, so you need to add gemcutter to your sources if you haven't yet:
sudo gem sources -a http://gemcutter.org/
Install warden gem if you don't have it installed (requires 0.6.4 or higher):
Install warden gem if you don't have it installed:
sudo gem install warden
Install devise gem:
sudo gem install devise
sudo gem install devise --version=1.0.1
Configure warden and devise gems inside your app:
@@ -53,6 +51,10 @@ And you're ready to go. The generator will install an initializer which describe
http://rdoc.info/projects/plataformatec/devise
If you want to use Devise with bundler on Rails 2.3, you need to follow the instructions here:
http://github.com/carlhuda/bundler/issues/issue/83
== Basic Usage
This is a walkthrough with all steps you need to setup a devise resource, including model, migration, route files, and optional configuration. You MUST also check out the *Generators* section below to help you start.
@@ -175,6 +177,8 @@ By default Devise will use the same views for all roles you have. But what if yo
After doing so you will be able to have views based on the scope like 'sessions/users/new' and 'sessions/admin/new'. If no view is found within the scope, Devise will fallback to the default view.
Devise uses flash messages to let users know if their login is successful or not. Devise expects your application to call 'flash[:notice]' and 'flash[:alert]' as appropriate.
== I18n
Devise uses flash messages with I18n with the flash keys :success and :failure. To customize your app, you can setup your locale file this way:

View File

@@ -43,8 +43,8 @@ begin
s.homepage = "http://github.com/plataformatec/devise"
s.description = "Flexible authentication solution for Rails with Warden"
s.authors = ['José Valim', 'Carlos Antônio']
s.files = FileList["[A-Z]*", "{app,config,generators,lib}/**/*", "init.rb"]
s.add_dependency("warden", "~> 0.9.0")
s.files = FileList["[A-Z]*", "{app,config,generators,lib}/**/*", "rails/init.rb"]
s.add_dependency("warden", "~> 0.9.4")
end
Jeweler::GemcutterTasks.new

3
TODO
View File

@@ -1,3 +1,2 @@
* Make test run with DataMapper
* Add Registerable support
* Extract Activatable tests from Confirmable
* Extract Activatable tests from Confirmable

View File

@@ -27,7 +27,7 @@ class DeviseMailer < ::ActionMailer::Base
from mailer_sender(mapping)
recipients record.email
sent_on Time.now
content_type 'text/html'
content_type Devise.mailer_content_type
body render_with_scope(key, mapping, mapping.name => record, :resource => record)
end

View File

@@ -1,5 +1,5 @@
Welcome <%= @resource.email %>!
<p>Welcome <%= @resource.email %>!</p>
You can confirm your account through the link below:
<p>You can confirm your account through the link below:</p>
<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>

View File

@@ -1,8 +1,8 @@
Hello <%= @resource.email %>!
<p>Hello <%= @resource.email %>!</p>
Someone has requested a link to change your password, and you can do this through the link below.
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

View File

@@ -1,7 +1,7 @@
Hello <%= @resource.email %>!
<p>Hello <%= @resource.email %>!</p>
Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
Click the link below to unlock your account:
<p>Click the link below to unlock your account:</p>
<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>

View File

@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{devise}
s.version = "1.0.0"
s.version = "1.0.4"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jos\303\251 Valim", "Carlos Ant\303\264nio"]
s.date = %q{2010-02-09}
s.date = %q{2010-03-03}
s.description = %q{Flexible authentication solution for Rails with Warden}
s.email = %q{contact@plataformatec.com.br}
s.extra_rdoc_files = [
@@ -50,7 +50,6 @@ Gem::Specification.new do |s|
"generators/devise_install/templates/devise.rb",
"generators/devise_views/USAGE",
"generators/devise_views/devise_views_generator.rb",
"init.rb",
"lib/devise.rb",
"lib/devise/controllers/helpers.rb",
"lib/devise/controllers/internal_helpers.rb",
@@ -73,6 +72,7 @@ Gem::Specification.new do |s|
"lib/devise/models/activatable.rb",
"lib/devise/models/authenticatable.rb",
"lib/devise/models/confirmable.rb",
"lib/devise/models/http_authenticatable.rb",
"lib/devise/models/lockable.rb",
"lib/devise/models/recoverable.rb",
"lib/devise/models/registerable.rb",
@@ -94,7 +94,8 @@ Gem::Specification.new do |s|
"lib/devise/strategies/rememberable.rb",
"lib/devise/strategies/token_authenticatable.rb",
"lib/devise/test_helpers.rb",
"lib/devise/version.rb"
"lib/devise/version.rb",
"rails/init.rb"
]
s.homepage = %q{http://github.com/plataformatec/devise}
s.rdoc_options = ["--charset=UTF-8"]
@@ -167,12 +168,12 @@ Gem::Specification.new do |s|
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<warden>, ["~> 0.9.0"])
s.add_runtime_dependency(%q<warden>, ["~> 0.9.4"])
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
s.add_dependency(%q<warden>, ["~> 0.9.4"])
end
else
s.add_dependency(%q<warden>, ["~> 0.9.0"])
s.add_dependency(%q<warden>, ["~> 0.9.4"])
end
end

View File

@@ -1,7 +1,8 @@
class <%= class_name %> < ActiveRecord::Base
# Include default devise modules.
# Others available are :lockable, :timeoutable and :activatable.
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
# Include default devise modules. Others available are:
# :http_authenticatable, :token_authenticatable, :lockable, :timeoutable and :activatable
devise :registerable, :authenticatable, :confirmable, :recoverable,
:rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation

View File

@@ -3,6 +3,9 @@
Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me@config-initializers-devise.com"
# Configure the content type of DeviseMailer mails (defaults to text/html")
# config.mailer_content_type = "text/plain"
# ==> Configuration for :authenticatable
# Invoke `rake secret` and use the printed value to setup a pepper to generate

View File

@@ -1,5 +1,6 @@
module Devise
autoload :FailureApp, 'devise/failure_app'
autoload :Models, 'devise/models'
autoload :Schema, 'devise/schema'
autoload :TestHelpers, 'devise/test_helpers'
@@ -13,7 +14,7 @@ module Devise
autoload :Base, 'devise/encryptors/base'
autoload :Bcrypt, 'devise/encryptors/bcrypt'
autoload :AuthlogicSha512, 'devise/encryptors/authlogic_sha512'
autoload :AuthlogicSha1, 'devise/encryptors/authlogic_sha1'
autoload :ClearanceSha1, 'devise/encryptors/clearance_sha1'
autoload :RestfulAuthenticationSha1, 'devise/encryptors/restful_authentication_sha1'
autoload :Sha512, 'devise/encryptors/sha512'
autoload :Sha1, 'devise/encryptors/sha1'
@@ -28,7 +29,7 @@ module Devise
ALL = []
# Authentication ones first
ALL.push :authenticatable, :token_authenticatable, :rememberable
ALL.push :authenticatable, :http_authenticatable, :token_authenticatable, :rememberable
# Misc after
ALL.push :recoverable, :registerable, :validatable
@@ -144,7 +145,11 @@ module Devise
# Address which sends Devise e-mails.
mattr_accessor :mailer_sender
@@mailer_sender = nil
@@mailer_sender = nil
# Content Type of Devise e-mails.
mattr_accessor :mailer_content_type
@@mailer_content_type = 'text/html'
# Authentication token params key name of choice. E.g. /users/sign_in?some_key=...
mattr_accessor :token_authentication_key

View File

@@ -3,7 +3,7 @@
# that specific user and adds a cookie with this user info to sign in this user
# automatically without asking for credentials. Refer to rememberable strategy
# for more info.
Warden::Manager.after_authentication do |record, warden, options|
Warden::Manager.prepend_after_authentication do |record, warden, options|
scope = options[:scope]
remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
@@ -22,9 +22,11 @@ end
# Before logout hook to forget the user in the given scope, only if rememberable
# is activated for this scope. Also clear remember token to ensure the user
# won't be remembered again.
# Notice that we forget the user if the record is frozen. This usually means the
# user was just deleted.
Warden::Manager.before_logout do |record, warden, scope|
if record.respond_to?(:forget_me!)
record.forget_me!
record.forget_me! unless record.frozen?
warden.response.delete_cookie "remember_#{scope}_token"
end
end

View File

@@ -1,5 +1,4 @@
require 'devise/strategies/authenticatable'
require 'devise/strategies/http_authenticatable'
module Devise
module Models
@@ -87,11 +86,12 @@ module Devise
params.delete(:password) if params[:password].blank?
params.delete(:password_confirmation) if params[:password_confirmation].blank?
current_password = params.delete(:current_password)
result = if valid_password?(params[:current_password])
result = if valid_password?(current_password)
update_attributes(params)
else
message = params[:current_password].blank? ? :blank : :invalid
message = current_password.blank? ? :blank : :invalid
self.class.add_error_on(self, :current_password, message, false)
self.attributes = params
false
@@ -120,11 +120,6 @@ module Devise
resource if resource.try(:valid_for_authentication?, attributes)
end
# Authenticate an user using http.
def authenticate_with_http(username, password)
authenticate(authentication_keys.first => username, :password => password)
end
# Returns the class for the configured encryptor.
def encryptor_class
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
@@ -145,7 +140,6 @@ module Devise
def find_for_authentication(conditions)
find(:first, :conditions => conditions)
end
end
end
end

View File

@@ -0,0 +1,21 @@
require 'devise/strategies/http_authenticatable'
module Devise
module Models
# Adds HttpAuthenticatable behavior to your model. It expects that your
# model class responds to authenticate and authentication_keys methods
# (which for example are defined in authenticatable).
module HttpAuthenticatable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
# Authenticate an user using http.
def authenticate_with_http(username, password)
authenticate(authentication_keys.first => username, :password => password)
end
end
end
end
end

View File

@@ -3,7 +3,7 @@ require 'devise/strategies/token_authenticatable'
module Devise
module Models
# Token Authenticatable Module, responsible for generate authentication token and validating
# authenticity of a user while signing in using a authentication token (say follows an URL).
# authenticity of a user while signing in using an authentication token (say follows an URL).
#
# == Configuration:
#

View File

@@ -22,14 +22,11 @@ module Devise
end
def find(*args)
options = args.extract_options!
case args.first
when :first
first(options)
when :all
all(options)
else
super
when :first, :all
send(args.shift, *args)
else
super
end
end

View File

@@ -9,12 +9,13 @@ module Devise
# * :null - When true, allow columns to be null.
# * :encryptor - The encryptor going to be used, necessary for setting the proper encrypter password length.
def authenticatable(options={})
null = options[:null] || false
encryptor = options[:encryptor] || (respond_to?(:encryptor) ? self.encryptor : :sha1)
null = options[:null] || false
default = options[:default]
encryptor = options[:encryptor] || (respond_to?(:encryptor) ? self.encryptor : :sha1)
apply_schema :email, String, :null => null
apply_schema :encrypted_password, String, :null => null, :limit => Devise::ENCRYPTORS_LENGTH[encryptor]
apply_schema :password_salt, String, :null => null
apply_schema :email, String, :null => null, :default => default
apply_schema :encrypted_password, String, :null => null, :default => default, :limit => Devise::ENCRYPTORS_LENGTH[encryptor]
apply_schema :password_salt, String, :null => null, :default => default
end
# Creates authentication_token.

View File

@@ -23,7 +23,7 @@ module Devise
protected
def valid_controller?
params[:controller] == 'sessions'
params[:controller] =~ /sessions$/
end
def valid_params?

View File

@@ -14,7 +14,7 @@ module Devise
if resource = mapping.to.authenticate_with_http(username, password)
success!(resource)
else
custom!([401, custom_headers, ["HTTP Basic: Access denied.\n"]])
custom!([401, custom_headers, [response_body]])
end
end
@@ -24,6 +24,12 @@ module Devise
decode_credentials(request).split(/:/, 2)
end
def response_body
body = "HTTP Basic: Access denied."
method = :"to_#{request_format.to_sym}"
{}.respond_to?(method) ? { :error => body }.send(method) : body
end
def http_authentication
request.env['HTTP_AUTHORIZATION'] ||
request.env['X-HTTP_AUTHORIZATION'] ||
@@ -38,10 +44,14 @@ module Devise
def custom_headers
{
"Content-Type" => "text/plain",
"Content-Type" => request_format.to_s,
"WWW-Authenticate" => %(Basic realm="#{Devise.http_authentication_realm.gsub(/"/, "")}")
}
end
def request_format
@request_format ||= Mime::Type.lookup_by_extension(request.template_format.to_s)
end
end
end
end

View File

@@ -1,3 +1,3 @@
module Devise
VERSION = "1.0.0".freeze
VERSION = "1.0.4".freeze
end

View File

@@ -16,6 +16,14 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
end
test 'uses the request format as response content type' do
sign_in_as_new_user_with_http("unknown", "123456", :xml)
assert_equal 401, status
assert_equal "application/xml", headers["Content-Type"]
# Cannot assert this due to a bug between integration tests and rack on 2.3
# assert response.body.include?("<error>HTTP Basic: Access denied.</error>")
end
test 'returns a custom response with www-authenticate and chosen realm' do
swap Devise, :http_authentication_realm => "MyApp" do
sign_in_as_new_user_with_http("unknown")
@@ -36,9 +44,9 @@ class HttpAuthenticationTest < ActionController::IntegrationTest
private
def sign_in_as_new_user_with_http(username="user@test.com", password="123456")
def sign_in_as_new_user_with_http(username="user@test.com", password="123456", format=:html)
user = create_user
get users_path, {}, :authorization => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
get users_path(:format => format), {}, :authorization => "Basic #{ActiveSupport::Base64.encode64("#{username}:#{password}")}"
user
end
end

View File

@@ -28,6 +28,14 @@ class RememberMeTest < ActionController::IntegrationTest
assert warden.user(:user) == user
end
test 'does not remember other scopes' do
user = create_user_and_remember
get root_path
assert_response :success
assert warden.authenticated?(:user)
assert_not warden.authenticated?(:admin)
end
test 'do not remember with invalid token' do
user = create_user_and_remember('add')
get users_path

View File

@@ -63,6 +63,12 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
end
end
test 'content type should be set to plain when manually configured' do
swap Devise, :mailer_content_type => "text/plain" do
assert_equal "text/plain", mail.content_type
end
end
test 'renders a scoped if scoped_views is set in the mailer class' do
begin
DeviseMailer.scoped_views = true

View File

@@ -216,7 +216,7 @@ class ConfirmableTest < ActiveSupport::TestCase
Devise.confirm_within = 0.days
user = create_user
user.confirmation_sent_at = Date.today
assert_not user.active?
assert_not user.reload.active?
end
test 'should not be active without confirmation' do

View File

@@ -1,5 +1,5 @@
class User < ActiveRecord::Base
devise :authenticatable, :confirmable, :lockable, :recoverable,
devise :authenticatable, :http_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable

View File

@@ -1,9 +1,13 @@
class Admin
include MongoMapper::Document
devise :authenticatable, :timeoutable
devise :authenticatable, :registerable, :timeoutable
def self.find_for_authentication(conditions)
last(:conditions => conditions, :order => "email")
last(:conditions => conditions)
end
def self.last(options={})
options.merge!(:order => 'email')
super options
end
end

View File

@@ -1,7 +1,14 @@
class User
include MongoMapper::Document
key :created_at, DateTime
devise :authenticatable, :confirmable, :recoverable, :rememberable, :trackable,
:validatable, :timeoutable, :lockable, :token_authenticatable
devise :authenticatable, :http_authenticatable, :confirmable, :lockable, :recoverable,
:registerable, :rememberable, :timeoutable, :token_authenticatable,
:trackable, :validatable
# attr_accessible :username, :email, :password, :password_confirmation
def self.last(options={})
options.merge!(:order => 'email')
super options
end
end

View File

@@ -35,6 +35,9 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "please-change-me-omg@yourapp.com"
# Configure the content type of DeviseMailer mails (defaults to text/html")
# config.mailer_content_type = "text/plain"
# Load and configure the ORM. Supports :active_record, :data_mapper and :mongo_mapper.
require "devise/orm/#{DEVISE_ORM}"