Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 54f632c38ffad8f02b02761111ea21e2f6ece9cb @binarylogic committed Mar 23, 2009
7 .gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+*.log
+*.sqlite3
+pkg/*
+coverage/*
+doc/*
+benchmarks/*
0 CHANGELOG.rdoc
No changes.
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Ben Johnson of Binary Logic (binarylogic.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 Manifest.txt
No changes.
86 README.rdoc
@@ -0,0 +1,86 @@
+= Authlogic OpenID
+
+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:
+
+ class AddUsersOpenidField < ActiveRecord::Migration
+ def self.up
+ add_column :users, :openid_identifier, :string
+ add_index :users, :openid_identifier
+
+ change_column :users, :login, :string, :default => nil, :null => true
+ change_column :users, :crypted_password, :string, :default => nil, :null => true
+ change_column :users, :password_salt, :string, :default => nil, :null => true
+ end
+
+ def self.down
+ remove_column :users, :openid_identifier
+
+ [:login, :crypted_password, :password_salt].each do |field|
+ User.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
+ change_column :users, field, :string, :default => "", :null => false
+ end
+ end
+ end
+
+=== 2. Install the openid_authentication plugin
+
+ script/plugin install git://github.com/rails/open_id_authentication.git
+
+=== 3. Install the Authlogic Openid gem
+
+ sudo gem install authlogic-oid
+
+Now add the gem dependency in your config:
+
+ config.gem "authlogic-oid", :lib => "authlogic_openid"
+
+Or for older version of rails, install it as a plugin:
+
+ script/plugin install git://github.com/binarylogic/authlogic_openid.git
+
+=== 4. Make sure you save your objects properly
+
+You only need to save your objects this way if you want the user to authenticate with their OpenID provider.
+
+That being said, you probably want to do this in your controllers. You should do this for BOTH your User objects and UserSession objects (assuming you are authenticating users). It should look something like this:
+
+ @user_session.save do |result|
+ if result
+ flash[:notice] = "Login successful!"
+ redirect_back_or_default account_url
+ else
+ render :action => :new
+ end
+ end
+
+You should save your @user objects this way as well, because you also want the user to verify that they own the OpenID identifier that they supplied.
+
+Notice we are saving with a block. Why? Because we need to redirect the user to their OpenID provider so that they can authenticate. When we do this, we don't want to execute that block of code, because if we do, we will get a DoubleRender error. This lets us skip that entire block and send the user along their way without any problems.
+
+That's it! The rest is taken care of for you.
+
+== Redirecting from the models?
+
+If you are interested, I explain myself below. Regardless, you don't have to use this library. As you saw in the setup instructions, this library leverages the open_id_authentication rails plugin. You can EASILY use this in your controllers and do your traditional OpenID authentication yourself. After the user has been authenticated just do this:
+
+ UserSession.create(@user)
+
+It's that simple. For more information there is a great OpenID tutorial at: http://railscasts.com/episodes/68-openid-authentication
+
+Now, here are my thoughts on the subject:
+
+You are probably thinking: "Ben, you can't handle controller responsibilities in models". I would agree with you on that comment, because my personal opinion is that these are not controller responsibilities. The fact that OpenID authentication requires a redirect should not effect the location of the logic / code. It's all part of the authentication process, which is the entire purpose of this library. The logic that handles this process should be in it's own domain, which is the definition of the "M" in MVC. The "M" doesn't have to just be a data access layer, it's a place for domain logic.
+
+What if you wanted to authenticate with OpenID in multiple controllers in your application? You would probably pull out the common code into a module and include it in the respective controllers. Even better, you might create a class that elegantly handles this process and then place it in your lib directory. That's exactly what this is.
+
+The last thing I will leave you with, to get you thinking, is... where do sweepers lie in the MVC pattern?
+
+Regardless, if I still haven't convinced you, I hope this library is of some benefit to you. At the very least an example of how to extend Authlogic.
+
+Copyright (c) 2009 Ben Johnson of [Binary Logic](http://www.binarylogic.com), released under the MIT license
19 Rakefile
@@ -0,0 +1,19 @@
+ENV['RDOCOPT'] = "-S -f html -T hanna"
+
+require "rubygems"
+require "hoe"
+require File.dirname(__FILE__) << "/lib/authlogic_openid/version"
+
+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'
+ p.summary = "Extension of the Authlogic library to add OpenID support."
+ p.description = "Extension of the Authlogic library to add OpenID support."
+ p.url = "http://github.com/binarylogic/authlogic_openid"
+ 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.extra_deps = %w(authlogic)
+end
2 init.rb
@@ -0,0 +1,2 @@
+require "authlogic"
+require "authlogic_openid"
6 lib/authlogic_openid.rb
@@ -0,0 +1,6 @@
+require "authlogic_openid/version"
+require "authlogic_openid/acts_as_authentic"
+require "authlogic_openid/session"
+
+ActiveRecord::Base.send(:include, AuthlogicOpenid::ActsAsAuthentic)
+Authlogic::Session::Base.send(:include, AuthlogicOpenid::Session)
86 lib/authlogic_openid/acts_as_authentic.rb
@@ -0,0 +1,86 @@
+module AuthlogicOpenid
+ module ActsAsAuthentic
+ def self.included(klass)
+ klass.class_eval do
+ add_acts_as_authentic_module(Methods)
+ end
+ end
+
+ module Methods
+ def self.included(klass)
+ klass.class_eval do
+ alias_method_chain :save, :openid
+ #validates_uniqueness_of :openid_identifier, :scope => validations_scope, :if => :using_openid?
+ validate :validate_openid
+ [:validates_length_of_login_field_options, :validates_format_of_login_field_options,
+ :validates_confirmation_of_password_field_options, :validates_length_of_password_confirmation_field_options].each do |method|
+ send(method, send(method).merge(:unless => :using_openid?))
+ end
+ end
+ end
+
+ def save_with_openid(*args, &block)
+ normalize_openid_identifier if using_openid?
+ if !authenticate_with_openid? || (authenticate_with_openid? && authenticate_with_openid)
+ result = save_without_openid(*args)
+ yield(result) if block_given?
+ result
+ else
+ false
+ end
+ end
+
+ private
+ def normalize_openid_identifier
+ begin
+ self.openid_identifier = OpenIdAuthentication.normalize_identifier(openid_identifier)
+ rescue Exception
+ end
+ end
+
+ def authenticate_with_openid
+ @openid_error = nil
+
+ if !openid_complete?
+ attrs_to_persist = attributes.delete_if do |k, v|
+ [:password, crypted_password_field, password_salt_field, :persistence_token, :perishable_token, :single_access_token, :login_count,
+ :failed_login_count, :last_request_at, :current_login_at, :last_login_at, :current_login_ip, :last_login_ip, :created_at,
+ :updated_at, :lock_version].include?(k.to_sym)
+ end
+ attrs_to_persist.merge!(:password => password, :password_confirmation => password_confirmation)
+ session_class.controller.session[:openid_attributes] = attrs_to_persist
+ else
+ self.attributes = session_class.controller.session[:openid_attributes]
+ session_class.controller.session[:openid_attributes] = nil
+ end
+
+ session_class.controller.send(:authenticate_with_open_id, openid_identifier, :return_to => session_class.controller.url_for(:for_model => "1")) do |result, openid_identifier|
+ @openid_error = result.message if result.unsuccessful?
+ return true
+ end
+
+ return false
+ end
+
+ def validate_openid
+ errors.add(:openid_identifier, "had the following error: #{@openid_error}") if @openid_error
+ end
+
+ def using_openid?
+ !openid_identifier.blank?
+ end
+
+ def openid_complete?
+ session_class.controller.params[:open_id_complete] && session_class.controller.params[:for_model]
+ end
+
+ def authenticate_with_openid?
+ session_class.activated? && ((using_openid? && openid_identifier_changed?) || openid_complete?)
+ end
+
+ def redirecting_to_openid?
+ @redirecting_to_openid == true
+ end
+ end
+ end
+end
43 lib/authlogic_openid/session.rb
@@ -0,0 +1,43 @@
+module AuthlogicOpenid
+ module Session
+ def self.included(klass)
+ klass.class_eval do
+ attr_accessor :openid_identifier
+ validate :validate_by_openid, :if => :authenticating_with_openid?
+ end
+ end
+
+ 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 save(&block)
+ block = nil if !openid_identifier.blank?
+ super(&block)
+ end
+
+ private
+ def authenticating_with_openid?
+ !openid_identifier.blank? || (controller.params[:open_id_complete] && controller.params[:for_session])
+ end
+
+ def validate_by_openid
+ controller.send(:authenticate_with_open_id, openid_identifier, :return_to => controller.url_for(:for_session => "1")) do |result, openid_identifier|
+ if result.unsuccessful?
+ errors.add_to_base(result.message)
+ return
+ end
+
+ self.attempted_record = klass.find_by_openid_identifier(openid_identifier)
+
+ if !attempted_record
+ errors.add(:openid_identifier, "did not match any users in our database, have you set up your account to use OpenID?")
+ return
+ end
+ end
+ end
+ end
+end
56 lib/authlogic_openid/version.rb
@@ -0,0 +1,56 @@
+module AuthlogicOpenid # :nodoc:
+ # = Version
+ #
+ # 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
+ # given +major+, +minor+, and +tiny+ components.
+ def self.[](major, minor, tiny)
+ new(major, minor, tiny)
+ end
+
+ attr_reader :major, :minor, :tiny
+
+ # Create a new Version object with the given components.
+ def initialize(major, minor, tiny)
+ @major, @minor, @tiny = major, minor, tiny
+ end
+
+ # Compare this version to the given +version+ object.
+ def <=>(version)
+ to_i <=> version.to_i
+ end
+
+ # Converts this version object to a string, where each of the three
+ # version components are joined by the '.' character. E.g., 2.0.0.
+ def to_s
+ @to_s ||= [@major, @minor, @tiny].join(".")
+ end
+
+ # Converts this version to a canonical integer that may be compared
+ # against other version objects.
+ def to_i
+ @to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny
+ end
+
+ def to_a
+ [@major, @minor, @tiny]
+ end
+
+ MAJOR = 0
+ MINOR = 0
+ TINY = 9
+
+ # The current version as a Version instance
+ CURRENT = new(MAJOR, MINOR, TINY)
+ # The current version as a String
+ STRING = CURRENT.to_s
+
+ end
+
+end

0 comments on commit 54f632c

Please sign in to comment.
Something went wrong with that request. Please try again.