Class: OpenID::Consumer::AssociationManager

### Home Classes Methods

### In Files

- lib/openid/consumer/associationmanager.rb

### Parent

Object

### Methods

- ::create_session
- ::extract_expires_in
- ::new
- #create_associate_request
- #extract_association
- #extract_supported_association_type
- #get_association
- #get_openid1_session_type
- #negotiate_association
- #request_association

### Files

- LICENSE

### Class/Module Index

Quicksearch

- OpenID
- OpenID::AX
- OpenID::AX::AXMessage
- OpenID::AX::AttrInfo
- OpenID::AX::Error
- OpenID::AX::FetchRequest
- OpenID::AX::FetchResponse
- OpenID::AX::KeyValueMessage
- OpenID::AX::StoreRequest
- OpenID::AX::StoreResponse
- OpenID::AssertionError
- OpenID::Association
- OpenID::AssociationNegotiator
- OpenID::Consumer
- OpenID::Consumer::AssociationManager
- OpenID::Consumer::CancelResponse
- OpenID::Consumer::CheckIDRequest
- OpenID::Consumer::DiffieHellmanSHA1Session
- OpenID::Consumer::DiffieHellmanSHA256Session
- OpenID::Consumer::DiffieHellmanSession
- OpenID::Consumer::DiscoveredServices
- OpenID::Consumer::DiscoveryManager
- OpenID::Consumer::FailureResponse
- OpenID::Consumer::IdResHandler
- OpenID::Consumer::NoEncryptionSession
- OpenID::Consumer::Response
- OpenID::Consumer::Session
- OpenID::Consumer::SetupNeededResponse
- OpenID::Consumer::SuccessResponse
- OpenID::CryptUtil
- OpenID::DiffieHellman
- OpenID::DiscoveryFailure
- OpenID::Extension
- OpenID::FetchingError
- OpenID::HTTPRedirectLimitReached
- OpenID::HTTPResponse
- OpenID::HTTPStatusError
- OpenID::InvalidOpenIDNamespace
- OpenID::KVFormError
- OpenID::KVPostNetworkError
- OpenID::Message
- OpenID::Message::KeyNotFound
- OpenID::NamespaceAliasRegistrationError
- OpenID::NamespaceMap
- OpenID::Nonce
- OpenID::OAuth
- OpenID::OAuth::Request
- OpenID::OAuth::Response
- OpenID::OpenIDError
- OpenID::OpenIDServiceEndpoint
- OpenID::PAPE
- OpenID::PAPE::Request
- OpenID::PAPE::Response
- OpenID::ProtocolError
- OpenID::RealmVerificationRedirected
- OpenID::SReg
- OpenID::SReg::NamespaceError
- OpenID::SReg::Request
- OpenID::SReg::Response
- OpenID::SSLFetchingError
- OpenID::Server
- OpenID::Server::AlreadySigned
- OpenID::Server::AssociateRequest
- OpenID::Server::BaseServerSession
- OpenID::Server::CheckAuthRequest
- OpenID::Server::CheckIDRequest
- OpenID::Server::Decoder
- OpenID::Server::DiffieHellmanSHA1ServerSession
- OpenID::Server::DiffieHellmanSHA256ServerSession
- OpenID::Server::Encoder
- OpenID::Server::EncodingError
- OpenID::Server::MalformedReturnURL
- OpenID::Server::MalformedTrustRoot
- OpenID::Server::NoReturnToError
- OpenID::Server::OpenIDRequest
- OpenID::Server::OpenIDResponse
- OpenID::Server::PlainTextServerSession
- OpenID::Server::ProtocolError
- OpenID::Server::Server
- OpenID::Server::Signatory
- OpenID::Server::SigningEncoder
- OpenID::Server::UntrustedReturnURL
- OpenID::Server::VersionError
- OpenID::Server::WebResponse
- OpenID::ServerError
- OpenID::StandardFetcher
- OpenID::Store
- OpenID::Store::Filesystem
- OpenID::Store::Interface
- OpenID::Store::Memcache
- OpenID::Store::Memory
- OpenID::TrustRoot
- OpenID::TrustRoot::TrustRoot
- OpenID::TypeURIMismatch
- OpenID::UI
- OpenID::UI::Request
- OpenID::URINorm
- OpenID::UndefinedOpenIDNamespace
- OpenID::Util
- OpenID::Yadis
- OpenID::Yadis::BasicServiceEndpoint
- OpenID::Yadis::CompoundFilter
- OpenID::Yadis::DiscoveryResult
- OpenID::Yadis::TransformFilterMaker
- OpenID::Yadis::XRDSError
- OpenID::Yadis::XRDSFraud
- OpenID::Yadis::XRI
- OpenID::Yadis::XRI::ProxyResolver
- OpenID::Yadis::XRI::XRIHTTPError
- HMAC
- HMAC::Base
- HMAC::SHA1
- HMAC::SHA256
- HMAC::SHA384
- HMAC::SHA512
- Net
- Net::HTTP
- HTMLComment
- HTMLTag
- HTMLText
- HTMLToken
- HTMLTokenizer
- HTMLTokenizerError
- Object

No matching classes.

# OpenID::Consumer::AssociationManager

An object that manages creating and storing associations for an OpenID provider endpoint

### Public Class Methods

create_session(session_type) click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 89
    def self.create_session(session_type)
      case session_type
      when 'no-encryption'
        NoEncryptionSession.new
      when 'DH-SHA1'
        DiffieHellmanSHA1Session.new
      when 'DH-SHA256'
        DiffieHellmanSHA256Session.new
      else
        raise ArgumentError, "Unknown association session type: "                                "#{session_type.inspect}"
      end
    end

new(store, server_url, compatibility_mode=false, negotiator=nil) click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 103
    def initialize(store, server_url, compatibility_mode=false,
                   negotiator=nil)
      @store = store
      @server_url = server_url
      @compatibility_mode = compatibility_mode
      @negotiator = negotiator || DefaultNegotiator
    end

### Protected Class Methods

extract_expires_in(message) click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 272
    def self.extract_expires_in(message)
      # expires_in should be a base-10 string.
      expires_in_str = message.get_arg(OPENID_NS, 'expires_in', NO_DEFAULT)
      if !(/\A\d+\Z/ =~ expires_in_str)
        raise ProtocolError, "Invalid expires_in field: #{expires_in_str}"
      end
      expires_in_str.to_i
    end

### Public Instance Methods

get_association() click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 111
    def get_association
      if @store.nil?
        return nil
      end

      assoc = @store.get_association(@server_url)
      if assoc.nil? || assoc.expires_in <= 0
        assoc = negotiate_association
        if !assoc.nil?
          @store.store_association(@server_url, assoc)
        end
      end

      return assoc
    end

negotiate_association() click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 127
    def negotiate_association
      assoc_type, session_type = @negotiator.get_allowed_type
      begin
        return request_association(assoc_type, session_type)
      rescue ServerError => why
        supported_types = extract_supported_association_type(why, assoc_type)
        if !supported_types.nil?
          # Attempt to create an association from the assoc_type and
          # session_type that the server told us it supported.
          assoc_type, session_type = supported_types
          begin
            return request_association(assoc_type, session_type)
          rescue ServerError => why
            Util.log("Server #{@server_url} refused its suggested "                         "association type: session_type=#{session_type}, "                         "assoc_type=#{assoc_type}")
            return nil
          end
        end
      rescue InvalidOpenIDNamespace
        Util.log("Server #{@server_url} returned a malformed association "                     "response.  Falling back to check_id mode for this request.")
        return nil
      end
    end

### Protected Instance Methods

create_associate_request(assoc_type, session_type) click to toggle source

Create an association request for the given assoc_type and session_type. Returns a pair of the association session object and the request message that will be sent to the server.

    # File lib/openid/consumer/associationmanager.rb, line 215
    def create_associate_request(assoc_type, session_type)
      assoc_session = self.class.create_session(session_type)
      args = {
        'mode' => 'associate',
        'assoc_type' => assoc_type,
      }

      if !@compatibility_mode
        args['ns'] = OPENID2_NS
      end

      # Leave out the session type if we're in compatibility mode
      # *and* it's no-encryption.
      if !@compatibility_mode ||
          assoc_session.class.session_type != 'no-encryption'
        args['session_type'] = assoc_session.class.session_type
      end

      args.merge!(assoc_session.get_request)
      message = Message.from_openid_args(args)
      return assoc_session, message
    end

extract_association(assoc_response, assoc_session) click to toggle source

Attempt to extract an association from the response, given the association response message and the established association session.

    # File lib/openid/consumer/associationmanager.rb, line 284
    def extract_association(assoc_response, assoc_session)
      # Extract the common fields from the response, raising an
      # exception if they are not found
      assoc_type = assoc_response.get_arg(OPENID_NS, 'assoc_type',
                                          NO_DEFAULT)
      assoc_handle = assoc_response.get_arg(OPENID_NS, 'assoc_handle',
                                            NO_DEFAULT)
      expires_in = self.class.extract_expires_in(assoc_response)

      # OpenID 1 has funny association session behaviour.
      if assoc_response.is_openid1
          session_type = get_openid1_session_type(assoc_response)
      else
        session_type = assoc_response.get_arg(OPENID2_NS, 'session_type',
                                              NO_DEFAULT)
      end

      # Session type mismatch
      if assoc_session.class.session_type != session_type
        if (assoc_response.is_openid1 and session_type == 'no-encryption')
          # In OpenID 1, any association request can result in a
          # 'no-encryption' association response. Setting
          # assoc_session to a new no-encryption session should
          # make the rest of this function work properly for
          # that case.
          assoc_session = NoEncryptionSession.new
        else
          # Any other mismatch, regardless of protocol version
          # results in the failure of the association session
          # altogether.
          raise ProtocolError, "Session type mismatch. Expected "                                  "#{assoc_session.class.session_type}, got "                                  "#{session_type}"
        end
      end

      # Make sure assoc_type is valid for session_type
      if !assoc_session.class.allowed_assoc_types.member?(assoc_type)
        raise ProtocolError, "Unsupported assoc_type for session "                                "#{assoc_session.class.session_type} "                                "returned: #{assoc_type}"
      end

      # Delegate to the association session to extract the secret
      # from the response, however is appropriate for that session
      # type.
      begin
        secret = assoc_session.extract_secret(assoc_response)
      rescue Message::KeyNotFound, ArgumentError => why
        raise ProtocolError, "Malformed response for "                                "#{assoc_session.class.session_type} "                                "session: #{why.message}"
      end

      return Association.from_expires_in(expires_in, assoc_handle, secret,
                                         assoc_type)
    end

extract_supported_association_type(server_error, assoc_type) click to toggle source

    # File lib/openid/consumer/associationmanager.rb, line 154
    def extract_supported_association_type(server_error, assoc_type)
      # Any error message whose code is not 'unsupported-type' should
      # be considered a total failure.
      if (server_error.error_code != 'unsupported-type' or
          server_error.message.is_openid1)
        Util.log("Server error when requesting an association from "                    "#{@server_url}: #{server_error.error_text}")
        return nil
      end

      # The server didn't like the association/session type that we
      # sent, and it sent us back a message that might tell us how to
      # handle it.
      Util.log("Unsupported association type #{assoc_type}: "                  "#{server_error.error_text}")

      # Extract the session_type and assoc_type from the error message
      assoc_type = server_error.message.get_arg(OPENID_NS, 'assoc_type')
      session_type = server_error.message.get_arg(OPENID_NS, 'session_type')

      if assoc_type.nil? or session_type.nil?
        Util.log("Server #{@server_url} responded with unsupported "                    "association session but did not supply a fallback.")
        return nil
      elsif !@negotiator.allowed?(assoc_type, session_type)
        Util.log("Server sent unsupported session/association type: "                    "session_type=#{session_type}, assoc_type=#{assoc_type}")
        return nil
      else
        return [assoc_type, session_type]
      end
    end

get_openid1_session_type(assoc_response) click to toggle source

Given an association response message, extract the OpenID 1.X session type. Returns the association type for this message

This function mostly takes care of the 'no-encryption' default behavior in OpenID 1.

If the association type is plain-text, this function will return 'no-encryption'

    # File lib/openid/consumer/associationmanager.rb, line 246
    def get_openid1_session_type(assoc_response)
      # If it's an OpenID 1 message, allow session_type to default
      # to nil (which signifies "no-encryption")
      session_type = assoc_response.get_arg(OPENID_NS, 'session_type')

      # Handle the differences between no-encryption association
      # respones in OpenID 1 and 2:

      # no-encryption is not really a valid session type for
      # OpenID 1, but we'll accept it anyway, while issuing a
      # warning.
      if session_type == 'no-encryption'
        Util.log("WARNING: #{@server_url} sent 'no-encryption'"                    "for OpenID 1.X")

      # Missing or empty session type is the way to flag a
      # 'no-encryption' response. Change the session type to
      # 'no-encryption' so that it can be handled in the same
      # way as OpenID 2 'no-encryption' respones.
      elsif session_type == '' || session_type.nil?
        session_type = 'no-encryption'
      end

      return session_type
    end

request_association(assoc_type, session_type) click to toggle source

Make and process one association request to this endpoint's OP endpoint URL. Returns an association object or nil if the association processing failed. Raises ServerError when the remote OpenID server returns an error.

    # File lib/openid/consumer/associationmanager.rb, line 191
    def request_association(assoc_type, session_type)
      assoc_session, args = create_associate_request(assoc_type, session_type)

      begin
        response = OpenID.make_kv_post(args, @server_url)
        return extract_association(response, assoc_session)
      rescue HTTPStatusError => why
        Util.log("Got HTTP status error when requesting association: #{why}")
        return nil
      rescue Message::KeyNotFound => why
        Util.log("Missing required parameter in response from "                    "#{@server_url}: #{why}")
        return nil

      rescue ProtocolError => why
        Util.log("Protocol error processing response from #{@server_url}: "                    "#{why}")
        return nil
      end
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.