Class: OpenID::Association
- Inherits:
-
Object
- Object
- OpenID::Association
- Defined in:
- lib/openid/association.rb
Overview
An Association holds the shared secret between a relying party and an OpenID provider.
Constant Summary collapse
- FIELD_ORDER =
i[version handle secret issued lifetime assoc_type]
Instance Attribute Summary collapse
-
#assoc_type ⇒ Object
readonly
Returns the value of attribute assoc_type.
-
#handle ⇒ Object
readonly
Returns the value of attribute handle.
-
#issued ⇒ Object
readonly
Returns the value of attribute issued.
-
#lifetime ⇒ Object
readonly
Returns the value of attribute lifetime.
-
#secret ⇒ Object
readonly
Returns the value of attribute secret.
Class Method Summary collapse
-
.deserialize(serialized) ⇒ Object
Load a serialized Association.
-
.from_expires_in(expires_in, handle, secret, assoc_type) ⇒ Object
Create an Association with an issued time of now.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#check_message_signature(message) ⇒ Object
Return whether the message’s signature passes.
-
#expires_in(now = nil) ⇒ Object
The number of seconds until this association expires.
-
#get_message_signature(message) ⇒ Object
Get the signature for this message.
-
#initialize(handle, secret, issued, lifetime, assoc_type) ⇒ Association
constructor
A new instance of Association.
-
#make_pairs(message) ⇒ Object
Generate the list of pairs that form the signed elements of the given message.
-
#serialize ⇒ Object
Serialize the association to a form that’s consistent across JanRain OpenID libraries.
-
#sign(pairs) ⇒ Object
Generate a signature for a sequence of [key, value] pairs.
-
#sign_message(message) ⇒ Object
Add a signature (and a signed list) to a message.
Constructor Details
#initialize(handle, secret, issued, lifetime, assoc_type) ⇒ Association
Returns a new instance of Association.
55 56 57 58 59 60 61 |
# File 'lib/openid/association.rb', line 55 def initialize(handle, secret, issued, lifetime, assoc_type) @handle = handle @secret = secret @issued = issued @lifetime = lifetime @assoc_type = assoc_type end |
Instance Attribute Details
#assoc_type ⇒ Object (readonly)
Returns the value of attribute assoc_type.
20 21 22 |
# File 'lib/openid/association.rb', line 20 def assoc_type @assoc_type end |
#handle ⇒ Object (readonly)
Returns the value of attribute handle.
20 21 22 |
# File 'lib/openid/association.rb', line 20 def handle @handle end |
#issued ⇒ Object (readonly)
Returns the value of attribute issued.
20 21 22 |
# File 'lib/openid/association.rb', line 20 def issued @issued end |
#lifetime ⇒ Object (readonly)
Returns the value of attribute lifetime.
20 21 22 |
# File 'lib/openid/association.rb', line 20 def lifetime @lifetime end |
#secret ⇒ Object (readonly)
Returns the value of attribute secret.
20 21 22 |
# File 'lib/openid/association.rb', line 20 def secret @secret end |
Class Method Details
.deserialize(serialized) ⇒ Object
Load a serialized Association
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/openid/association.rb', line 26 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 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) ⇒ Object
Create an Association with an issued time of now
50 51 52 53 |
# File 'lib/openid/association.rb', line 50 def self.from_expires_in(expires_in, handle, secret, assoc_type) issued = Time.now new(handle, secret, issued, expires_in, assoc_type) end |
Instance Method Details
#==(other) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/openid/association.rb', line 133 def ==(other) (other.class == self.class and other.handle == handle and other.secret == 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 == issued.to_i and other.lifetime == lifetime and other.assoc_type == assoc_type) end |
#check_message_signature(message) ⇒ Object
Return whether the message’s signature passes
120 121 122 123 124 125 126 |
# File 'lib/openid/association.rb', line 120 def () = .get_arg(OPENID_NS, "sig") raise ProtocolError, "#{message} has no sig." if .nil? calculated_sig = () CryptUtil.const_eq(calculated_sig, ) end |
#expires_in(now = nil) ⇒ Object
The number of seconds until this association expires
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/openid/association.rb', line 82 def expires_in(now = nil) now = if now.nil? Time.now.to_i else now.to_i end time_diff = (issued.to_i + lifetime) - now return 0 if time_diff < 0 time_diff end |
#get_message_signature(message) ⇒ Object
Get the signature for this message
129 130 131 |
# File 'lib/openid/association.rb', line 129 def () Util.to_base64(sign(make_pairs())) end |
#make_pairs(message) ⇒ Object
Generate the list of pairs that form the signed elements of the given message
110 111 112 113 114 115 116 117 |
# File 'lib/openid/association.rb', line 110 def make_pairs() signed = .get_arg(OPENID_NS, "signed") raise ProtocolError, "Missing signed list" if signed.nil? signed_fields = signed.split(",", -1) data = .to_post_args signed_fields.map { |field| [field, data.fetch("openid." + field, "")] } end |
#serialize ⇒ Object
Serialize the association to a form that’s consistent across JanRain OpenID libraries.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/openid/association.rb', line 65 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.truthy_assert(data.length == FIELD_ORDER.length) pairs = FIELD_ORDER.map { |field| [field.to_s, data[field]] } Util.seq_to_kv(pairs, true) end |
#sign(pairs) ⇒ Object
Generate a signature for a sequence of [key, value] pairs
95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/openid/association.rb', line 95 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) ⇒ Object
Add a signature (and a signed list) to a message.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/openid/association.rb', line 148 def () if .has_key?(OPENID_NS, "sig") or .has_key?(OPENID_NS, "signed") raise ArgumentError, "Message already has signed list or signature" end extant_handle = .get_arg(OPENID_NS, "assoc_handle") raise ArgumentError, "Message has a different association handle" if extant_handle and extant_handle != handle = .copy .set_arg(OPENID_NS, "assoc_handle", handle) = .to_post_args.keys signed_list = [] .each do |k| signed_list << k[7..-1] if k.start_with?("openid.") end signed_list << "signed" signed_list.sort! .set_arg(OPENID_NS, "signed", signed_list.join(",")) sig = () .set_arg(OPENID_NS, "sig", sig) end |