class OmfCommon::Message::Json::Message
Public Class Methods
create(type, properties, body = {})
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 24 def self.create(type, properties, body = {}) if type == :request unless (req_props = properties).kind_of?(Array) raise "Expected array, but got #{properties.class} for request message" end #properties = {select: properties} properties = {} req_props.each {|n| properties[n] = nil } elsif not properties.kind_of?(Hash) raise "Expected hash, but got #{properties.class}" end content = body.merge({ op: type, mid: SecureRandom.uuid, ts: Time.now.to_i, props: properties }) issuer = self.authenticate? ? (body[:issuer] || body[:src]) : nil self.new(content, issuer) end
create_inform_message(itype = nil, properties = {}, body = {})
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 46 def self.create_inform_message(itype = nil, properties = {}, body = {}) body[:itype] = itype if itype create(:inform, properties, body) end
new(content, issuer = nil)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 226 def initialize(content, issuer = nil) debug "Create message: #{content.inspect}" unless op = content[:op] raise "Missing message type (:operation)" end @content = {} @issuer = issuer content[:op] = op.to_sym # needs to be symbol if src = content[:src] content[:src] = OmfCommon.comm.create_topic(src) end content.each {|k,v| _set_core(k, v)} @properties = content[:props] || [] #@properties = Hashie::Mash.new(content[:properties]) @authenticate = self.class.authenticate? # keep track if we sent local certs on a topic. Should do this the first time @certOnTopic = {} end
parse(str, content_type, &block)
click to toggle source
Create and authenticate, if necessary a message and pass it on to ‘block’ if parsing (and authentication) is successful.
# File lib/omf_common/message/json/json_message.rb, line 54 def self.parse(str, content_type, &block) #puts "CT>> #{content_type}" issuer = nil case content_type.to_s when 'jwt' content, issuer = parse_jwt(str, &block) when 'text/json' content = JSON.parse(str, :symbolize_names => true) else warn "Received message with unknown content type '#{content_type}'" end #puts "CTTT>> #{content}::#{content.class}" if (content) msg = new(content, issuer) block.call(msg) end end
parse_jwt(jwt_string)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 72 def self.parse_jwt(jwt_string) key_or_secret = :skip_verification # Code lifted from 'json-jwt-0.4.3/lib/json/jwt.rb' case jwt_string.count('.') when 2 # JWT / JWS header, claims, signature = jwt_string.split('.', 3).collect do |segment| UrlSafeBase64.decode64 segment.to_s end header, claims = [header, claims].collect do |json| #MultiJson.load(json).with_indifferent_access JSON.parse(json, :symbolize_names => true) end signature_base_string = jwt_string.split('.')[0, 2].join('.') jwt = JSON::JWT.new claims jwt.header = header jwt.signature = signature # NOTE: # Some JSON libraries generates wrong format of JSON (spaces between keys and values etc.) # So we need to use raw base64 strings for signature verification. unless issuer = claims[:iss] warn "JWT: Message is missing :iss element" return nil end if cert_pem = claims[:crt] # let's the credential store take care of it pem = "#{OmfCommon::Auth::Certificate::BEGIN_CERT}#{cert_pem}#{OmfCommon::Auth::Certificate::END_CERT}" cert = OmfCommon::Auth::Certificate.create_from_pem(pem) cert.resource_id = issuer OmfCommon::Auth::CertificateStore.instance.register(cert) end unless cert = OmfCommon::Auth::CertificateStore.instance.cert_for(issuer) warn "JWT: Can't find cert for issuer '#{issuer}'" return nil end unless OmfCommon::Auth::CertificateStore.instance.verify(cert) warn "JWT: Invalid certificate '#{cert.to_s}', NOT signed by CA certs, or its CA cert NOT loaded into cert store." return nil end #puts ">>> #{cert.to_x509.public_key}::#{signature_base_string}" jwt.verify signature_base_string, cert.to_x509.public_key #unless key_or_secret == :skip_verification [JSON.parse(claims[:cnt], :symbolize_names => true), cert] else warn('JWT: Invalid Format. JWT should include 2 or 3 dots.') return nil end end
Public Instance Methods
each_bound_request_property(&block)
click to toggle source
Loop over all the bound (sent with a value) properties of a request message.
# File lib/omf_common/message/json/json_message.rb, line 162 def each_bound_request_property(&block) unless type == :request raise "Can only be used for request messages" end self[:select].each do |el| #puts "BBB #{el}::#{el.class}" if el.is_a? Hash el.each do |key, value| block.call(key, value) end end end end
each_property(&block)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 123 def each_property(&block) @properties.each do |k, v| #unless INTERNAL_PROPS.include?(k.to_sym) block.call(k, v) #end end end
each_unbound_request_property(&block)
click to toggle source
Loop over all the unbound (sent without a value) properties of a request message.
# File lib/omf_common/message/json/json_message.rb, line 147 def each_unbound_request_property(&block) unless type == :request raise "Can only be used for request messages" end self[:select].each do |el| #puts "UUU: #{el}::#{el.class}" if el.is_a? Symbol block.call(el) end end end
has_properties?()
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 136 def has_properties? not @properties.empty? end
marshall(topic)
click to toggle source
Marshall message into a string to be shipped across the network. Depending on authentication setting, the message will be signed as well, or maybe even dropped.
@param [Topic] topic for which to marshall
# File lib/omf_common/message/json/json_message.rb, line 187 def marshall(topic) #puts "MARSHALL: #{@content.inspect} - #{@properties.to_hash.inspect}" raise "Missing SRC declaration in #{@content}" unless @content[:src] if @content[:src].is_a? OmfCommon::Comm::Topic @content[:src] = @content[:src].address end @content[:itype] = self.itype(:frcp) unless self.itype(:frcp).nil? #raise 'local/local' if @content[:src].id.match 'local:/local' #puts @content.inspect payload = @content.to_json if self.class.authenticate? unless issuer = self.issuer raise "Missing ISSUER for '#{self}'" end if issuer.is_a? OmfCommon::Auth::CertificateStore cert = issuer issuer = cert.subject else cert = OmfCommon::Auth::CertificateStore.instance.cert_for(issuer) end if cert && cert.can_sign? debug "Found cert for '#{issuer} - #{cert}" msg = {cnt: payload, iss: issuer} unless @certOnTopic[k = [topic, issuer]] # first time for this issuer on this topic, so let's send the cert along msg[:crt] = cert.to_pem_compact #ALWAYS ADD CERT @certOnTopic[k] = Time.now end #:RS256, :RS384, :RS512 p = JSON::JWT.new(msg).sign(cert.key , :RS256).to_s #puts "SIGNED>> #{msg}" return ['jwt', p] end end ['text/json', payload] end
properties()
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 131 def properties @properties end
to_s()
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 177 def to_s "JsonMessage: #{@content.inspect}" end
valid?()
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 140 def valid? true # don't do schema verification , yet end
Private Instance Methods
_get_core(key)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 249 def _get_core(key) @content[@@key2json_key[key] || key] end
_get_property(key, ns = nil)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 258 def _get_property(key, ns = nil) warn "Can't handle namespaces yet" if ns #puts key @properties[key] end
_set_core(key, value)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 245 def _set_core(key, value) @content[(@@key2json_key[key] || key).to_sym] = value end
_set_property(key, value, ns = nil)
click to toggle source
# File lib/omf_common/message/json/json_message.rb, line 253 def _set_property(key, value, ns = nil) warn "Can't handle namespaces yet" if ns @properties[key] = value end