Skip to content

Commit

Permalink
Release v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
binarylogic committed Mar 30, 2009
1 parent 83cb915 commit 83f05ca
Show file tree
Hide file tree
Showing 35 changed files with 1,402 additions and 23 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rdoc
@@ -0,0 +1,3 @@
== 1.0.0

* Initial release
2 changes: 0 additions & 2 deletions README.rdoc
Expand Up @@ -2,8 +2,6 @@

Authlogic OpenID is an extension of the Authlogic library to add OpenID support. Authlogic v2.0 introduced an enhanced API that makes "plugging in" alternate authentication methods as easy as installing a gem.

**DISCLAIMER**: This library is in it's beta stage. It is working properly in my sample application, and I have yet to encounter a problem with it, but I still need to write some tests and document the code. The only reason I released this in its current state is because some people have been waiting to use it.

== Install and use

=== 1. Make some simple changes to your database:
Expand Down
4 changes: 2 additions & 2 deletions Rakefile
Expand Up @@ -4,7 +4,7 @@ require "rubygems"
require "hoe"
require File.dirname(__FILE__) << "/lib/authlogic_openid/version"

Hoe.new("Authlogic OpenID", AuthlogicOpenId::Version::STRING) do |p|
Hoe.new("Authlogic OpenID", AuthlogicOpenid::Version::STRING) do |p|
p.name = "authlogic-oid"
p.author = "Ben Johnson of Binary Logic"
p.email = 'bjohnson@binarylogic.com'
Expand All @@ -14,6 +14,6 @@ Hoe.new("Authlogic OpenID", AuthlogicOpenId::Version::STRING) do |p|
p.history_file = "CHANGELOG.rdoc"
p.readme_file = "README.rdoc"
p.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc"]
p.test_globs = ["test/*/test_*.rb", "test/*/*_test.rb"]
p.test_globs = ["test/*/test_*.rb", "test/*_test.rb", "test/*/*_test.rb"]
p.extra_deps = %w(authlogic)
end
3 changes: 1 addition & 2 deletions init.rb
@@ -1,2 +1 @@
require "authlogic"
require "authlogic_openid"
require "authlogic_openid"
32 changes: 25 additions & 7 deletions lib/authlogic_openid/acts_as_authentic.rb
@@ -1,5 +1,11 @@
# This module is responsible for adding OpenID functionality to Authlogic. Checkout the README for more info and please
# see the sub modules for detailed documentation.
module AuthlogicOpenid
# This module is responsible for adding in the OpenID functionality to your models. It hooks itself into the
# acts_as_authentic method provided by Authlogic.
module ActsAsAuthentic
# Adds in the neccesary modules for acts_as_authentic to include and also disabled password validation if
# OpenID is being used.
def self.included(klass)
klass.class_eval do
add_acts_as_authentic_module(Methods)
Expand All @@ -10,22 +16,34 @@ def self.included(klass)
end

module Methods
# Set up some simple validations
def self.included(klass)
klass.class_eval do
validates_uniqueness_of :openid_identifier, :scope => validations_scope, :if => :using_openid?
validate :validate_openid
end
end

# Set the openid_identifier field and also resets the persistence_token if this value changes.
def openid_identifier=(value)
write_attribute(:openid_identifier, value.blank? ? nil : OpenIdAuthentication.normalize_identifier(value))
reset_persistence_token if openid_identifier_changed?
rescue OpenIdAuthentication::InvalidOpenId => e
@openid_error = e.message
end

def save(*args, &block)
if !authenticate_with_openid? || (authenticate_with_openid? && authenticate_with_openid)
# This is where all of the magic happens. This is where we hook in and add all of the OpenID sweetness.
#
# I had to take this approach because when authenticating with OpenID nonces and what not are stored in database
# tables. That being said, the whole save process for ActiveRecord is wrapped in a transaction. Trying to authenticate
# with OpenID in a transaction is not good because that transaction be get rolled back, thus reversing all of the OpenID
# inserts and making OpenID authentication fail every time. So We need to step outside of the transaction and do our OpenID
# madness.
#
# Another advantage of taking this approach is that we can set fields from their OpenID profile before we save the record,
# if their OpenID provider supports it.
def save(perform_validation = true, &block)
if !perform_validation || !authenticate_with_openid? || (authenticate_with_openid? && authenticate_with_openid)
result = super
yield(result) if block_given?
result
Expand Down Expand Up @@ -60,7 +78,7 @@ def authenticate_with_openid
if result.unsuccessful?
@openid_error = result.message
else
map_openid_fields(registration)
map_openid_registration(registration)
end

return true
Expand All @@ -69,10 +87,10 @@ def authenticate_with_openid
return false
end

def map_openid_fields(registration)
self.name = registration[:fullname] if respond_to?(:name) && !registration[:fullname].blank?
self.first_name = registration[:fullname].split(" ").first if respond_to?(:first_name) && !registration[:fullname].blank?
self.first_name = registration[:fullname].split(" ").last if respond_to?(:last_name) && !registration[:last_name].blank?
def map_openid_registration(registration)
self.name ||= registration[:fullname] if respond_to?(:name) && !registration[:fullname].blank?
self.first_name ||= registration[:fullname].split(" ").first if respond_to?(:first_name) && !registration[:fullname].blank?
self.first_name ||= registration[:fullname].split(" ").last if respond_to?(:last_name) && !registration[:last_name].blank?
end

def validate_openid
Expand Down
22 changes: 20 additions & 2 deletions lib/authlogic_openid/session.rb
@@ -1,19 +1,33 @@
module AuthlogicOpenid
# This module is responsible for adding all of the OpenID goodness to the Authlogic::Session::Base class.
module Session
# Add a simple openid_identifier attribute and some validations for the field.
def self.included(klass)
klass.class_eval do
attr_accessor :openid_identifier
attr_reader :openid_identifier
validate :validate_openid_error
validate :validate_by_openid, :if => :authenticating_with_openid?
end
end


# Hooks into credentials so that you can pass an :openid_identifier key.
def credentials=(value)
super
values = value.is_a?(Array) ? value : [value]
hash = values.first.is_a?(Hash) ? values.first.with_indifferent_access : nil
self.openid_identifier = hash[:openid_identifier] if !hash.nil? && hash.key?(:openid_identifier)
end

def openid_identifier=(value)
@openid_identifier = value.blank? ? nil : OpenIdAuthentication.normalize_identifier(value)
@openid_error = nil
rescue OpenIdAuthentication::InvalidOpenId => e
@openid_identifier = nil
@openid_error = e.message
end

# Cleaers out the block if we are authenticating with OpenID, so that we can redirect without a DoubleRender
# error.
def save(&block)
block = nil if !openid_identifier.blank?
super(&block)
Expand All @@ -39,5 +53,9 @@ def validate_by_openid
end
end
end

def validate_openid_error
errors.add(:openid_identifier, @openid_error) if @openid_error
end
end
end
11 changes: 3 additions & 8 deletions lib/authlogic_openid/version.rb
@@ -1,11 +1,8 @@
module AuthlogicOpenid # :nodoc:
# = Version
#
module AuthlogicOpenid
# A class for describing the current version of a library. The version
# consists of three parts: the +major+ number, the +minor+ number, and the
# +tiny+ (or +patch+) number.
class Version

include Comparable

# A convenience method for instantiating a new Version instance with the
Expand Down Expand Up @@ -42,15 +39,13 @@ def to_a
[@major, @minor, @tiny]
end

MAJOR = 0
MAJOR = 1
MINOR = 0
TINY = 9
TINY = 0

# The current version as a Version instance
CURRENT = new(MAJOR, MINOR, TINY)
# The current version as a String
STRING = CURRENT.to_s

end

end
90 changes: 90 additions & 0 deletions test/acts_as_authentic_test.rb
@@ -0,0 +1,90 @@
require File.dirname(__FILE__) + '/test_helper.rb'

class ActsAsAuthenticTest < ActiveSupport::TestCase
def test_included
assert User.send(:acts_as_authentic_modules).include?(AuthlogicOpenid::ActsAsAuthentic::Methods)
assert_equal :validate_password_with_openid?, User.validates_length_of_password_field_options[:if]
assert_equal :validate_password_with_openid?, User.validates_confirmation_of_password_field_options[:if]
assert_equal :validate_password_with_openid?, User.validates_length_of_password_confirmation_field_options[:if]
end

def test_password_not_required_on_create
user = User.new
user.login = "sweet"
user.email = "a@a.com"
user.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
assert !user.save # because we are redirecting, the user was NOT saved
assert redirecting_to_yahoo?
end

def test_password_required_on_create
user = User.new
user.login = "sweet"
user.email = "a@a.com"
assert !user.save
assert user.errors.on(:password)
assert user.errors.on(:password_confirmation)
end

def test_password_not_required_on_update
ben = users(:ben)
assert_nil ben.crypted_password
assert ben.save
end

def test_password__required_on_update
ben = users(:ben)
ben.openid_identifier = nil
assert_nil ben.crypted_password
assert !ben.save
assert ben.errors.on(:password)
assert ben.errors.on(:password_confirmation)
end

def test_validates_uniqueness_of_openid_identifier
u = User.new(:openid_identifier => "bens_identifier")
assert !u.valid?
assert u.errors.on(:openid_identifier)
end

def test_setting_openid_identifier_changed_persistence_token
ben = users(:ben)
old_persistence_token = ben.persistence_token
ben.openid_identifier = "new"
assert_not_equal old_persistence_token, ben.persistence_token
end

def test_invalid_openid_identifier
u = User.new(:openid_identifier => "%")
assert !u.valid?
assert u.errors.on(:openid_identifier)
end

def test_blank_openid_identifer_gets_set_to_nil
u = User.new(:openid_identifier => "")
assert_nil u.openid_identifier
end

def test_updating_with_openid
ben = users(:ben)
ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
assert !ben.save # because we are redirecting
assert redirecting_to_yahoo?
end

def test_updating_without_openid
ben = users(:ben)
ben.openid_identifier = nil
ben.password = "test"
ben.password_confirmation = "test"
assert ben.save
assert !redirecting_to_yahoo?
end

def test_updating_without_validation
ben = users(:ben)
ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
assert ben.save(false)
assert !redirecting_to_yahoo?
end
end
9 changes: 9 additions & 0 deletions test/fixtures/users.yml
@@ -0,0 +1,9 @@
ben:
login: bjohnson
persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
single_access_token: <%= Authlogic::Random.friendly_token %>
perishable_token: <%= Authlogic::Random.friendly_token %>
openid_identifier: bens_identifier
email: bjohnson@binarylogic.com
first_name: Ben
last_name: Johnson
35 changes: 35 additions & 0 deletions test/libs/open_id_authentication/CHANGELOG
@@ -0,0 +1,35 @@
* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek]

* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek]

* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler]

* Add Timeout protection [Rick]

* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block.

* Allow a return_to option to be used instead of the requested url [Josh Peek]

* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek]

* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH]

* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb]

* Allow -'s in #normalize_url [Rick]

* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick]

* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH]

* Just use the path for the return URL, so extra query parameters don't interfere [DHH]

* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH]

* Added normalize_url and applied it to all operations going through the plugin [DHH]

* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH]

* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH]

* Stop relying on root_url being defined, we can just grab the current url instead [DHH]

0 comments on commit 83f05ca

Please sign in to comment.