diff options
Diffstat (limited to 'vendor/gems/ruby-openid-2.1.4/lib/openid/consumer/associationmanager.rb')
-rw-r--r-- | vendor/gems/ruby-openid-2.1.4/lib/openid/consumer/associationmanager.rb | 340 |
1 files changed, 0 insertions, 340 deletions
diff --git a/vendor/gems/ruby-openid-2.1.4/lib/openid/consumer/associationmanager.rb b/vendor/gems/ruby-openid-2.1.4/lib/openid/consumer/associationmanager.rb deleted file mode 100644 index 51c0f3d25..000000000 --- a/vendor/gems/ruby-openid-2.1.4/lib/openid/consumer/associationmanager.rb +++ /dev/null @@ -1,340 +0,0 @@ -require "openid/dh" -require "openid/util" -require "openid/kvpost" -require "openid/cryptutil" -require "openid/protocolerror" -require "openid/association" - -module OpenID - class Consumer - - # A superclass for implementing Diffie-Hellman association sessions. - class DiffieHellmanSession - class << self - attr_reader :session_type, :secret_size, :allowed_assoc_types, - :hashfunc - end - - def initialize(dh=nil) - if dh.nil? - dh = DiffieHellman.from_defaults - end - @dh = dh - end - - # Return the query parameters for requesting an association - # using this Diffie-Hellman association session - def get_request - args = {'dh_consumer_public' => CryptUtil.num_to_base64(@dh.public)} - if (!@dh.using_default_values?) - args['dh_modulus'] = CryptUtil.num_to_base64(@dh.modulus) - args['dh_gen'] = CryptUtil.num_to_base64(@dh.generator) - end - - return args - end - - # Process the response from a successful association request and - # return the shared secret for this association - def extract_secret(response) - dh_server_public64 = response.get_arg(OPENID_NS, 'dh_server_public', - NO_DEFAULT) - enc_mac_key64 = response.get_arg(OPENID_NS, 'enc_mac_key', NO_DEFAULT) - dh_server_public = CryptUtil.base64_to_num(dh_server_public64) - enc_mac_key = Util.from_base64(enc_mac_key64) - return @dh.xor_secret(self.class.hashfunc, - dh_server_public, enc_mac_key) - end - end - - # A Diffie-Hellman association session that uses SHA1 as its hash - # function - class DiffieHellmanSHA1Session < DiffieHellmanSession - @session_type = 'DH-SHA1' - @secret_size = 20 - @allowed_assoc_types = ['HMAC-SHA1'] - @hashfunc = CryptUtil.method(:sha1) - end - - # A Diffie-Hellman association session that uses SHA256 as its hash - # function - class DiffieHellmanSHA256Session < DiffieHellmanSession - @session_type = 'DH-SHA256' - @secret_size = 32 - @allowed_assoc_types = ['HMAC-SHA256'] - @hashfunc = CryptUtil.method(:sha256) - end - - # An association session that does not use encryption - class NoEncryptionSession - class << self - attr_reader :session_type, :allowed_assoc_types - end - @session_type = 'no-encryption' - @allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256'] - - def get_request - return {} - end - - def extract_secret(response) - mac_key64 = response.get_arg(OPENID_NS, 'mac_key', NO_DEFAULT) - return Util.from_base64(mac_key64) - end - end - - # An object that manages creating and storing associations for an - # OpenID provider endpoint - class AssociationManager - 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 - - def initialize(store, server_url, compatibility_mode=false, - negotiator=nil) - @store = store - @server_url = server_url - @compatibility_mode = compatibility_mode - @negotiator = negotiator || DefaultNegotiator - end - - 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 - - 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 - end - end - - protected - 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 - - # 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. - 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 - - # 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. - 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 - - # 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' - 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(OPENID1_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 - - 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 - - # Attempt to extract an association from the response, given the - # association response message and the established association - # session. - 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 - end - end -end |