summary refs log tree commit
diff options
context:
space:
mode:
authorScytrin dai Kinthra <scytrin@gmail.com>2009-05-01 16:25:16 -0700
committerScytrin dai Kinthra <scytrin@gmail.com>2009-05-23 12:50:32 -0700
commit2ebe768b58a13f4f80e6cb410e5d5d8eb1eee8ca (patch)
tree605065788f92d6d7b775aff3aeb708e50d372e85
parent7a55c98a30deea7fe198958d7c2770b087aa94b9 (diff)
downloadrack-2ebe768b58a13f4f80e6cb410e5d5d8eb1eee8ca.tar.gz
Documentation reorganization for Rack::Auth::OpenID
Adjust derivation of values for ValidStatus
Whitespace and syntax cleanups.
Changed authorship tagline.
-rw-r--r--lib/rack/auth/openid.rb238
1 files changed, 122 insertions, 116 deletions
diff --git a/lib/rack/auth/openid.rb b/lib/rack/auth/openid.rb
index c5f6a514..fda3504e 100644
--- a/lib/rack/auth/openid.rb
+++ b/lib/rack/auth/openid.rb
@@ -1,13 +1,13 @@
-# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
+# AUTHOR: Scytrin dai Kinthra <scytrin@gmail.com>; blink#ruby-lang@irc.freenode.net
 
 gem 'ruby-openid', '~> 2' if defined? Gem
 require 'rack/request'
 require 'rack/utils'
-require 'rack/auth/abstract/handler'
+
 require 'uri'
-require 'openid' #gem
-require 'openid/extension' #gem
-require 'openid/store/memory' #gem
+require 'openid'
+require 'openid/extension'
+require 'openid/store/memory'
 
 module Rack
   class Request
@@ -45,108 +45,111 @@ module Rack
     #
     # NOTE: Due to the amount of data that this library stores in the
     # session, Rack::Session::Cookie may fault.
+    #
+    # == Examples
+    #
+    #   simple_oid = OpenID.new('http://mysite.com/')
+    #
+    #   return_oid = OpenID.new('http://mysite.com/', {
+    #     :return_to => 'http://mysite.com/openid'
+    #   })
+    #
+    #   complex_oid = OpenID.new('http://mysite.com/',
+    #     :immediate => true,
+    #     :extensions => {
+    #       ::OpenID::SReg => [['email'],['nickname']]
+    #     }
+    #   )
+    #
+    # = Advanced
+    #
+    # Most of the functionality of this library is encapsulated such that
+    # expansion and overriding functions isn't difficult nor tricky.
+    # Alternately, to avoid opening up singleton objects or subclassing, a
+    # wrapper rack middleware can be composed to act upon Auth::OpenID's
+    # responses. See #check and #finish for locations of pertinent data.
+    #
+    # == Responses
+    #
+    # To change the responses that Auth::OpenID returns, override the methods
+    # #redirect, #bad_request, #unauthorized, #access_denied, and
+    # #foreign_server_failure.
+    #
+    # Additionally #confirm_post_params is used when the URI would exceed
+    # length limits on a GET request when doing the initial verification
+    # request.
+    #
+    # == Processing
+    #
+    # To change methods of processing completed transactions, override the
+    # methods #success, #setup_needed, #cancel, and #failure. Please ensure
+    # the returned object is a rack compatible response.
+    #
+    # The first argument is an OpenID::Response, the second is a
+    # Rack::Request of the current request, the last is the hash used in
+    # ruby-openid handling, which can be found manually at
+    # env['rack.session'][:openid].
+    #
+    # This is useful if you wanted to expand the processing done, such as
+    # setting up user accounts.
+    #
+    #   oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to
+    #   def oid_app.success oid, request, session
+    #     user = Models::User[oid.identity_url]
+    #     user ||= Models::User.create_from_openid oid
+    #     request['rack.session'][:user] = user.id
+    #     redirect MyApp.site_home
+    #   end
+    #
+    #   site_map['/openid'] = oid_app
+    #   map = Rack::URLMap.new site_map
+    #   ...
 
     class OpenID
-
+      # Raised if an incompatible session is being used.
       class NoSession < RuntimeError; end
+      # Raised if an extension not matching specifications is provided.
       class BadExtension < RuntimeError; end
-      # Required for ruby-openid
-      ValidStatus = [:success, :setup_needed, :cancel, :failure]
+      # Possible statuses returned from consumer responses. See definitions
+      # in the ruby-openid library.
+      ValidStatus = [
+        ::OpenID::Consumer::SUCCESS,
+        ::OpenID::Consumer::FAILURE,
+        ::OpenID::Consumer::CANCEL,
+        ::OpenID::Consumer::SETUP_NEEDED
+      ]
 
-      # = Arguments
-      #
       # The first argument is the realm, identifying the site they are trusting
       # with their identity. This is required, also treated as the trust_root
       # in OpenID 1.x exchanges.
       #
-      # The optional second argument is a hash of options.
-      #
-      # == Options
+      # The lits of acceptable options include :return_to, :session_key,
+      # :openid_param, :store, :immediate, :extensions.
       #
       # <tt>:return_to</tt> defines the url to return to after the client
       # authenticates with the openid service provider. This url should point
-      # to where Rack::Auth::OpenID is mounted. If <tt>:return_to</tt> is not
-      # provided, return_to will be the current url which allows flexibility
-      # with caveats.
+      # to where Rack::Auth::OpenID is mounted. If unprovided, the url of
+      # the current request is used.
       #
       # <tt>:session_key</tt> defines the key to the session hash in the env.
-      # It defaults to 'rack.session'.
+      # The default is 'rack.session'.
       #
       # <tt>:openid_param</tt> defines at what key in the request parameters to
       # find the identifier to resolve. As per the 2.0 spec, the default is
       # 'openid_identifier'.
       #
       # <tt>:store</tt> defined what OpenID Store to use for persistant
-      # information. By default a Store::Memory will be used.
+      # information. By default a Store::Memory is used.
       #
       # <tt>:immediate</tt> as true will make initial requests to be of an
       # immediate type. This is false by default. See OpenID specification
       # documentation.
       #
       # <tt>:extensions</tt> should be a hash of openid extension
-      # implementations. The key should be the extension main module, the value
-      # should be an array of arguments for extension::Request.new.
+      # implementations. The key should be the extension module, the value
+      # should be an array of arguments for extension::Request.new().
       # The hash is iterated over and passed to #add_extension for processing.
       # Please see #add_extension for further documentation.
-      #
-      # == Examples
-      #
-      #   simple_oid = OpenID.new('http://mysite.com/')
-      #
-      #   return_oid = OpenID.new('http://mysite.com/', {
-      #     :return_to => 'http://mysite.com/openid'
-      #   })
-      #
-      #   complex_oid = OpenID.new('http://mysite.com/',
-      #     :immediate => true,
-      #     :extensions => {
-      #       ::OpenID::SReg => [['email'],['nickname']]
-      #     }
-      #   )
-      #
-      # = Advanced
-      #
-      # Most of the functionality of this library is encapsulated such that
-      # expansion and overriding functions isn't difficult nor tricky.
-      # Alternately, to avoid opening up singleton objects or subclassing, a
-      # wrapper rack middleware can be composed to act upon Auth::OpenID's
-      # responses. See #check and #finish for locations of pertinent data.
-      #
-      # == Responses
-      #
-      # To change the responses that Auth::OpenID returns, override the methods
-      # #redirect, #bad_request, #unauthorized, #access_denied, and
-      # #foreign_server_failure.
-      #
-      # Additionally #confirm_post_params is used when the URI would exceed
-      # length limits on a GET request when doing the initial verification
-      # request.
-      #
-      # == Processing
-      #
-      # To change methods of processing completed transactions, override the
-      # methods #success, #setup_needed, #cancel, and #failure. Please ensure
-      # the returned object is a rack compatible response.
-      #
-      # The first argument is an OpenID::Response, the second is a
-      # Rack::Request of the current request, the last is the hash used in
-      # ruby-openid handling, which can be found manually at
-      # env['rack.session'][:openid].
-      #
-      # This is useful if you wanted to expand the processing done, such as
-      # setting up user accounts.
-      #
-      #   oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to
-      #   def oid_app.success oid, request, session
-      #     user = Models::User[oid.identity_url]
-      #     user ||= Models::User.create_from_openid oid
-      #     request['rack.session'][:user] = user.id
-      #     redirect MyApp.site_home
-      #   end
-      #
-      #   site_map['/openid'] = oid_app
-      #   map = Rack::URLMap.new site_map
-      #   ...
 
       def initialize(realm, options={})
         realm = URI(realm)
@@ -162,7 +165,7 @@ module Rack
           ruri = URI(ruri)
           raise ArgumentError, "Invalid return_to: #{ruri}" \
             unless ruri.absolute? \
-            and ruri.scheme  =~ /^https?$/ \
+            and ruri.scheme =~ /^https?$/ \
             and ruri.fragment.nil?
           raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \
             unless self.within_realm?(ruri)
@@ -174,10 +177,10 @@ module Rack
         @store        = options[:store]         || ::OpenID::Store::Memory.new
         @immediate    = !!options[:immediate]
 
-        @extensions = {}
-        if extensions = options.delete(:extensions)
+        @extensions   = {}
+        if extensions = options[:extensions]
           extensions.each do |ext, args|
-            add_extension ext, *args
+            add_extension(ext, *args)
           end
         end
 
@@ -199,33 +202,29 @@ module Rack
       # If the parameter specified by <tt>options[:openid_param]</tt> is
       # present, processing is passed to #check and the result is returned.
       #
-      # If neither of these conditions are met, #unauthorized is called.
+      # If neither of these conditions are met, #bad_request is called.
 
       def call(env)
         env['rack.auth.openid'] = self
         env_session = env[@session_key]
         unless env_session and env_session.is_a?(Hash)
-          raise NoSession, 'No compatible session'
+          raise NoSession, 'No compatible session.'
         end
         # let us work in our own namespace...
         session = (env_session[:openid] ||= {})
         unless session and session.is_a?(Hash)
-          raise NoSession, 'Incompatible openid session'
+          raise NoSession, 'Incompatible openid session.'
         end
 
         request = Rack::Request.new(env)
         consumer = ::OpenID::Consumer.new(session, @store)
 
         if mode = request.GET['openid.mode']
-          if session.key?(:openid_param)
-            finish(consumer, session, request)
-          else
-            bad_request
-          end
+          finish(consumer, session, request)
         elsif request.GET[@openid_param]
           check(consumer, session, request)
         else
-          unauthorized
+          bad_request
         end
       end
 
@@ -263,14 +262,13 @@ module Rack
         immediate = session.key?(:setup_needed) ? false : immediate
 
         if oid.send_redirect?(realm, return_to_uri, immediate)
-          uri = oid.redirect_url(realm, return_to_uri, immediate)
-          redirect(uri)
+          redirect(oid.redirect_url(realm, return_to_uri, immediate))
         else
           confirm_post_params(oid, realm, return_to_uri, immediate)
         end
       rescue ::OpenID::DiscoveryFailure => e
         # thrown from inside OpenID::Consumer#begin by yadis stuff
-        req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n")
+        req.env['rack.errors'].puts( [e.message, *e.backtrace]*"\n" )
         return foreign_server_failure
       end
 
@@ -290,21 +288,24 @@ module Rack
         req.env['rack.errors'].puts(oid.message)
         p oid if $DEBUG
 
-        raise unless ValidStatus.include?(oid.status)
-        __send__(oid.status, oid, req, session)
+        if ValidStatus.include?(oid.status)
+          __send__(oid.status, oid, req, session)
+        else
+          invalid_status(oid, req, session)
+        end
       end
 
       # The first argument should be the main extension module.
       # The extension module should contain the constants:
-      #   * class Request, should have OpenID::Extension as an ancestor
-      #   * class Response, should have OpenID::Extension as an ancestor
-      #   * string NS_URI, which defining the namespace of the extension
+      # * class Request, should have OpenID::Extension as an ancestor
+      # * class Response, should have OpenID::Extension as an ancestor
+      # * string NS_URI, which defining the namespace of the extension
       #
       # All trailing arguments will be passed to extension::Request.new in
       # #check.
       # The openid response will be passed to
-      # extension::Response#from_success_response, #get_extension_args will be
-      # called on the result to attain the gathered data.
+      # extension::Response#from_success_response, oid#get_extension_args will
+      # be called on the result to attain the gathered data.
       #
       # This method returns the key at which the response data will be found in
       # the session, which is the namespace uri by default.
@@ -344,28 +345,27 @@ module Rack
         return false unless uri.host.match(realm_match)
         return true
       end
+
       alias_method :include?, :within_realm?
 
       protected
 
-      ### These methods define some of the boilerplate responses.
-
       # Returns an html form page for posting to an Identity Provider if the
       # GET request would exceed the upper URI length limit.
 
       def confirm_post_params(oid, realm, return_to, immediate)
-        Rack::Response.new.finish do |r|
-          r.write '<html><head><title>Confirm...</title></head><body>'
-          r.write oid.form_markup(realm, return_to, immediate)
-          r.write '</body></html>'
-        end
+        response = Rack::Response.new '<html>'+
+          '<head><title>Confirm...</title></head>'+
+          '<body>'+oid.form_markup(realm, return_to, immediate)+'</body>'+
+          '</html>'
+        response.finish
       end
 
       # Returns a 303 redirect with the destination of that provided by the
       # argument.
 
       def redirect(uri)
-        [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain',
+        [ 303, {'Content-Type'=>'text/plain', 'Content-Length'=>'0',
           'Location' => uri},
           [] ]
       end
@@ -401,10 +401,6 @@ module Rack
 
       private
 
-      ### These methods are called after a transaction is completed, depending
-      # on its outcome. These should all return a rack compatible response.
-      # You'd want to override these to provide additional functionality.
-
       # Called to complete processing on a successful transaction.
       # Within the openid session, :openid_identity and :openid_identifier are
       # set to the user friendly and the standard representation of the
@@ -430,7 +426,7 @@ module Rack
       def setup_needed(oid, request, session)
         identifier = session[:openid_param]
         session[:setup_needed] = true
-        redirect req.script_name + '?' + openid_param + '=' + identifier
+        redirect(req.script_name + '?' + openid_param + '=' + identifier)
       end
 
       # Called if the user indicates they wish to cancel identification.
@@ -448,6 +444,16 @@ module Rack
       def failure(oid, request, session)
         unauthorized
       end
+
+      # To be called if there is no method for handling the OpenID response
+      # status.
+
+      def invalid_status(oid, request, session)
+        msg = 'Invalid status returned by the OpenID authorization reponse.'
+        [ 500,
+          {'Content-Type'=>'text/plain','Content-Length'=>msg.length.to_s},
+          [msg] ]
+      end
     end
 
     # A class developed out of the request to use OpenID as an authentication
@@ -473,7 +479,7 @@ module Rack
 
       def call(env)
         to = auth.call(env) ? @app : @oid
-        to.call env
+        to.call(env)
       end
     end
   end