omf_common 6.0.0 → 6.0.2.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|