diff options
Diffstat (limited to 'actionpack/lib/action_controller/vendor/rack-0.4.0/rack/auth/openid.rb')
-rw-r--r-- | actionpack/lib/action_controller/vendor/rack-0.4.0/rack/auth/openid.rb | 437 |
1 files changed, 0 insertions, 437 deletions
diff --git a/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/auth/openid.rb b/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/auth/openid.rb deleted file mode 100644 index 2bd064ea4a..0000000000 --- a/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/auth/openid.rb +++ /dev/null @@ -1,437 +0,0 @@ -# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net - -gem 'ruby-openid', '~> 2' if defined? Gem -require 'rack/auth/abstract/handler' #rack -require 'uri' #std -require 'pp' #std -require 'openid' #gem -require 'openid/extension' #gem -require 'openid/store/memory' #gem - -module Rack - module Auth - # Rack::Auth::OpenID provides a simple method for permitting - # openid based logins. It requires the ruby-openid library from - # janrain to operate, as well as a rack method of session management. - # - # The ruby-openid home page is at http://openidenabled.com/ruby-openid/. - # - # The OpenID specifications can be found at - # http://openid.net/specs/openid-authentication-1_1.html - # and - # http://openid.net/specs/openid-authentication-2_0.html. Documentation - # for published OpenID extensions and related topics can be found at - # http://openid.net/developers/specs/. - # - # It is recommended to read through the OpenID spec, as well as - # ruby-openid's documentation, to understand what exactly goes on. However - # a setup as simple as the presented examples is enough to provide - # functionality. - # - # This library strongly intends to utilize the OpenID 2.0 features of the - # ruby-openid library, while maintaining OpenID 1.0 compatiblity. - # - # All responses from this rack application will be 303 redirects unless an - # error occurs, with the exception of an authentication request requiring - # an HTML form submission. - # - # NOTE: Extensions are not currently supported by this implimentation of - # the OpenID rack application due to the complexity of the current - # ruby-openid extension handling. - # - # NOTE: Due to the amount of data that this library stores in the - # session, Rack::Session::Cookie may fault. - class OpenID < AbstractHandler - class NoSession < RuntimeError; end - # Required for ruby-openid - OIDStore = ::OpenID::Store::Memory.new - HTML = '<html><head><title>%s</title></head><body>%s</body></html>' - - # A Hash of options is taken as it's single initializing - # argument. For example: - # - # simple_oid = OpenID.new('http://mysite.com/') - # - # return_oid = OpenID.new('http://mysite.com/', { - # :return_to => 'http://mysite.com/openid' - # }) - # - # page_oid = OpenID.new('http://mysite.com/', - # :login_good => 'http://mysite.com/auth_good' - # ) - # - # complex_oid = OpenID.new('http://mysite.com/', - # :return_to => 'http://mysite.com/openid', - # :login_good => 'http://mysite.com/user/preferences', - # :auth_fail => [500, {'Content-Type'=>'text/plain'}, - # 'Unable to negotiate with foreign server.'], - # :immediate => true, - # :extensions => { - # ::OpenID::SReg => [['email'],['nickname']] - # } - # ) - # - # = Arguments - # - # The first argument is the realm, identifying the site they are trusting - # with their identity. This is required. - # - # NOTE: In OpenID 1.x, the realm or trust_root is optional and the - # return_to url is required. As this library strives tward ruby-openid - # 2.0, and OpenID 2.0 compatibiliy, the realm is required and return_to - # is optional. However, this implimentation is still backwards compatible - # with OpenID 1.0 servers. - # - # The optional second argument is a hash of options. - # - # == Options - # - # <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 including all query - # parameters. - # - # <tt>:session_key</tt> defines the key to the session hash in the env. - # It defaults to '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>:immediate</tt> as true will make immediate type of requests the - # default. See OpenID specification documentation. - # - # === URL options - # - # <tt>:login_good</tt> is the url to go to after the authentication - # process has completed. - # - # <tt>:login_fail</tt> is the url to go to after the authentication - # process has failed. - # - # <tt>:login_quit</tt> is the url to go to after the authentication - # process - # has been cancelled. - # - # === Response options - # - # <tt>:no_session</tt> should be a rack response to be returned if no or - # an incompatible session is found. - # - # <tt>:auth_fail</tt> should be a rack response to be returned if an - # OpenID::DiscoveryFailure occurs. This is typically due to being unable - # to access the identity url or identity server. - # - # <tt>:error</tt> should be a rack response to return if any other - # generic error would occur and <tt>options[:catch_errors]</tt> is true. - # - # === Extensions - # - # <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 - # - # The hash is iterated over and passed to #add_extension for processing. - # Please see #add_extension for further documentation. - def initialize(realm, options={}) - @realm = realm - realm = URI(realm) - if realm.path.empty? - raise ArgumentError, "Invalid realm path: '#{realm.path}'" - elsif not realm.absolute? - raise ArgumentError, "Realm '#{@realm}' not absolute" - end - - [:return_to, :login_good, :login_fail, :login_quit].each do |key| - if options.key? key and luri = URI(options[key]) - if !luri.absolute? - raise ArgumentError, ":#{key} is not an absolute uri: '#{luri}'" - end - end - end - - if options[:return_to] and ruri = URI(options[:return_to]) - if ruri.path.empty? - raise ArgumentError, "Invalid return_to path: '#{ruri.path}'" - elsif realm.path != ruri.path[0, realm.path.size] - raise ArgumentError, 'return_to not within realm.' \ - end - end - - # TODO: extension support - if extensions = options.delete(:extensions) - extensions.each do |ext, args| - add_extension ext, *args - end - end - - @options = { - :session_key => 'rack.session', - :openid_param => 'openid_identifier', - #:return_to, :login_good, :login_fail, :login_quit - #:no_session, :auth_fail, :error - :store => OIDStore, - :immediate => false, - :anonymous => false, - :catch_errors => false - }.merge(options) - @extensions = {} - end - - attr_reader :options, :extensions - - # It sets up and uses session data at <tt>:openid</tt> within the - # session. It sets up the ::OpenID::Consumer using the store specified by - # <tt>options[:store]</tt>. - # - # If the parameter specified by <tt>options[:openid_param]</tt> is - # present, processing is passed to #check and the result is returned. - # - # If the parameter 'openid.mode' is set, implying a followup from the - # openid server, processing is passed to #finish and the result is - # returned. - # - # If neither of these conditions are met, a 400 error is returned. - # - # If an error is thrown and <tt>options[:catch_errors]</tt> is false, the - # exception will be reraised. Otherwise a 500 error is returned. - def call(env) - env['rack.auth.openid'] = self - session = env[@options[:session_key]] - unless session and session.is_a? Hash - raise(NoSession, 'No compatible session') - end - # let us work in our own namespace... - session = (session[:openid] ||= {}) - unless session and session.is_a? Hash - raise(NoSession, 'Incompatible session') - end - - request = Rack::Request.new env - consumer = ::OpenID::Consumer.new session, @options[:store] - - if request.params['openid.mode'] - finish consumer, session, request - elsif request.params[@options[:openid_param]] - check consumer, session, request - else - env['rack.errors'].puts "No valid params provided." - bad_request - end - rescue NoSession - env['rack.errors'].puts($!.message, *$@) - - @options. ### Missing or incompatible session - fetch :no_session, [ 500, - {'Content-Type'=>'text/plain'}, - $!.message ] - rescue - env['rack.errors'].puts($!.message, *$@) - - if not @options[:catch_error] - raise($!) - end - @options. - fetch :error, [ 500, - {'Content-Type'=>'text/plain'}, - 'OpenID has encountered an error.' ] - end - - # As the first part of OpenID consumer action, #check retrieves the data - # required for completion. - # - # * <tt>session[:openid][:openid_param]</tt> is set to the submitted - # identifier to be authenticated. - # * <tt>session[:openid][:site_return]</tt> is set as the request's - # HTTP_REFERER, unless already set. - # * <tt>env['rack.auth.openid.request']</tt> is the openid checkid - # request instance. - def check(consumer, session, req) - session[:openid_param] = req.params[@options[:openid_param]] - oid = consumer.begin(session[:openid_param], @options[:anonymous]) - pp oid if $DEBUG - req.env['rack.auth.openid.request'] = oid - - session[:site_return] ||= req.env['HTTP_REFERER'] - - # SETUP_NEEDED check! - # see OpenID::Consumer::CheckIDRequest docs - query_args = [@realm, *@options.values_at(:return_to, :immediate)] - query_args[1] ||= req.url - query_args[2] = false if session.key? :setup_needed - pp query_args if $DEBUG - - ## Extension support - extensions.each do |ext,args| - oid.add_extension ext::Request.new(*args) - end - - if oid.send_redirect?(*query_args) - redirect = oid.redirect_url(*query_args) - if $DEBUG - pp redirect - pp Rack::Utils.parse_query(URI(redirect).query) - end - [ 303, {'Location'=>redirect}, [] ] - else - # check on 'action' option. - formbody = oid.form_markup(*query_args) - if $DEBUG - pp formbody - end - body = HTML % ['Confirm...', formbody] - [ 200, {'Content-Type'=>'text/html'}, body.to_a ] - end - rescue ::OpenID::DiscoveryFailure => e - # thrown from inside OpenID::Consumer#begin by yadis stuff - req.env['rack.errors'].puts($!.message, *$@) - - @options. ### Foreign server failed - fetch :auth_fail, [ 503, - {'Content-Type'=>'text/plain'}, - 'Foreign server failure.' ] - end - - # This is the final portion of authentication. Unless any errors outside - # of specification occur, a 303 redirect will be returned with Location - # determined by the OpenID response type. If none of the response type - # :login_* urls are set, the redirect will be set to - # <tt>session[:openid][:site_return]</tt>. If - # <tt>session[:openid][:site_return]</tt> is unset, the realm will be - # used. - # - # Any messages from OpenID's response are appended to the 303 response - # body. - # - # Data gathered from extensions are stored in session[:openid] with the - # extension's namespace uri as the key. - # - # * <tt>env['rack.auth.openid.response']</tt> is the openid response. - # - # The four valid possible outcomes are: - # * failure: <tt>options[:login_fail]</tt> or - # <tt>session[:site_return]</tt> or the realm - # * <tt>session[:openid]</tt> is cleared and any messages are send to - # rack.errors - # * <tt>session[:openid]['authenticated']</tt> is <tt>false</tt> - # * success: <tt>options[:login_good]</tt> or - # <tt>session[:site_return]</tt> or the realm - # * <tt>session[:openid]</tt> is cleared - # * <tt>session[:openid]['authenticated']</tt> is <tt>true</tt> - # * <tt>session[:openid]['identity']</tt> is the actual identifier - # * <tt>session[:openid]['identifier']</tt> is the pretty identifier - # * cancel: <tt>options[:login_good]</tt> or - # <tt>session[:site_return]</tt> or the realm - # * <tt>session[:openid]</tt> is cleared - # * <tt>session[:openid]['authenticated']</tt> is <tt>false</tt> - # * setup_needed: resubmits the authentication request. A flag is set for - # non-immediate handling. - # * <tt>session[:openid][:setup_needed]</tt> is set to <tt>true</tt>, - # which will prevent immediate style openid authentication. - def finish(consumer, session, req) - oid = consumer.complete(req.params, req.url) - pp oid if $DEBUG - req.env['rack.auth.openid.response'] = oid - - goto = session.fetch :site_return, @realm - body = [] - - case oid.status - when ::OpenID::Consumer::FAILURE - session.clear - session['authenticated'] = false - req.env['rack.errors'].puts oid.message - - goto = @options[:login_fail] if @option.key? :login_fail - body << "Authentication unsuccessful.\n" - when ::OpenID::Consumer::SUCCESS - session.clear - - ## Extension support - extensions.each do |ext, args| - session[ext::NS_URI] = ext::Response. - from_success_response(oid). - get_extension_args - end - - session['authenticated'] = true - # Value for unique identification and such - session['identity'] = oid.identity_url - # Value for display and UI labels - session['identifier'] = oid.display_identifier - - goto = @options[:login_good] if @options.key? :login_good - body << "Authentication successful.\n" - when ::OpenID::Consumer::CANCEL - session.clear - session['authenticated'] = false - - goto = @options[:login_fail] if @option.key? :login_fail - body << "Authentication cancelled.\n" - when ::OpenID::Consumer::SETUP_NEEDED - session[:setup_needed] = true - unless o_id = session[:openid_param] - raise('Required values missing.') - end - - goto = req.script_name+ - '?'+@options[:openid_param]+ - '='+o_id - body << "Reauthentication required.\n" - end - body << oid.message if oid.message - [ 303, {'Location'=>goto}, body] - end - - # The first argument should be the main extension module. - # The extension module should contain the constants: - # * class Request, with OpenID::Extension as an ancestor - # * class Response, with OpenID::Extension as an ancestor - # * string NS_URI, which defines the namespace of the extension, should - # be an absolute http uri - # - # 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. - # - # This method returns the key at which the response data will be found in - # the session, which is the namespace uri by default. - def add_extension ext, *args - if not ext.is_a? Module - raise TypeError, "#{ext.inspect} is not a module" - elsif not (m = %w'Request Response NS_URI' - ext.constants).empty? - raise ArgumentError, "#{ext.inspect} missing #{m*', '}" - end - - consts = [ext::Request, ext::Response] - - if not consts.all?{|c| c.is_a? Class } - raise TypeError, "#{ext.inspect}'s Request or Response is not a class" - elsif not consts.all?{|c| ::OpenID::Extension > c } - raise ArgumentError, "#{ext.inspect}'s Request or Response not a decendant of OpenID::Extension" - end - - if not ext::NS_URI.is_a? String - raise TypeError, "#{ext.inspect}'s NS_URI is not a string" - elsif not uri = URI(ext::NS_URI) - raise ArgumentError, "#{ext.inspect}'s NS_URI is not a valid uri" - elsif not uri.scheme =~ /^https?$/ - raise ArgumentError, "#{ext.inspect}'s NS_URI is not an http uri" - elsif not uri.absolute? - raise ArgumentError, "#{ext.inspect}'s NS_URI is not and absolute uri" - end - @extensions[ext] = args - return ext::NS_URI - end - - # A conveniance method that returns the namespace of all current - # extensions used by this instance. - def extension_namespaces - @extensions.keys.map{|e|e::NS_URI} - end - end - end -end |