Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Release v1.3.5

  • Loading branch information...
commit 6ddadfbfd82bde6ab6efa2ee515fd783250ad565 1 parent 72f3a21
@binarylogic authored
View
6 CHANGELOG.rdoc
@@ -1,7 +1,11 @@
-== 1.3.5 released 2008-11-24
+== 1.3.5 released 2008-11-30
* :transition_from_crypto_provider for acts_as_authentic now accepts an array to transition from multiple providers. Which solves the problem of a double transition.
* Added AES256 as a crypto_provider option, for those that want to use a reversible encryption method by supplying a key.
+* Fixed typo for using validates_format_of_options instead of validates_length_of_options
+* Fixed bug when accessing the dynamic method for accessing the session record in a namespace, since it uses class_name.underscore which replaces :: with a /
+* Added minimum length requirement of 4 for the password, and removed validates_presence_of for password since validates_length_of enforces this
+* Set before_validation to reset the persistence token if it is blank, since a password is not required for open id authentication
== 1.3.4 released 2008-11-24
View
32 README.rdoc
@@ -2,7 +2,7 @@
Authlogic is a clean, simple, and unobtrusive ruby authentication solution. Put simply, its the Chuck Norris of authentication solutions for your framework of choice.
-So what is Authlogic, and why would I create a solution to a problem that already has plenty of solutions? Because none of the solutions felt right to me, RESTful development and authentication just didn't seem to go well together. It was like trying to fit a square peg in a round hole. All of the current solutions, for both rails and merb, just seemed to force that square peg in the round hole for me. Just because they did it for me doesn't make it right. They were either too complicated, bloated, littered my application with tons of code, or were just confusing. This is not the simple / elegant ruby we all fell in love with. We need a "ruby like" authentication solution. Authlogic is my attempt to satisfy that need...
+So what is Authlogic, and why would I create a solution to a problem that already has plenty of solutions? Because none of the solutions felt right to me, RESTful development and authentication just didn't seem to go well together. It was like trying to fit a square peg in a round hole. All of the current solutions, for both rails and merb, just seemed to force that square peg in the round hole for me. Just because they did it for me doesn't make it right. They were either too complicated, bloated, littered my application with tons of code, had no platform for reasonable updating, used an inferior encryption algorithm, or were just confusing. This is not the simple / elegant ruby we all fell in love with. We need a "ruby like" authentication solution. Authlogic is my attempt to satisfy that need...
Let's take a rails application...
@@ -130,9 +130,7 @@ One thing to keep in mind here is that the default :crypto_provider for Authlogi
You are all set, now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this README or check out the tutorials (see above in "helpful links") for a more detailed walk through.
-== Migrating from restful_authentication
-
-This is for migrating an existing application from restful_authentication to Authlogic. If you are starting a new application, please ignore this section.
+== Migrating an existing app from restful_authentication and upgrading your encryption
For those that are switching existing apps over, I made an option especially for you. Just do the following and everything will be taken care of, your users won't even know anything changed:
@@ -141,13 +139,25 @@ For those that are switching existing apps over, I made an option especially for
acts_as_authentic :act_like_restful_authentication => true
end
-Or you can transition your users to the Authlogic password system:
+The above will not change a thing, from your database's perspective it will be as if you are still using restful_authentication.
+
+Or you can upgrade from Sha1 and transition your users to a much more secure encryption algorithm:
# app/models/user.rb
class User < ActiveRecord::Base
acts_as_authentic :transition_from_restful_authentication => true
end
+By default this will switch your users to Authlogic's Sha512 implementation. You do *NOT* have to use this. Check out the encryption methods section below for a list of encryption methods Authlogic provides you. If you want to use something besides Sha512 just specify it by doing:
+
+ # app/models/user.rb
+ class User < ActiveRecord::Base
+ acts_as_authentic :transition_from_restful_authentication => true,
+ :crypto_provider => Authlogic::CryptoProviders::BCrypt
+ end
+
+Every time a user logs in their password will be upgraded and every time a new account is created it will use the new algorithm all while allowing users to login with the old algorithm.
+
For more information checkout my blog post on this: http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic
== Magic Columns
@@ -272,11 +282,11 @@ There could be many more depending on your application. What's great about Authl
Here are the 3 tokens in more detail:
-=== 1. Persistence token
+=== 1. Persistence token (stored in cookie / session)
This token is used to persist the user's session. This is the token that is stored in the session and the cookie, so that during each request the user stays logged in. What's unique about this token is that the first time it is used the value is stored in the session, thus persisting the session. This field is required and must be in your database.
-=== 2. Single access token
+=== 2. Single access token (private feed access, etc.)
This token is used for single access only, it is not persisted. Meaning the user provides it, Authlogic grants them access, and that's it. If they want access again they need to provide the token again. Authlogic will *NEVER* store this value in the session or a cookie. For added security, by default this token is *ONLY* allowed for RSS and ATOM requests. Also, this token does *NOT* change with the password. Meaning if the user changes their password, this token will remain the same. Lastly, this token uses a "friendly" toke (see the URL example below) so that it is easier to email / copy and paste. You can change all of this with configuration (see Authlogic::Session::config), so if you don't like how this works by default, just set some simple configuration in your session.
@@ -293,7 +303,7 @@ The single_access_token parameter name is configurable (see Authlogic::Session::
For more information see: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::SingleAccess
-=== 3. Perishable token
+=== 3. Perishable token (resetting passwords, confirming accounts, etc)
This token is used for temporary account access, hence the term "perishable". This token is constantly changing, it changes...
@@ -445,7 +455,7 @@ From there it is pretty simple. When you try to create a new session the record
== What's wrong with the current solutions?
-You probably don't care, but I think releasing the millionth authentication solution for a framework that has been around for over 4 years requires a little explanation.
+You probably don't care, but I think releasing the millionth ruby authentication solution requires a little explanation.
I don't necessarily think the current solutions are "wrong", nor am I saying Authlogic is the answer to your prayers. But, to me, the current solutions were lacking something. Here's what I came up with...
@@ -459,6 +469,10 @@ Using a library that hundreds of other people use has it advantages. Probably on
Lastly, there is a pattern here, why clutter up all of your applications with the same code over and over?
+=== Security gets outdated
+
+Just as I stated in the above section, you can't stay up to date with your security since the code is generated and updating the plugin does nothing. If there is one thing you should stay up to date with, it's security. But it's not just the fact that there is no reasonable method for receiving updates. It's the fact that they tie you down to an encryption algorithm *AND* they use a bad one at that. Every single solution I've seen uses Sha1, which is joining the party with MD5. Sha1 is not as secure as it used to be. But that's the nature of algorithms, they eventually get phased out, which is fine. Everyone knows this, why not accommodate for this? Authlogic does this with the :transition_from_crypto_provider option. It takes care of transitioning all of your users to a new algorithm. Even better, it provides BCrypt as an option which should, in theory, never require you to switch since you can adjust the cost and make the encryption stronger. At the same time, still compatible with older passwords using the lower cost.
+
=== Why test the same code over and over?
I've noticed my apps get cluttered with authentication tests, and they are the same exact tests! This irritates me. When you have identical tests across your apps thats a red flag that code can be extracted into a library. What's great about Authlogic is that I tested it for you. You don't write tests that test the internals of ActiveRecord do you? The same applies for Authlogic. Only test code that you've written. Essentially testing authentication is similar to testing any another RESTful controller. This makes your tests focused and easier to understand.
View
2  lib/authlogic/crypto_providers/aes256.rb
@@ -30,6 +30,8 @@ def matches?(crypted, *tokens)
aes.decrypt
aes.key = @key
(aes.update(crypted.unpack("m").first) + aes.final) == tokens.join
+ rescue OpenSSL::CipherError
+ false
end
private
View
6 lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb
@@ -124,8 +124,8 @@ module ActsAsAuthentic
# * <tt>password_field_validation_options</tt> - default: {},
# The same as :validation_options but these are only applied to validations that pertain to the :password_field
#
- # * <tt>password_field_validates_presence_of_options</tt> - default: {:on => :create},
- # These options are applied to the validates_presence_of call for the :password_field
+ # * <tt>password_field_validates_length_of_options</tt> - default: {:minimum => 4},
+ # These options are applied to the validates_length_of call for the :password_field
#
# * <tt>login_field_validates_confirmation_of_options</tt> - default: {},
# These options are applied to the validates_confirmation_of call for the :password_field
@@ -187,7 +187,7 @@ def acts_as_authentic_with_config(options = {})
field_key = "#{field_name}_field_validation_options".to_sym
options[field_key] = options[:validation_options].merge(options[field_key] || {})
- validation_types = field_name == :password ? [:presence, :confirmation] : [:length, :format, :uniqueness]
+ validation_types = field_name == :password ? [:length, :confirmation] : [:length, :format, :uniqueness]
validation_types.each do |validation_type|
validation_key = "#{field_name}_field_validates_#{validation_type}_of_options".to_sym
options[validation_key] = options[field_key].merge(options[validation_key] || {})
View
12 lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb
@@ -30,7 +30,7 @@ def acts_as_authentic_with_credentials(options = {})
case options[:login_field_type]
when :email
validates_length_of options[:login_field], {:within => 6..100}.merge(options[:login_field_validates_length_of_options])
- validates_format_of options[:login_field], {:with => email_field_regex, :message => "should look like an email address."}.merge(options[:login_field_validates_length_of_options])
+ validates_format_of options[:login_field], {:with => email_field_regex, :message => "should look like an email address."}.merge(options[:login_field_validates_format_of_options])
else
validates_length_of options[:login_field], {:within => 2..100}.merge(options[:login_field_validates_length_of_options])
validates_format_of options[:login_field], {:with => /\A\w[\w\.\-_@ ]+\z/, :message => "should use only letters, numbers, spaces, and .-_@ please."}.merge(options[:login_field_validates_format_of_options])
@@ -40,9 +40,9 @@ def acts_as_authentic_with_credentials(options = {})
end
if options[:validate_password_field]
- validates_presence_of options[:password_field], {:on => :create}.merge(options[:password_field_validates_presence_of_options])
- validates_confirmation_of options[:password_field], options[:password_field_validates_confirmation_of_options].merge(:if => "#{options[:crypted_password_field]}_changed?".to_sym)
- validates_presence_of "#{options[:password_field]}_confirmation", :if => "#{options[:crypted_password_field]}_changed?"
+ validates_length_of options[:password_field], {:minimum => 4}.merge(options[:password_field_validates_length_of_options].merge(:if => "validate_#{options[:password_field]}?".to_sym))
+ validates_confirmation_of options[:password_field], options[:password_field_validates_confirmation_of_options].merge(:if => "validate_#{options[:password_field]}?".to_sym)
+ validates_presence_of "#{options[:password_field]}_confirmation", :if => "validate_#{options[:password_field]}?".to_sym
end
if options[:validate_email_field] && options[:email_field]
@@ -113,6 +113,10 @@ def reset_#{options[:password_field]}!
end
alias_method :randomize_password!, :reset_password!
+ def validate_#{options[:password_field]}?
+ new_record? || #{options[:crypted_password_field]}_changed?
+ end
+
private
def encrypt_arguments(raw_password, arguments_type = nil)
case arguments_type
View
18 lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb
@@ -22,7 +22,10 @@ module Persistence
def acts_as_authentic_with_persistence(options = {})
acts_as_authentic_without_persistence(options)
+ validates_presence_of options[:persistence_token_field]
validates_uniqueness_of options[:persistence_token_field], :if => "#{options[:persistence_token_field]}_changed?".to_sym
+
+ before_validation "reset_#{options[:persistence_token_field]}".to_sym, :if => "reset_#{options[:persistence_token_field]}?".to_sym
def forget_all!
# Paginate these to save on memory
@@ -46,10 +49,23 @@ def forget!
end
def #{options[:password_field]}_with_persistence=(value)
- self.#{options[:persistence_token_field]} = self.class.unique_token
+ reset_#{options[:persistence_token_field]}
self.#{options[:password_field]}_without_persistence = value
end
alias_method_chain :#{options[:password_field]}=, :persistence
+
+ def reset_#{options[:persistence_token_field]}
+ self.#{options[:persistence_token_field]} = self.class.unique_token
+ end
+
+ def reset_#{options[:persistence_token_field]}!
+ reset_#{options[:persistence_token_field]}
+ save_without_session_maintenance(false)
+ end
+
+ def reset_#{options[:persistence_token_field]}?
+ #{options[:persistence_token_field]}.blank?
+ end
end_eval
end
end
View
4 lib/authlogic/session/base.rb
@@ -203,7 +203,7 @@ def find_record
end
# Allows you to set a unique identifier for your session, so that you can have more than 1 session at a time. A good example when this might be needed is when you want to have a normal user session
- # and a "secure" user session. The secure user session would be created only when they want to modify their billing information, or other sensative information. Similar to me.com. This requires 2
+ # and a "secure" user session. The secure user session would be created only when they want to modify their billing information, or other sensitive information. Similar to me.com. This requires 2
# user sessions. Just use an id for the "secure" session and you should be good.
#
# You can set the id during initialization (see initialize for more information), or as an attribute:
@@ -357,7 +357,7 @@ def create_configurable_methods!
return if respond_to?(login_field) # already created these methods
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
- alias_method :#{klass_name.underscore}, :record
+ alias_method :#{klass_name.underscore.split("/").last}, :record
attr_reader :#{login_field}
View
2  lib/authlogic/version.rb
@@ -44,7 +44,7 @@ def to_a
MAJOR = 1
MINOR = 3
- TINY = 4
+ TINY = 5
# The current version as a Version instance
CURRENT = new(MAJOR, MINOR, TINY)
View
17 test/libs/aes128_crypto_provider.rb
@@ -1,17 +0,0 @@
-require "ezcrypto"
-
-class AES128CryptoProvider
- class << self
- def encrypt(*tokens)
- [key.encrypt(tokens.join)].pack("m").chomp
- end
-
- def matches?(crypted, *tokens)
- key.decrypt(crypted.unpack("m").first) == tokens.join
- end
-
- def key
- EzCrypto::Key.with_password "master_key", "some_salt"
- end
- end
-end
View
2  test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb
@@ -36,7 +36,7 @@ def test_acts_as_authentic_config
:validate_fields => true,
:login_field => :login,
:perishable_token_valid_for => 600,
- :password_field_validates_presence_of_options => {},
+ :password_field_validates_length_of_options => {},
:password_field => :password,
:validate_login_field => true,
:email_field => :email,
View
1  test/test_helper.rb
@@ -4,7 +4,6 @@
require "active_record"
require 'active_record/fixtures'
require File.dirname(__FILE__) + '/../lib/authlogic' unless defined?(Authlogic)
-require File.dirname(__FILE__) + '/libs/aes128_crypto_provider'
require File.dirname(__FILE__) + '/libs/mock_request'
require File.dirname(__FILE__) + '/libs/mock_cookie_jar'
require File.dirname(__FILE__) + '/libs/mock_controller'
Please sign in to comment.
Something went wrong with that request. Please try again.