Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 9103

Show
Ignore:
Timestamp:
03/27/08 23:26:52 (2 months ago)
Author:
josh
Message:

Updated OpenIdAuthentication to use Ruby OpenID 2.x.x gem (closes #10604) [Josh Peek]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • plugins/open_id_authentication/CHANGELOG

    r8872 r9103  
     1* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek] 
     2 
    13* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH] 
    24 
  • plugins/open_id_authentication/init.rb

    r8872 r9103  
    11begin 
    2   gem 'ruby-openid', '=1.1.4' 
    3   require 'openid'   
     2  require 'openid' 
    43rescue LoadError 
    5   puts "Install the ruby-openid gem to enable OpenID support" 
     4  begin 
     5    gem 'ruby-openid', '>=2.0.4' 
     6  rescue Gem::LoadError 
     7    puts "Install the ruby-openid gem to enable OpenID support" 
     8  end 
    69end 
    710 
  • plugins/open_id_authentication/lib/open_id_authentication.rb

    r8931 r9103  
    11require 'uri' 
     2require 'openid/extensions/sreg' 
     3require 'openid/store/filesystem' 
    24 
    35module OpenIdAuthentication 
    46  OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids" 
    5    
     7 
    68  def self.store 
    79    @@store 
    810  end 
    9    
     11 
    1012  def self.store=(value) 
    1113    @@store = value 
    1214  end 
    13    
     15 
    1416  self.store = :db 
    15    
     17 
    1618  def store 
    1719    OpenIdAuthentication.store 
     
    2325  class Result 
    2426    ERROR_MESSAGES = { 
    25       :missing    => "Sorry, the OpenID server couldn't be found", 
    26       :canceled   => "OpenID verification was canceled", 
    27       :failed     => "Sorry, the OpenID verification failed" 
     27      :missing      => "Sorry, the OpenID server couldn't be found", 
     28      :canceled     => "OpenID verification was canceled", 
     29      :failed       => "Sorry, the OpenID verification failed", 
     30      :setup_needed => "OpenID verification needs setup" 
    2831    } 
    29      
     32 
    3033    def self.[](code) 
    3134      new(code) 
    3235    end 
    33      
     36 
    3437    def initialize(code) 
    3538      @code = code 
    3639    end 
    37      
     40 
    3841    def ===(code) 
    3942      if code == :unsuccessful && unsuccessful? 
     
    4346      end 
    4447    end 
    45      
     48 
    4649    ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } } 
    4750 
     
    5356      ERROR_MESSAGES.keys.include?(@code) 
    5457    end 
    55      
     58 
    5659    def message 
    5760      ERROR_MESSAGES[@code] 
     
    6770    raise InvalidOpenId.new("#{url} is not an OpenID URL") 
    6871  end 
    69  
    7072 
    7173  protected 
     
    8890    end 
    8991 
    90  
    9192  private 
    9293    def begin_open_id_authentication(identity_url, fields = {}) 
    93       open_id_response = timeout_protection_from_identity_server { open_id_consumer.begin(identity_url) } 
     94      open_id_request = open_id_consumer.begin(identity_url) 
     95      add_simple_registration_fields(open_id_request, fields) 
     96      redirect_to(open_id_redirect_url(open_id_request)) 
     97    rescue OpenID::OpenIDError, Timeout::Error => e 
     98      logger.error("[OPENID] #{e}") 
     99      yield Result[:missing], identity_url, nil 
     100    end 
     101 
     102    def complete_open_id_authentication 
     103      params_with_path = params.reject { |key, value| request.path_parameters[key] } 
     104      open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) } 
     105      identity_url     = normalize_url(open_id_response.endpoint.claimed_id) if open_id_response.endpoint.claimed_id 
    94106 
    95107      case open_id_response.status 
    96       when OpenID::FAILURE 
    97         yield Result[:missing], identity_url, nil 
    98       when OpenID::SUCCESS 
    99         add_simple_registration_fields(open_id_response, fields) 
    100         redirect_to(open_id_redirect_url(open_id_response)) 
     108      when OpenID::Consumer::SUCCESS 
     109        yield Result[:successful], identity_url, OpenID::SReg::Response.from_success_response(open_id_response) 
     110      when OpenID::Consumer::CANCEL 
     111        yield Result[:canceled], identity_url, nil 
     112      when OpenID::Consumer::FAILURE 
     113        yield Result[:failed], identity_url, nil 
     114      when OpenID::Consumer::SETUP_NEEDED 
     115        yield Result[:setup_needed], open_id_response.setup_url, nil 
    101116      end 
    102     end 
    103    
    104     def complete_open_id_authentication 
    105       open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params) } 
    106       identity_url     = normalize_url(open_id_response.identity_url) if open_id_response.identity_url 
    107  
    108       case open_id_response.status 
    109       when OpenID::CANCEL 
    110         yield Result[:canceled], identity_url, nil 
    111       when OpenID::FAILURE 
    112         logger.info "OpenID authentication failed: #{open_id_response.msg}" 
    113         yield Result[:failed], identity_url, nil 
    114       when OpenID::SUCCESS 
    115         yield Result[:successful], identity_url, open_id_response.extension_response('sreg') 
    116       end       
    117117    end 
    118118 
     
    120120      OpenID::Consumer.new(session, open_id_store) 
    121121    end 
    122      
     122 
    123123    def open_id_store 
    124124      case store 
     
    132132    end 
    133133 
     134    def add_simple_registration_fields(open_id_request, fields) 
     135      sreg_request = OpenID::SReg::Request.new 
     136      sreg_request.request_fields(Array(fields[:required]).map(&:to_s), true) if fields[:required] 
     137      sreg_request.request_fields(Array(fields[:optional]).map(&:to_s), false) if fields[:optional] 
     138      sreg_request.policy_url = fields[:policy_url] if fields[:policy_url] 
     139      open_id_request.add_extension(sreg_request) 
     140    end 
    134141 
    135     def add_simple_registration_fields(open_id_response, fields
    136       open_id_response.add_extension_arg('sreg', 'required', [ fields[:required] ].flatten * ',') if fields[:required] 
    137       open_id_response.add_extension_arg('sreg', 'optional', [ fields[:optional] ].flatten * ',') if fields[:optional] 
     142    def open_id_redirect_url(open_id_request
     143      open_id_request.return_to_args['open_id_complete'] = '1' 
     144      open_id_request.redirect_url(root_url, requested_url) 
    138145    end 
    139      
    140     def open_id_redirect_url(open_id_response) 
    141       open_id_response.redirect_url( 
    142         request.protocol + request.host_with_port + "/", 
    143         open_id_response.return_to("#{request.protocol + request.host_with_port + request.relative_url_root + request.path}?open_id_complete=1") 
    144       )      
     146 
     147    def requested_url 
     148      "#{request.protocol + request.host_with_port + request.relative_url_root + request.path}" 
    145149    end 
    146150 
     
    152156          OpenID::FAILURE 
    153157        end 
    154          
     158 
    155159        def msg 
    156160          "Identity server timed out" 
  • plugins/open_id_authentication/lib/open_id_authentication/db_store.rb

    r6514 r9103  
     1require 'openid/store/interface' 
     2 
    13module OpenIdAuthentication 
    2   class DbStore < OpenID::Store 
    3     def self.gc 
     4  class DbStore < OpenID::Store::Interface 
     5    def self.cleanup_nonces 
    46      now = Time.now.to_i 
    5  
    6       # remove old nonces 
    7       nonces = Nonce.find(:all) 
    8       nonces.each {|n| n.destroy if now - n.created > 6.hours} unless nonces.nil? 
    9      
    10       # remove expired assocs 
    11       assocs = Association.find(:all) 
    12       assocs.each { |a| a.destroy if a.from_record.expired? } unless assocs.nil? 
     7      Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) 
    138    end 
    149 
    15  
    16     def get_auth_key 
    17       unless setting = Setting.find_by_setting('auth_key') 
    18         auth_key = OpenID::Util.random_string(20) 
    19         setting  = Setting.create(:setting => 'auth_key', :value => auth_key) 
    20       end 
    21  
    22       setting.value 
     10    def self.cleanup_associations 
     11      now = Time.now.to_i 
     12      Association.delete_all(['issued + lifetime > ?',now]) 
    2313    end 
    2414 
    2515    def store_association(server_url, assoc) 
    26       remove_association(server_url, assoc.handle)     
     16      remove_association(server_url, assoc.handle) 
    2717      Association.create(:server_url => server_url, 
    2818                         :handle     => assoc.handle, 
     
    3323    end 
    3424 
    35     def get_association(server_url, handle=nil) 
    36       assocs = handle.blank? ?  
    37         Association.find_all_by_server_url(server_url) : 
     25    def get_association(server_url, handle = nil) 
     26      assocs = if handle.blank? 
     27          Association.find_all_by_server_url(server_url) 
     28        else 
    3829          Association.find_all_by_server_url_and_handle(server_url, handle) 
    39      
     30        end 
     31 
    4032      assocs.reverse.each do |assoc| 
    41         a = assoc.from_record     
    42         if a.expired? 
     33        a = assoc.from_record 
     34        if a.expires_in == 0 
    4335          assoc.destroy 
    4436        else 
     
    4638        end 
    4739      end if assocs.any? 
    48      
     40 
    4941      return nil 
    5042    end 
    51    
     43 
    5244    def remove_association(server_url, handle) 
    53       assoc = Association.find_by_server_url_and_handle(server_url, handle) 
    54       unless assoc.nil? 
    55         assoc.destroy 
    56         return true 
    57       end 
    58       false 
     45      Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 
    5946    end 
    60    
    61     def store_nonce(nonce) 
    62       use_nonce(nonce) 
    63       Nonce.create :nonce => nonce, :created => Time.now.to_i 
    64     end 
    65    
    66     def use_nonce(nonce) 
    67       nonce = Nonce.find_by_nonce(nonce) 
    68       return false if nonce.nil? 
    69      
    70       age = Time.now.to_i - nonce.created 
    71       nonce.destroy 
    7247 
    73       age < 6.hours # max nonce age of 6 hours 
    74     end 
    75    
    76     def dumb? 
    77       fals
     48    def use_nonce(server_url, timestamp, salt) 
     49      return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) 
     50      return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew 
     51      Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt) 
     52      return tru
    7853    end 
    7954  end 
  • plugins/open_id_authentication/README

    r8225 r9103  
    99from that gem. 
    1010 
    11 The specification used is http://openid.net/specs/openid-authentication-1_1.html (not the 2.0 draft)
     11The specification used is http://openid.net/specs/openid-authentication-2_0.html
    1212 
    1313 
  • plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake

    r6515 r9103  
    33    desc "Creates authentication tables for use with OpenIdAuthentication" 
    44    task :create => :environment do 
    5       raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations? 
     5      generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"]) 
     6    end 
     7 
     8    desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x" 
     9    task :upgrade => :environment do 
     10      generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"]) 
     11    end 
     12 
     13    def generate_migration(args) 
    614      require 'rails_generator' 
    715      require 'rails_generator/scripts/generate' 
    8       Rails::Generator::Scripts::Generate.new.run([ "open_id_authentication_tables", "add_open_id_authentication_tables" ]) 
     16 
     17      if ActiveRecord::Base.connection.supports_migrations? 
     18        Rails::Generator::Scripts::Generate.new.run(args) 
     19      else 
     20        raise "Task unavailable to this database (no migration support)" 
     21      end 
    922    end 
    1023 
    1124    desc "Clear the authentication tables" 
    1225    task :clear => :environment do 
    13       OpenIdAuthentication::DbStore.gc 
     26      OpenIdAuthentication::DbStore.cleanup_nonces 
     27      OpenIdAuthentication::DbStore.cleanup_associations 
    1428    end 
    1529  end 
  • plugins/open_id_authentication/test/normalize_test.rb

    r8931 r9103  
    1 require 'test/unit' 
    2 require 'rubygems' 
    3 require 'active_support' 
    4  
    5 RAILS_ROOT = File.dirname(__FILE__) 
    6 require File.dirname(__FILE__) + "/../lib/open_id_authentication" 
     1require File.dirname(__FILE__) + '/test_helper' 
    72 
    83class NormalizeTest < Test::Unit::TestCase 
     
    3025    end 
    3126  end 
    32  
     27   
    3328  def test_broken_open_id 
    3429    assert_raises(InvalidOpenId) { normalize_url(nil) } 
  • plugins/open_id_authentication/test/open_id_authentication_test.rb

    r7162 r9103  
    1 require 'test/unit' 
    2  
    3 require 'rubygems' 
    4 gem 'mocha' 
    5 require 'mocha' 
    6  
    7 gem 'ruby-openid' 
    8 require 'openid' 
    9  
    10 RAILS_ROOT = File.dirname(__FILE__) 
    11 require File.dirname(__FILE__) + "/../lib/open_id_authentication" 
     1require File.dirname(__FILE__) + '/test_helper' 
    122 
    133class OpenIdAuthenticationTest < Test::Unit::TestCase 
     
    2010 
    2111  def test_authentication_should_fail_when_the_identity_server_is_missing 
    22     @controller.stubs(:open_id_consumer).returns(stub(:begin => stub(:status => OpenID::FAILURE))) 
    23      
     12    open_id_consumer = mock() 
     13    open_id_consumer.expects(:begin).raises(OpenID::OpenIDError) 
     14    @controller.stubs(:open_id_consumer).returns(open_id_consumer) 
     15 
    2416    @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| 
    2517      assert result.missing? 
     
    2921 
    3022  def test_authentication_should_fail_when_the_identity_server_times_out 
    31     @controller.stubs(:open_id_consumer).returns(stub(:begin => Proc.new { raise Timeout::Error, "Identity Server took too long." })) 
     23    open_id_consumer = mock() 
     24    open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.") 
     25    @controller.stubs(:open_id_consumer).returns(open_id_consumer) 
    3226 
    3327    @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| 
     
    3832 
    3933  def test_authentication_should_begin_when_the_identity_server_is_present 
    40     @controller.stubs(:open_id_consumer).returns(stub(:begin => stub(:status => OpenID::SUCCESS))) 
    41     @controller.expects(:begin_open_id_authentication)  
     34    @controller.stubs(:open_id_consumer).returns(stub(:begin => true)) 
     35    @controller.expects(:begin_open_id_authentication) 
    4236    @controller.send(:authenticate_with_open_id, "http://someone.example.com") 
    4337  end 
  • plugins/open_id_authentication/test/status_test.rb

    r6324 r9103  
    1 require 'test/unit' 
    2  
    3 RAILS_ROOT = File.dirname(__FILE__) 
    4 require File.dirname(__FILE__) + "/../lib/open_id_authentication" 
     1require File.dirname(__FILE__) + '/test_helper' 
    52 
    63class StatusTest < Test::Unit::TestCase