Class: OpenID::Association

### Home Classes Methods

### In Files

- lib/openid/association.rb

### Parent

Object

### Methods

- ::deserialize
- ::from_expires_in
- ::new
- #==
- #check_message_signature
- #expires_in
- #get_message_signature
- #make_pairs
- #serialize
- #sign
- #sign_message

### 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::Association

An Association holds the shared secret between a relying party and an OpenID provider.

### Constants

FIELD_ORDER

### Attributes

assoc_type[R]
handle[R]
issued[R]
lifetime[R]
secret[R]

### Public Class Methods

deserialize(serialized) click to toggle source

Load a serialized Association

    # File lib/openid/association.rb, line 27
    def self.deserialize(serialized)
      parsed = Util.kv_to_seq(serialized)
      parsed_fields = parsed.map{|k, v| k.to_sym}
      if parsed_fields != FIELD_ORDER
          raise ProtocolError, 'Unexpected fields in serialized association'           " (Expected #{FIELD_ORDER.inspect}, got #{parsed_fields.inspect})"
      end
      version, handle, secret64, issued_s, lifetime_s, assoc_type =
        parsed.map {|field, value| value}
      if version != '2'
        raise ProtocolError, "Attempted to deserialize unsupported version "                              "(#{parsed[0][1].inspect})"
      end

      self.new(handle,
               Util.from_base64(secret64),
               Time.at(issued_s.to_i),
               lifetime_s.to_i,
               assoc_type)
    end

from_expires_in(expires_in, handle, secret, assoc_type) click to toggle source

Create an Association with an issued time of now

    # File lib/openid/association.rb, line 49
    def self.from_expires_in(expires_in, handle, secret, assoc_type)
      issued = Time.now
      self.new(handle, secret, issued, expires_in, assoc_type)
    end

new(handle, secret, issued, lifetime, assoc_type) click to toggle source

    # File lib/openid/association.rb, line 54
    def initialize(handle, secret, issued, lifetime, assoc_type)
      @handle = handle
      @secret = secret
      @issued = issued
      @lifetime = lifetime
      @assoc_type = assoc_type
    end

### Public Instance Methods

==(other) click to toggle source

    # File lib/openid/association.rb, line 136
    def ==(other)
      (other.class == self.class and
       other.handle == self.handle and
       other.secret == self.secret and

       # The internals of the time objects seemed to differ
       # in an opaque way when serializing/unserializing.
       # I don't think this will be a problem.
       other.issued.to_i == self.issued.to_i and

       other.lifetime == self.lifetime and
       other.assoc_type == self.assoc_type)
    end

check_message_signature(message) click to toggle source

Return whether the message's signature passes

    # File lib/openid/association.rb, line 122
    def check_message_signature(message)
      message_sig = message.get_arg(OPENID_NS, 'sig')
      if message_sig.nil?
        raise ProtocolError, "#{message} has no sig."
      end
      calculated_sig = get_message_signature(message)
      return CryptUtil.const_eq(calculated_sig, message_sig)
    end

expires_in(now=nil) click to toggle source

The number of seconds until this association expires

    # File lib/openid/association.rb, line 81
    def expires_in(now=nil)
      if now.nil?
        now = Time.now.to_i
      else
        now = now.to_i
      end
      time_diff = (issued.to_i + lifetime) - now
      if time_diff < 0
        return 0
      else
        return time_diff
      end
    end

get_message_signature(message) click to toggle source

Get the signature for this message

    # File lib/openid/association.rb, line 132
    def get_message_signature(message)
      Util.to_base64(sign(make_pairs(message)))
    end

make_pairs(message) click to toggle source

Generate the list of pairs that form the signed elements of the given message

    # File lib/openid/association.rb, line 111
    def make_pairs(message)
      signed = message.get_arg(OPENID_NS, 'signed')
      if signed.nil?
        raise ProtocolError, 'Missing signed list'
      end
      signed_fields = signed.split(',', -1)
      data = message.to_post_args
      signed_fields.map {|field| [field, data.fetch('openid.'+field,'')] }
    end

serialize() click to toggle source

Serialize the association to a form that's consistent across JanRain OpenID libraries.

    # File lib/openid/association.rb, line 64
    def serialize
      data = {
        :version => '2',
        :handle => handle,
        :secret => Util.to_base64(secret),
        :issued => issued.to_i.to_s,
        :lifetime => lifetime.to_i.to_s,
        :assoc_type => assoc_type,
      }

      Util.assert(data.length == FIELD_ORDER.length)

      pairs = FIELD_ORDER.map{|field| [field.to_s, data[field]]}
      return Util.seq_to_kv(pairs, true)
    end

sign(pairs) click to toggle source

Generate a signature for a sequence of [key, value] pairs

    # File lib/openid/association.rb, line 96
    def sign(pairs)
      kv = Util.seq_to_kv(pairs)
      case assoc_type
      when 'HMAC-SHA1'
        CryptUtil.hmac_sha1(@secret, kv)
      when 'HMAC-SHA256'
        CryptUtil.hmac_sha256(@secret, kv)
      else
        raise ProtocolError, "Association has unknown type: "           "#{assoc_type.inspect}"
      end
    end

sign_message(message) click to toggle source

Add a signature (and a signed list) to a message.

    # File lib/openid/association.rb, line 151
    def sign_message(message)
      if (message.has_key?(OPENID_NS, 'sig') or
          message.has_key?(OPENID_NS, 'signed'))
        raise ArgumentError, 'Message already has signed list or signature'
      end

      extant_handle = message.get_arg(OPENID_NS, 'assoc_handle')
      if extant_handle and extant_handle != self.handle
        raise ArgumentError, "Message has a different association handle"
      end

      signed_message = message.copy()
      signed_message.set_arg(OPENID_NS, 'assoc_handle', self.handle)
      message_keys = signed_message.to_post_args.keys()

      signed_list = []
      message_keys.each { |k|
        if k.start_with?('openid.')
          signed_list << k[7..-1]
        end
      }

      signed_list << 'signed'
      signed_list.sort!

      signed_message.set_arg(OPENID_NS, 'signed', signed_list.join(','))
      sig = get_message_signature(signed_message)
      signed_message.set_arg(OPENID_NS, 'sig', sig)
      return signed_message
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.