omf_common 6.0.0 → 6.0.2.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +4 -0
- data/bin/file_broadcaster.rb +56 -0
- data/bin/file_receiver.rb +62 -0
- data/bin/omf_keygen +21 -0
- data/bin/{monitor_topic.rb → omf_monitor_topic} +21 -8
- data/bin/omf_send_create +118 -0
- data/bin/{send_request.rb → omf_send_request} +12 -7
- data/example/engine_alt.rb +23 -24
- data/example/ls_app.yaml +21 -0
- data/lib/omf_common.rb +73 -12
- data/lib/omf_common/auth.rb +15 -0
- data/lib/omf_common/auth/certificate.rb +174 -0
- data/lib/omf_common/auth/certificate_store.rb +72 -0
- data/lib/omf_common/auth/ssh_pub_key_convert.rb +80 -0
- data/lib/omf_common/comm.rb +66 -9
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +40 -13
- data/lib/omf_common/comm/amqp/amqp_file_transfer.rb +259 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +14 -21
- data/lib/omf_common/comm/local/local_communicator.rb +31 -2
- data/lib/omf_common/comm/local/local_topic.rb +19 -3
- data/lib/omf_common/comm/topic.rb +48 -34
- data/lib/omf_common/comm/xmpp/communicator.rb +19 -10
- data/lib/omf_common/comm/xmpp/topic.rb +22 -81
- data/lib/omf_common/default_logging.rb +11 -0
- data/lib/omf_common/eventloop.rb +14 -0
- data/lib/omf_common/eventloop/em.rb +39 -6
- data/lib/omf_common/eventloop/local_evl.rb +15 -0
- data/lib/omf_common/exec_app.rb +29 -15
- data/lib/omf_common/message.rb +53 -5
- data/lib/omf_common/message/json/json_message.rb +149 -39
- data/lib/omf_common/message/xml/message.rb +112 -39
- data/lib/omf_common/protocol/6.0.rnc +5 -1
- data/lib/omf_common/protocol/6.0.rng +12 -0
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +7 -2
- data/test/fixture/omf_test.cert.pem +15 -0
- data/test/fixture/omf_test.pem +15 -0
- data/test/fixture/omf_test.pub +1 -0
- data/test/fixture/omf_test.pub.pem +6 -0
- data/test/omf_common/auth/certificate_spec.rb +113 -0
- data/test/omf_common/auth/ssh_pub_key_convert_spec.rb +13 -0
- data/test/omf_common/comm/topic_spec.rb +175 -0
- data/test/omf_common/comm/xmpp/communicator_spec.rb +15 -16
- data/test/omf_common/comm/xmpp/topic_spec.rb +63 -10
- data/test/omf_common/comm_spec.rb +66 -9
- data/test/omf_common/message/xml/message_spec.rb +43 -13
- data/test/omf_common/message_spec.rb +14 -0
- data/test/test_helper.rb +25 -0
- metadata +78 -15
- data/bin/send_create.rb +0 -94
@@ -9,7 +9,6 @@ require 'omf_common/message/xml/relaxng_schema'
|
|
9
9
|
module OmfCommon
|
10
10
|
class Message
|
11
11
|
class XML
|
12
|
-
|
13
12
|
# @example To create a valid omf message, e.g. a 'create' message:
|
14
13
|
#
|
15
14
|
# Message.create(:create,
|
@@ -47,12 +46,46 @@ class XML
|
|
47
46
|
new(content)
|
48
47
|
end
|
49
48
|
|
50
|
-
def parse(xml)
|
49
|
+
def parse(xml, content_type = "text/xml", &block)
|
50
|
+
raise ArgumentError, 'Need message handling block' unless block
|
51
|
+
|
52
|
+
content_type ||= "text/xml" # Since by default parent class pass in nil object
|
53
|
+
raise ArgumentError, "Unknown content type: #{content_type}" unless content_type =~ /xml/
|
51
54
|
raise ArgumentError, 'Can not parse an empty XML into OMF message' if xml.nil? || xml.empty?
|
52
55
|
|
53
56
|
xml_node = Nokogiri::XML(xml).root
|
54
57
|
|
55
|
-
|
58
|
+
if xml_node.name.to_sym == :env # envelope
|
59
|
+
cert = xml_node.element_children.find { |v| v.element_name == 'cert' }.content
|
60
|
+
sig = xml_node.element_children.find { |v| v.element_name == 'sig' }.content
|
61
|
+
iss = xml_node.element_children.find { |v| v.element_name == 'iss' }.content
|
62
|
+
xml_node = xml_node.element_children.find { |v| v.element_name =~ /create|request|configure|release|inform/ }
|
63
|
+
|
64
|
+
if self.authenticate?
|
65
|
+
existing_cert = OmfCommon::Auth::CertificateStore.instance.cert_for(iss)
|
66
|
+
|
67
|
+
if existing_cert
|
68
|
+
cert = existing_cert
|
69
|
+
else
|
70
|
+
OmfCommon::Auth::CertificateStore.instance.register_x509(cert, iss)
|
71
|
+
cert = OmfCommon::Auth::CertificateStore.instance.cert_for(iss)
|
72
|
+
end
|
73
|
+
|
74
|
+
unless cert.verify_cert
|
75
|
+
warn "Invalid certificate '#{cert.to_s}', NOT signed by root certificate."
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
canonicalised_xml_node = fix_canonicalised_xml(xml_node.canonicalize)
|
80
|
+
|
81
|
+
unless cert.to_x509.public_key.verify(OpenSSL::Digest::SHA256.new(canonicalised_xml_node), Base64.decode64(sig), canonicalised_xml_node)
|
82
|
+
warn "Verfication failed #{canonicalised_xml_node} #{OpenSSL::Digest::SHA256.new(canonicalised_xml_node)}"
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
parsed_msg = self.create(xml_node.name.to_sym).tap do |message|
|
56
89
|
message.xml = xml_node
|
57
90
|
|
58
91
|
message.send(:_set_core, :mid, message.xml.attr('mid'))
|
@@ -82,6 +115,8 @@ class XML
|
|
82
115
|
MPMessage.inject(Time.now.to_f, message.operation.to_s, message.mid, message.cid, message.to_s.gsub("\n",''))
|
83
116
|
end
|
84
117
|
end
|
118
|
+
block.call(parsed_msg)
|
119
|
+
parsed_msg
|
85
120
|
end
|
86
121
|
end
|
87
122
|
|
@@ -90,17 +125,50 @@ class XML
|
|
90
125
|
OmfCommon::Comm::XMPP::Topic.create(r_id)
|
91
126
|
end
|
92
127
|
|
93
|
-
def itype
|
94
|
-
@content.itype.to_s.upcase.gsub(/_/, '.') unless @content.itype.nil?
|
95
|
-
end
|
96
|
-
|
97
128
|
def marshall
|
98
129
|
build_xml
|
99
|
-
|
130
|
+
|
131
|
+
if self.class.authenticate?
|
132
|
+
src = @content[:src]
|
133
|
+
src = src.address if src.is_a?(OmfCommon::Comm::Topic)
|
134
|
+
cert = OmfCommon::Auth::CertificateStore.instance.cert_for(src)
|
135
|
+
if cert && cert.can_sign?
|
136
|
+
debug "Found cert for '#{src} - #{cert}"
|
137
|
+
signature_node = Niceogiri::XML::Node.new(:sig)
|
138
|
+
|
139
|
+
canonicalised_xml = self.class.fix_canonicalised_xml(@xml.canonicalize)
|
140
|
+
|
141
|
+
signature = Base64.encode64(cert.key.sign(OpenSSL::Digest::SHA256.new(canonicalised_xml), canonicalised_xml)).encode('utf-8')
|
142
|
+
signature_node.add_child(signature)
|
143
|
+
|
144
|
+
@envelope = Niceogiri::XML::Node.new(:env, nil, OMF_NAMESPACE)
|
145
|
+
@envelope.add_child(@xml)
|
146
|
+
@envelope.add_child(signature_node)
|
147
|
+
|
148
|
+
iss_node = Niceogiri::XML::Node.new(:iss)
|
149
|
+
iss_node.add_child(src)
|
150
|
+
@envelope.add_child(iss_node)
|
151
|
+
|
152
|
+
#unless @certOnTopic[k = [topic, src]]
|
153
|
+
# first time for this src on this topic, so let's send the cert along
|
154
|
+
cert_node = Niceogiri::XML::Node.new(:cert)
|
155
|
+
cert_node.add_child(cert.to_pem_compact)
|
156
|
+
@envelope.add_child(cert_node)
|
157
|
+
#ALWAYS ADD CERT @certOnTopic[k] = Time.now
|
158
|
+
#end
|
159
|
+
['text/xml', @envelope]
|
160
|
+
else
|
161
|
+
error "Missing cert for #{src}"
|
162
|
+
['text/xml', nil]
|
163
|
+
end
|
164
|
+
else
|
165
|
+
['text/xml', @xml]
|
166
|
+
end
|
100
167
|
end
|
101
168
|
|
102
|
-
|
103
|
-
|
169
|
+
def to_s
|
170
|
+
@content
|
171
|
+
end
|
104
172
|
|
105
173
|
def build_xml
|
106
174
|
@xml = Niceogiri::XML::Node.new(self.operation.to_s, nil, OMF_NAMESPACE)
|
@@ -118,25 +186,30 @@ class XML
|
|
118
186
|
@xml.add_child(guard_node) if _get_core(:guard)
|
119
187
|
|
120
188
|
(OMF_CORE_READ - [:mid, :guard, :operation]).each do |attr|
|
121
|
-
attr_value =
|
189
|
+
attr_value = case attr
|
190
|
+
when :itype
|
191
|
+
self.itype(:frcp)
|
192
|
+
when :src
|
193
|
+
self.src.is_a?(OmfCommon::Comm::Topic) ? self.src.address : self.src
|
194
|
+
else
|
195
|
+
self.send(attr)
|
196
|
+
end
|
122
197
|
|
123
198
|
next unless attr_value
|
124
199
|
|
125
200
|
add_element(attr, attr_value) unless (self.operation != :release && attr == :res_id)
|
126
201
|
end
|
127
202
|
|
128
|
-
self.properties.each { |k, v| add_property(k, v) }
|
203
|
+
self.properties.each { |k, v| add_property(k, v) unless k == 'certificate'}
|
129
204
|
self.guard.each { |k, v| add_property(k, v, :guard) } if _get_core(:guard)
|
130
205
|
|
131
|
-
#digest = OpenSSL::Digest::SHA512.new(@xml.canonicalize)
|
132
|
-
|
133
|
-
#add_element(:digest, digest)
|
134
206
|
@xml
|
135
207
|
end
|
136
208
|
|
137
209
|
# Construct a property xml node
|
138
210
|
#
|
139
211
|
def add_property(key, value = nil, add_to = :props)
|
212
|
+
key = escape_key(key)
|
140
213
|
if !default_props_ns.empty? && add_to == :props
|
141
214
|
key_node = Niceogiri::XML::Node.new(key, nil, default_props_ns)
|
142
215
|
else
|
@@ -162,6 +235,7 @@ class XML
|
|
162
235
|
when Hash
|
163
236
|
[].tap do |array|
|
164
237
|
value.each_pair do |k, v|
|
238
|
+
k = escape_key(k)
|
165
239
|
n = Niceogiri::XML::Node.new(k, nil, OMF_NAMESPACE)
|
166
240
|
n.write_attr('type', ruby_type_2_prop_type(v.class))
|
167
241
|
|
@@ -191,33 +265,13 @@ class XML
|
|
191
265
|
if key.nil?
|
192
266
|
string_value(value)
|
193
267
|
else
|
268
|
+
key = escape_key(key)
|
194
269
|
n = Niceogiri::XML::Node.new(key, nil, OMF_NAMESPACE)
|
195
270
|
n.add_child(string_value(value))
|
196
271
|
end
|
197
272
|
end
|
198
273
|
end
|
199
274
|
|
200
|
-
# Generate SHA1 of canonicalised xml and write into the ID attribute of the message
|
201
|
-
#
|
202
|
-
def sign
|
203
|
-
write_attr('mid', SecureRandom.uuid)
|
204
|
-
write_attr('ts', Time.now.utc.to_i)
|
205
|
-
canonical_msg = self.canonicalize
|
206
|
-
|
207
|
-
#priv_key = OmfCommon::Key.instance.private_key
|
208
|
-
#digest = OpenSSL::Digest::SHA512.new(canonical_msg)
|
209
|
-
|
210
|
-
#signature = Base64.encode64(priv_key.sign(digest, canonical_msg)).encode('utf-8') if priv_key
|
211
|
-
#write_attr('digest', digest)
|
212
|
-
#write_attr('signature', signature) if signature
|
213
|
-
|
214
|
-
if OmfCommon::Measure.enabled?
|
215
|
-
MPMessage.inject(Time.now.to_f, operation.to_s, mid, cid, self.to_s.gsub("\n",''))
|
216
|
-
@@mid_list << mid
|
217
|
-
end
|
218
|
-
self
|
219
|
-
end
|
220
|
-
|
221
275
|
# Validate against relaxng schema
|
222
276
|
#
|
223
277
|
def valid?
|
@@ -236,6 +290,7 @@ class XML
|
|
236
290
|
# Short cut for adding xml node
|
237
291
|
#
|
238
292
|
def add_element(key, value = nil, &block)
|
293
|
+
key = escape_key(key)
|
239
294
|
key_node = Niceogiri::XML::Node.new(key)
|
240
295
|
@xml.add_child(key_node)
|
241
296
|
if block
|
@@ -310,7 +365,7 @@ class XML
|
|
310
365
|
end
|
311
366
|
|
312
367
|
def has_properties?
|
313
|
-
|
368
|
+
!@content.properties.empty?
|
314
369
|
end
|
315
370
|
|
316
371
|
def guard?
|
@@ -350,9 +405,8 @@ class XML
|
|
350
405
|
# end
|
351
406
|
#end
|
352
407
|
|
353
|
-
alias_method :read_property, :[]
|
354
|
-
|
355
408
|
alias_method :write_property, :[]=
|
409
|
+
alias_method :read_property, :[]
|
356
410
|
|
357
411
|
private
|
358
412
|
|
@@ -360,6 +414,11 @@ class XML
|
|
360
414
|
@content = content
|
361
415
|
@content.mid = SecureRandom.uuid
|
362
416
|
@content.ts = Time.now.utc.to_i
|
417
|
+
if (src = content[:src])
|
418
|
+
@content.src = OmfCommon.comm.create_topic(src)
|
419
|
+
end
|
420
|
+
# keep track if we sent local certs on a topic. Should do this the first time
|
421
|
+
@certOnTopic = {}
|
363
422
|
end
|
364
423
|
|
365
424
|
def _set_core(key, value)
|
@@ -394,6 +453,16 @@ class XML
|
|
394
453
|
end
|
395
454
|
end
|
396
455
|
|
456
|
+
def escape_key(key)
|
457
|
+
key = key.to_s
|
458
|
+
if key =~ /\W+/
|
459
|
+
warn "Due to the limitation of XML messages, please only use word character (a-z A-Z 0-9 _) in your property names. Offending characters will be replaced with underscore(_)."
|
460
|
+
key = key.gsub(/\W+/, '_')
|
461
|
+
else
|
462
|
+
key
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
397
466
|
# Get string of a value object, escape if object is string
|
398
467
|
def string_value(value)
|
399
468
|
if value.kind_of? String
|
@@ -403,6 +472,10 @@ class XML
|
|
403
472
|
end
|
404
473
|
value
|
405
474
|
end
|
475
|
+
|
476
|
+
def self.fix_canonicalised_xml(str)
|
477
|
+
str.gsub(/\n +/, '').gsub(/ xmlns=\"\"/, '')
|
478
|
+
end
|
406
479
|
end
|
407
480
|
end
|
408
481
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
default namespace = "http://schema.mytestbed.net/omf/6.0/protocol"
|
2
2
|
|
3
|
-
start = (create | configure | request | release | inform)
|
3
|
+
start = (create | configure | request | release | inform | env)
|
4
4
|
|
5
5
|
common_elements = attribute mid { text }?
|
6
6
|
& element ts { text }
|
@@ -36,3 +36,7 @@ inform = element inform {
|
|
36
36
|
& element cid { text }?
|
37
37
|
& element itype { "CREATION.OK" | "CREATION.FAILED" | "STATUS" | "RELEASED" | "ERROR" | "WARN" }
|
38
38
|
}
|
39
|
+
|
40
|
+
env = element env {
|
41
|
+
create | configure | request | release | inform
|
42
|
+
}
|
@@ -7,6 +7,7 @@
|
|
7
7
|
<ref name="request"/>
|
8
8
|
<ref name="release"/>
|
9
9
|
<ref name="inform"/>
|
10
|
+
<ref name="env"/>
|
10
11
|
</choice>
|
11
12
|
</start>
|
12
13
|
<define name="common_elements">
|
@@ -125,4 +126,15 @@
|
|
125
126
|
</interleave>
|
126
127
|
</element>
|
127
128
|
</define>
|
129
|
+
<define name="env">
|
130
|
+
<element name="env">
|
131
|
+
<choice>
|
132
|
+
<ref name="create"/>
|
133
|
+
<ref name="configure"/>
|
134
|
+
<ref name="request"/>
|
135
|
+
<ref name="release"/>
|
136
|
+
<ref name="inform"/>
|
137
|
+
</choice>
|
138
|
+
</element>
|
139
|
+
</define>
|
128
140
|
</grammar>
|
data/lib/omf_common/version.rb
CHANGED
data/omf_common.gemspec
CHANGED
@@ -17,16 +17,21 @@ Gem::Specification.new do |s|
|
|
17
17
|
|
18
18
|
s.files = `git ls-files`.split("\n")
|
19
19
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
-
s.executables =
|
20
|
+
s.executables = ["omf_monitor_topic","omf_send_request", "omf_send_create"]
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
|
23
23
|
# specify any dependencies here; for example:
|
24
24
|
s.add_development_dependency "minitest", "~> 3.2"
|
25
25
|
s.add_development_dependency "em-minitest-spec", "~> 1.1.1"
|
26
26
|
s.add_development_dependency "simplecov"
|
27
|
+
s.add_development_dependency "pry"
|
28
|
+
s.add_development_dependency "mocha"
|
29
|
+
|
27
30
|
s.add_runtime_dependency "eventmachine", "~> 0.12.10"
|
28
31
|
s.add_runtime_dependency "blather", "= 0.8.1"
|
29
32
|
s.add_runtime_dependency "logging", "~> 1.7.1"
|
30
33
|
s.add_runtime_dependency "hashie", "~> 1.2.0"
|
31
|
-
s.add_runtime_dependency "oml4r", "~> 2.
|
34
|
+
s.add_runtime_dependency "oml4r", "~> 2.9.1"
|
35
|
+
#s.add_runtime_dependency "json-jwt", "~> 0.5.2"
|
36
|
+
#s.add_runtime_dependency "amqp", "~> 1.0.1"
|
32
37
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICWDCCAcGgAwIBAgIJAIZg2YXVVvPIMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
3
|
+
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
4
|
+
aWRnaXRzIFB0eSBMdGQwHhcNMTMwNDIzMDQyOTE5WhcNMjMwNDIxMDQyOTE5WjBF
|
5
|
+
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
6
|
+
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
7
|
+
gQC24IfY2Kat2C35gw+X1fM8NI7CJ5DvT19BoDjQviXy8RhBl4fCTNVBvYYzgZXC
|
8
|
+
zVcTi4nAgJFbxvHMBeORmSWih5s3E/zllPWVmRstxGqscqoshjSnnU32p6HBXHEB
|
9
|
+
0zuZsO/8Ff2+L0Q1QX9XhFntrJsyeiOk2fstz5AXovL6iQIDAQABo1AwTjAdBgNV
|
10
|
+
HQ4EFgQUeXgde/SzFMMdPj0Sv7nGKlE0LoEwHwYDVR0jBBgwFoAUeXgde/SzFMMd
|
11
|
+
Pj0Sv7nGKlE0LoEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAgLs56
|
12
|
+
W7MpT9gc+/QGPt1FEIHqGGGwS/FuxQJEJnrnI0MpCf+2dqAlOwTKQDh+QB8558YO
|
13
|
+
cdGqgrFKPJSVvIaqow9OStOqn+PpyhBgfrDMkKMCdmN3yW4JeytAM+z5pV44YtTw
|
14
|
+
GBlr4kQzF0y3V1oo1+Ck1F1n+CARt2knmi3zAQ==
|
15
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICXQIBAAKBgQC24IfY2Kat2C35gw+X1fM8NI7CJ5DvT19BoDjQviXy8RhBl4fC
|
3
|
+
TNVBvYYzgZXCzVcTi4nAgJFbxvHMBeORmSWih5s3E/zllPWVmRstxGqscqoshjSn
|
4
|
+
nU32p6HBXHEB0zuZsO/8Ff2+L0Q1QX9XhFntrJsyeiOk2fstz5AXovL6iQIDAQAB
|
5
|
+
AoGBALJb/mJBux6mTwChEJ43rskzQWCfEj40nWT2DTOZoI13Ev81+NRJ91vsqmyl
|
6
|
+
oBikCJ8pYqp7OknWmJEx1Sd1xDs/jsb6AUfNsfJALtE54Cq2iEWBU3Q4BTuT1meE
|
7
|
+
Fyvqww9YoFZIaYHvyDWYTH2B8eYrswSt4nCpKmr9eb/cBplhAkEA42Fl+aYUv2A6
|
8
|
+
7EGFe+1OT9ctLZeEGPBIWuWIma6vj4+iM6Zn1rmsoqx3qsrjsIVUxpmmH5RvrJOY
|
9
|
+
Vq0WvqDwxQJBAM3lJ3lzs5fLEjzk/obiU6PJFq6BCFUTVtbjaRe8uN450fBEm+0M
|
10
|
+
pOacio2jDhA21ayHE+yAfZ2h0V+WXSvHNvUCQDV2JBTjoMMybAg6i5kMvbn1/NBY
|
11
|
+
bJ20eT6t80U3Fl4pxlhgis+ozlddN7G3jHtnjfw4CiAotW0dMtdGUS+3BYUCQD3a
|
12
|
+
YYly4LjxIIF6qZwL0eSaPF4gFUi5jpTvrFqdL0xTQmZTtiP4cHF3BYiXO1pTns09
|
13
|
+
pxadYx8/xY5ZtZO5PSECQQCwGIGrXQnT6FVpuJFRIl1m0rglbXEHy1x8xRYaQNJX
|
14
|
+
7cUKcQaIXoroQ43TQnkIcIK7Q11EFomrJBTTL7icpgfU
|
15
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1 @@
|
|
1
|
+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC24IfY2Kat2C35gw+X1fM8NI7CJ5DvT19BoDjQviXy8RhBl4fCTNVBvYYzgZXCzVcTi4nAgJFbxvHMBeORmSWih5s3E/zllPWVmRstxGqscqoshjSnnU32p6HBXHEB0zuZsO/8Ff2+L0Q1QX9XhFntrJsyeiOk2fstz5AXovL6iQ==
|
@@ -0,0 +1,6 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC24IfY2Kat2C35gw+X1fM8NI7C
|
3
|
+
J5DvT19BoDjQviXy8RhBl4fCTNVBvYYzgZXCzVcTi4nAgJFbxvHMBeORmSWih5s3
|
4
|
+
E/zllPWVmRstxGqscqoshjSnnU32p6HBXHEB0zuZsO/8Ff2+L0Q1QX9XhFntrJsy
|
5
|
+
eiOk2fstz5AXovL6iQIDAQAB
|
6
|
+
-----END PUBLIC KEY-----
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe OmfCommon::Auth::Certificate do
|
4
|
+
before do
|
5
|
+
OmfCommon::Auth::CertificateStore.init
|
6
|
+
|
7
|
+
@root = OmfCommon::Auth::Certificate.create(nil, 'omf_ca', 'ca', 'omf')
|
8
|
+
|
9
|
+
OmfCommon::Auth::CertificateStore.instance.register(@root)
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
OmfCommon::Auth::CertificateStore.reset
|
14
|
+
end
|
15
|
+
|
16
|
+
it "must create a self-signed root CA cert" do
|
17
|
+
@root.must_be_kind_of OmfCommon::Auth::Certificate
|
18
|
+
@root.address.must_be_nil
|
19
|
+
@root.subject.must_be_kind_of OpenSSL::X509::Name
|
20
|
+
@root.subject.to_s(OpenSSL::X509::Name::RFC2253).must_equal "CN=frcp//omf//frcp.ca.omf_ca"
|
21
|
+
@root.key.must_be_kind_of OpenSSL::PKey::RSA
|
22
|
+
@root.digest.must_be_kind_of OpenSSL::Digest::SHA1
|
23
|
+
|
24
|
+
cert = @root.to_x509
|
25
|
+
cert.must_be_kind_of OpenSSL::X509::Certificate
|
26
|
+
|
27
|
+
# It is self signed
|
28
|
+
cert.issuer.must_equal @root.subject
|
29
|
+
cert.verify(cert.public_key).must_equal true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "must create an end-entity cert using root cert" do
|
33
|
+
lambda { @root.create_for }.must_raise ArgumentError
|
34
|
+
|
35
|
+
@entity = @root.create_for('my_addr', 'bob', 'my_resource', 'omf')
|
36
|
+
cert = @entity.to_x509
|
37
|
+
|
38
|
+
cert.issuer.must_equal @root.subject
|
39
|
+
cert.issuer.wont_equal cert.subject
|
40
|
+
|
41
|
+
cert.issuer.to_s(OpenSSL::X509::Name::RFC2253).must_equal "CN=frcp//omf//frcp.ca.omf_ca"
|
42
|
+
cert.subject.to_s(OpenSSL::X509::Name::RFC2253).must_equal "CN=frcp//omf//frcp.my_resource.bob"
|
43
|
+
|
44
|
+
cert.verify(@root.to_x509.public_key).must_equal true
|
45
|
+
|
46
|
+
@entity.verify_cert.must_equal true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must verify cert validity" do
|
50
|
+
@root.verify_cert.must_equal true
|
51
|
+
@root.create_for('my_addr', 'bob', 'my_resource', 'omf').verify_cert.must_equal true
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "when init from an exisitng cert in pem format" do
|
55
|
+
before do
|
56
|
+
@private_folder = "#{File.dirname(__FILE__)}/../../fixture"
|
57
|
+
@cert = OmfCommon::Auth::Certificate.create_from_x509(File.read("#{@private_folder}/omf_test.cert.pem"))
|
58
|
+
@key = OpenSSL::PKey::RSA.new(File.read("#{@private_folder}/omf_test.pem"))
|
59
|
+
@pub_key = OpenSSL::PKey::RSA.new(File.read("#{@private_folder}/omf_test.pub.pem"))
|
60
|
+
end
|
61
|
+
|
62
|
+
it "must verify itself" do
|
63
|
+
# It is a self signed cert
|
64
|
+
@cert.subject.to_s(OpenSSL::X509::Name::RFC2253).must_equal "O=Internet Widgits Pty Ltd,ST=Some-State,C=AU"
|
65
|
+
@cert.to_x509.issuer.to_s(OpenSSL::X509::Name::RFC2253).must_equal "O=Internet Widgits Pty Ltd,ST=Some-State,C=AU"
|
66
|
+
@cert.verify_cert.must_equal true
|
67
|
+
end
|
68
|
+
|
69
|
+
it "must not have pirivate key initialised" do
|
70
|
+
@cert.can_sign?.must_equal false
|
71
|
+
end
|
72
|
+
|
73
|
+
it "must have a correct public key" do
|
74
|
+
@pub_key.public?.must_equal true
|
75
|
+
@pub_key.private?.must_equal false
|
76
|
+
@cert.to_x509.public_key.to_s.must_equal @pub_key.to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
it "must have a correct private key associated" do
|
80
|
+
@key.public?.must_equal true
|
81
|
+
@key.private?.must_equal true
|
82
|
+
@cert.to_x509.check_private_key(@key).must_equal true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "when provided an existing public key" do
|
87
|
+
it "must generate a cert contains a converted public key" do
|
88
|
+
private_folder = "#{File.dirname(__FILE__)}/../../fixture"
|
89
|
+
pub_key = OpenSSL::PKey::RSA.new(File.read("#{private_folder}/omf_test.pub.pem"))
|
90
|
+
|
91
|
+
test_entity = @root.create_for('my_addr', 'bob', 'my_resource', 'omf', 365, pub_key)
|
92
|
+
test_entity.to_x509.public_key.to_s.must_equal pub_key.to_s
|
93
|
+
test_entity.can_sign?.must_equal false
|
94
|
+
test_entity.verify_cert.must_equal true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "when provided an existing public cert and I have a private key associated" do
|
99
|
+
it "must attach the private key into instance so it could sign messages" do
|
100
|
+
private_folder = "#{File.dirname(__FILE__)}/../../fixture"
|
101
|
+
key = OpenSSL::PKey::RSA.new(File.read("#{private_folder}/omf_test.pem"))
|
102
|
+
pub_key = OpenSSL::PKey::RSA.new(File.read("#{private_folder}/omf_test.pub.pem"))
|
103
|
+
|
104
|
+
x509_cert = @root.create_for('my_addr', 'bob', 'my_resource', 'omf', 365, pub_key).to_x509.to_s
|
105
|
+
|
106
|
+
# Now create an instance using this cert
|
107
|
+
test_entity = OmfCommon::Auth::Certificate.create_from_x509(x509_cert, key)
|
108
|
+
test_entity.to_x509.public_key.to_s.must_equal pub_key.to_s
|
109
|
+
test_entity.can_sign?.must_equal true
|
110
|
+
test_entity.to_x509.check_private_key(key).must_equal true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|