sepafm 0.0.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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +8 -0
  6. data/README.md +236 -0
  7. data/Rakefile +10 -0
  8. data/lib/danske_get_bank_certificate_test.rb +15 -0
  9. data/lib/sepa/application_request.rb +182 -0
  10. data/lib/sepa/application_response.rb +123 -0
  11. data/lib/sepa/client.rb +79 -0
  12. data/lib/sepa/danske_testing/keys/danske_encryption.crt +24 -0
  13. data/lib/sepa/filedescriptor.rb +7 -0
  14. data/lib/sepa/filetypeservice.rb +6 -0
  15. data/lib/sepa/nordea_testing/keys/CSR.csr +0 -0
  16. data/lib/sepa/nordea_testing/keys/nordea.crt +27 -0
  17. data/lib/sepa/nordea_testing/keys/nordea.key +19 -0
  18. data/lib/sepa/nordea_testing/response/content_053.xml +998 -0
  19. data/lib/sepa/nordea_testing/response/content_054.xml +1 -0
  20. data/lib/sepa/nordea_testing/response/download_file_response.xml +14 -0
  21. data/lib/sepa/nordea_testing/response/download_filelist_response.xml +14 -0
  22. data/lib/sepa/nordea_testing/response/get_user_info_response.xml +14 -0
  23. data/lib/sepa/nordea_testing/response/upload_file_response.xml +14 -0
  24. data/lib/sepa/response.rb +177 -0
  25. data/lib/sepa/sender_verifier.rb +15 -0
  26. data/lib/sepa/signature.rb +7 -0
  27. data/lib/sepa/soap_builder.rb +395 -0
  28. data/lib/sepa/soap_danske.rb +47 -0
  29. data/lib/sepa/soap_nordea.rb +68 -0
  30. data/lib/sepa/userfiletype.rb +16 -0
  31. data/lib/sepa/version.rb +3 -0
  32. data/lib/sepa/wsdl/wsdl_danske.xml +234 -0
  33. data/lib/sepa/wsdl/wsdl_danske_cert.xml +280 -0
  34. data/lib/sepa/wsdl/wsdl_nordea.xml +234 -0
  35. data/lib/sepa/wsdl/wsdl_nordea_cert.xml +187 -0
  36. data/lib/sepa/xml_parser.rb +291 -0
  37. data/lib/sepa/xml_schemas/application_request.xsd +135 -0
  38. data/lib/sepa/xml_schemas/application_response.xsd +311 -0
  39. data/lib/sepa/xml_schemas/cert_application_request.xsd +107 -0
  40. data/lib/sepa/xml_schemas/danske_pki.xsd +334 -0
  41. data/lib/sepa/xml_schemas/oasis-200401-wss-wssecurity-secext-1.0.xsd +195 -0
  42. data/lib/sepa/xml_schemas/oasis-200401-wss-wssecurity-utility-1.0.xsd +108 -0
  43. data/lib/sepa/xml_schemas/soap.xsd +126 -0
  44. data/lib/sepa/xml_schemas/wsdl.xml +310 -0
  45. data/lib/sepa/xml_schemas/xml.xsd +287 -0
  46. data/lib/sepa/xml_schemas/xmldsig-core-schema.xsd +318 -0
  47. data/lib/sepa/xml_templates/application_request/create_certificate.xml +10 -0
  48. data/lib/sepa/xml_templates/application_request/danske_get_bank_certificate.xml +10 -0
  49. data/lib/sepa/xml_templates/application_request/download_file.xml +32 -0
  50. data/lib/sepa/xml_templates/application_request/download_file_list.xml +29 -0
  51. data/lib/sepa/xml_templates/application_request/get_certificate.xml +10 -0
  52. data/lib/sepa/xml_templates/application_request/get_user_info.xml +26 -0
  53. data/lib/sepa/xml_templates/application_request/upload_file.xml +29 -0
  54. data/lib/sepa/xml_templates/soap/create_certificate.xml +15 -0
  55. data/lib/sepa/xml_templates/soap/danske_get_bank_certificate.xml +14 -0
  56. data/lib/sepa/xml_templates/soap/download_file.xml +16 -0
  57. data/lib/sepa/xml_templates/soap/download_file_list.xml +16 -0
  58. data/lib/sepa/xml_templates/soap/get_certificate.xml +13 -0
  59. data/lib/sepa/xml_templates/soap/get_user_info.xml +16 -0
  60. data/lib/sepa/xml_templates/soap/header.xml +37 -0
  61. data/lib/sepa/xml_templates/soap/upload_file.xml +16 -0
  62. data/lib/sepa.rb +21 -0
  63. data/lib/sepa_client_testing_mika.rb +32 -0
  64. data/lib/sepa_client_testing_tiere.rb +80 -0
  65. data/sepa.gemspec +29 -0
  66. data/test/sepa/application_request_test.rb +423 -0
  67. data/test/sepa/application_response_test.rb +238 -0
  68. data/test/sepa/cert_application_request_test.rb +99 -0
  69. data/test/sepa/client_test.rb +425 -0
  70. data/test/sepa/danske_test_keys/danskeroot.pem +25 -0
  71. data/test/sepa/danske_test_keys/encryption_pkcs.csr +0 -0
  72. data/test/sepa/danske_test_keys/signing_key.pem +27 -0
  73. data/test/sepa/danske_test_keys/signing_pkcs.csr +0 -0
  74. data/test/sepa/nordea_cert_request_soap_builder_test.rb +112 -0
  75. data/test/sepa/nordea_generic_soap_builder_test.rb +427 -0
  76. data/test/sepa/nordea_test_keys/nordea.crt +27 -0
  77. data/test/sepa/nordea_test_keys/nordea.key +19 -0
  78. data/test/sepa/nordea_test_keys/root_cert.cer +0 -0
  79. data/test/sepa/nordea_test_keys/testcert.csr +0 -0
  80. data/test/sepa/response_test.rb +269 -0
  81. data/test/sepa/sepa_test.rb +20 -0
  82. data/test/sepa/test_files/invalid.wsdl +1 -0
  83. data/test/sepa/test_files/test_responses/df.xml +20 -0
  84. data/test/sepa/test_files/test_responses/dfl.xml +20 -0
  85. data/test/sepa/test_files/test_responses/gui.xml +20 -0
  86. data/test/sepa/test_files/test_responses/uf.xml +20 -0
  87. data/test/sepa/user_file_type_test.rb +21 -0
  88. data/test/sepa/xml_parser_test.rb +73 -0
  89. data/test/test_helper.rb +9 -0
  90. metadata +256 -0
@@ -0,0 +1,427 @@
1
+ require File.expand_path('../../test_helper.rb', __FILE__)
2
+
3
+ class NordeaGenericSoapBuilderTest < MiniTest::Test
4
+ def setup
5
+ @schemas_path = File.expand_path('../../../lib/sepa/xml_schemas',__FILE__)
6
+
7
+ @xml_templates_path = File.expand_path(
8
+ '../../../lib/sepa/xml_templates/soap',
9
+ __FILE__
10
+ )
11
+
12
+ keys_path = File.expand_path('../nordea_test_keys', __FILE__)
13
+
14
+ private_key = OpenSSL::PKey::RSA.new File.read "#{keys_path}/nordea.key"
15
+ cert = OpenSSL::X509::Certificate.new File.read "#{keys_path}/nordea.crt"
16
+ certplain = "-----BEGIN CERTIFICATE-----
17
+ MIIDwTCCAqmgAwIBAgIEAX1JuTANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT
18
+ RTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMR8wHQYDVQQDExZOb3Jk
19
+ ZWEgQ29ycG9yYXRlIENBIDAxMRQwEgYDVQQFEws1MTY0MDYtMDEyMDAeFw0xMzA1
20
+ MDIxMjI2MzRaFw0xNTA1MDIxMjI2MzRaMEQxCzAJBgNVBAYTAkZJMSAwHgYDVQQD
21
+ DBdOb3JkZWEgRGVtbyBDZXJ0aWZpY2F0ZTETMBEGA1UEBRMKNTc4MDg2MDIzODCB
22
+ nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwtFEfAtbJuGzQwwRumZkvYh2BjGY
23
+ VsAMUeiKtOne3bZSeisfCq+TXqL1gI9LofyeAQ9I/sDm6tL80yrD5iaSUqVm6A73
24
+ 9MsmpW/iyZcVf7ms8xAN51ESUgN6akwZCU9pH62ngJDj2gUsktY0fpsoVsARdrvO
25
+ Fk0fTSUXKWd6LbcCAwEAAaOCAR0wggEZMAkGA1UdEwQCMAAwEQYDVR0OBAoECEBw
26
+ 2cj7+XMAMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEALddbbzwun
27
+ MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVh
28
+ LnNlL0NDQTAxMA4GA1UdDwEB/wQEAwIFoDCBhQYDVR0fBH4wfDB6oHigdoZ0bGRh
29
+ cCUzQS8vbGRhcC5uYi5zZS9jbiUzRE5vcmRlYStDb3Jwb3JhdGUrQ0ErMDElMkNv
30
+ JTNETm9yZGVhK0JhbmsrQUIrJTI4cHVibCUyOSUyQ2MlM0RTRSUzRmNlcnRpZmlj
31
+ YXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBACLUPB1Gmq6286/s
32
+ ROADo7N+w3eViGJ2fuOTLMy4R0UHOznKZNsuk4zAbS2KycbZsE5py4L8o+IYoaS8
33
+ 8YHtEeckr2oqHnPpz/0Eg7wItj8Ad+AFWJqzbn6Hu/LQhlnl5JEzXzl3eZj9oiiJ
34
+ 1q/2CGXvFomY7S4tgpWRmYULtCK6jode0NhgNnAgOI9uy76pSS16aDoiQWUJqQgV
35
+ ydowAnqS9h9aQ6gedwbOdtkWmwKMDVXU6aRz9Gvk+JeYJhtpuP3OPNGbbC5L7NVd
36
+ no+B6AtwxmG3ozd+mPcMeVuz6kKLAmQyIiBSrRNa5OrTkq/CUzxO9WUgTnm/Sri7
37
+ zReR6mU=
38
+ -----END CERTIFICATE-----"
39
+ pkeyplain = "-----BEGIN PRIVATE KEY-----
40
+ MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMLRRHwLWybhs0MM
41
+ EbpmZL2IdgYxmFbADFHoirTp3t22UnorHwqvk16i9YCPS6H8ngEPSP7A5urS/NMq
42
+ w+YmklKlZugO9/TLJqVv4smXFX+5rPMQDedRElIDempMGQlPaR+tp4CQ49oFLJLW
43
+ NH6bKFbAEXa7zhZNH00lFylnei23AgMBAAECgYEAqt912/7x4jaQTrxlSELLFVp9
44
+ eo1BesVTiPwXvPpsGbbyvGjZ/ztkXNs9zZbh1aCGzZMkiR2U7F5GlsiprlIif4cF
45
+ 6Xz7rCjaAs7iDRt9PjhjVuqNGR2I+VIIlbQ9XWFJ3lJFW3v7TIZ8JbLnn0XOFz+Z
46
+ BBSSGTK1zTNh4TBQtjECQQDe5M3uu9m4RwSw9R6GaDw/IFQZgr0oWSv0WIjRwvwW
47
+ nFnSX2lbkNAjulP0daGsmn7vxIpqZxPxwcrU4wFqTF5dAkEA38DnbCm3YfogzwLH
48
+ Nre2hBmGqjWarhtxqtRarrkgnmOd8W0Z1Hb1dSHrliUSVSrINbK5ZdEV15Rpu7VD
49
+ OePzIwJAPMslS+8alANyyR0iJUC65fDYX1jkZOPldDDNqIDJJxWf/hwd7WaTDpuc
50
+ mHmZDi3ZX2Y45oqUywSzYNtFoIuR1QJAZYUZuyqmSK77SdGB36K1DfSi9AFEQDC1
51
+ fwPAbTwTv6mFFPAiYxLiRZXxVPtW+QtjMXH4ymh2V4y/+GnCqbZyLwJBAJQSDAME
52
+ Sn4Uz7Zjk3UrBIbMYEv0u2mcCypwsb0nGE5/gzDPjGE9cxWW+rXARIs+sNQVClnh
53
+ 45nhdfYxOjgYff0=
54
+ -----END PRIVATE KEY-----"
55
+ @params = {
56
+ bank: :nordea,
57
+ private_key_plain: pkeyplain,
58
+ cert_plain: certplain,
59
+ command: :get_user_info,
60
+ customer_id: '11111111',
61
+ environment: 'PRODUCTION',
62
+ status: 'NEW',
63
+ target_id: '11111111A1',
64
+ language: 'FI',
65
+ file_type: 'TITO',
66
+ content: Base64.encode64("Kurppa"),
67
+ file_reference: "11111111A12006030329501800000014"
68
+ }
69
+
70
+ @soap_request = Sepa::SoapBuilder.new(@params)
71
+
72
+ @doc = Nokogiri::XML(@soap_request.to_xml)
73
+ end
74
+
75
+ def test_get_user_info_template_is_unmodified
76
+ sha1 = OpenSSL::Digest::SHA1.new
77
+ template = File.read("#{@xml_templates_path}/get_user_info.xml")
78
+ digest = Base64.encode64(sha1.digest(template)).strip
79
+
80
+ assert_equal digest, "A1UYZTOycIBHAY/70Q5G3lNjQBo="
81
+ end
82
+
83
+ def test_download_file_list_template_is_unmodified
84
+ sha1 = OpenSSL::Digest::SHA1.new
85
+ template = File.read("#{@xml_templates_path}/download_file_list.xml")
86
+ digest = Base64.encode64(sha1.digest(template)).strip
87
+
88
+ assert_equal digest, "+3UaQMgseUUn5OKUp/PTHl/BNFE="
89
+ end
90
+
91
+ def test_download_file_template_is_unmodified
92
+ sha1 = OpenSSL::Digest::SHA1.new
93
+ template = File.read("#{@xml_templates_path}/download_file.xml")
94
+ digest = Base64.encode64(sha1.digest(template)).strip
95
+
96
+ assert_equal digest, "HSWQCmwOsMdPJP3erjksi/Sz7hE="
97
+ end
98
+
99
+ def test_should_not_initialize_with_unproper_params
100
+ @params = "kissa"
101
+ assert_raises(ArgumentError) do
102
+ Sepa::SoapBuilder.new(@params)
103
+ end
104
+ end
105
+ def test_upload_file_template_is_unmodified
106
+ sha1 = OpenSSL::Digest::SHA1.new
107
+ template = File.read("#{@xml_templates_path}/upload_file.xml")
108
+ digest = Base64.encode64(sha1.digest(template)).strip
109
+
110
+ assert_equal digest, "hdbglkugI1pzkeetqKIh2WBDkFM="
111
+ end
112
+
113
+ def test_header_template_is_unmodified
114
+ sha1 = OpenSSL::Digest::SHA1.new
115
+ template = File.read("#{@xml_templates_path}/header.xml")
116
+ digest = Base64.encode64(sha1.digest(template)).strip
117
+
118
+ assert_equal digest, "W6TTO6gmlVDssKeZJYsxiJebs6Q="
119
+ end
120
+
121
+ def test_should_initialize_with_proper_params
122
+ assert Sepa::SoapBuilder.new(@params)
123
+ end
124
+
125
+ def test_should_get_error_if_private_key_plain_missing
126
+ @params.delete(:private_key_plain)
127
+
128
+ assert_raises(ArgumentError) do
129
+ Sepa::SoapBuilder.new(@params)
130
+ end
131
+ end
132
+
133
+ def test_should_get_error_if_cert_plain_missing
134
+ @params.delete(:cert_plain)
135
+
136
+ assert_raises(ArgumentError) do
137
+ Sepa::SoapBuilder.new(@params)
138
+ end
139
+ end
140
+
141
+ def test_should_get_error_if_command_missing
142
+ @params.delete(:command)
143
+
144
+ assert_raises(ArgumentError) do
145
+ Sepa::SoapBuilder.new(@params)
146
+ end
147
+ end
148
+
149
+ def test_should_get_error_if_customer_id_missing
150
+ @params.delete(:customer_id)
151
+
152
+ assert_raises(ArgumentError) do
153
+ Sepa::SoapBuilder.new(@params)
154
+ end
155
+ end
156
+
157
+ def test_should_get_error_if_target_id_missing
158
+ @params.delete(:target_id)
159
+
160
+ assert_raises(ArgumentError) do
161
+ Sepa::SoapBuilder.new(@params)
162
+ end
163
+ end
164
+
165
+ def test_should_get_error_if_language_missing
166
+ @params.delete(:language)
167
+
168
+ assert_raises(ArgumentError) do
169
+ Sepa::SoapBuilder.new(@params)
170
+ end
171
+ end
172
+
173
+ def test_should_load_correct_template_with_download_file_list
174
+ @params[:command] = :download_file_list
175
+ doc = Nokogiri::XML(Sepa::SoapBuilder.new(@params).to_xml)
176
+
177
+ assert doc.xpath(
178
+ '//cor:downloadFileListin', 'cor' => 'http://bxd.fi/CorporateFileService'
179
+ ).first
180
+ end
181
+
182
+ def test_should_load_correct_template_with_get_user_info
183
+ @params[:command] = :get_user_info
184
+ doc = Nokogiri::XML(Sepa::SoapBuilder.new(@params).to_xml)
185
+
186
+ assert doc.xpath(
187
+ '//cor:getUserInfoin', 'cor' => 'http://bxd.fi/CorporateFileService'
188
+ ).first
189
+ end
190
+
191
+ def test_should_load_correct_template_with_download_file
192
+ @params[:command] = :download_file
193
+ doc = Nokogiri::XML(Sepa::SoapBuilder.new(@params).to_xml)
194
+
195
+ assert doc.xpath(
196
+ '//cor:downloadFilein', 'cor' => 'http://bxd.fi/CorporateFileService'
197
+ ).first
198
+ end
199
+
200
+ def test_should_load_correct_template_with_upload_file
201
+ @params[:command] = :upload_file
202
+ doc = Nokogiri::XML(Sepa::SoapBuilder.new(@params).to_xml)
203
+
204
+ assert doc.xpath(
205
+ '//cor:uploadFilein', 'cor' => 'http://bxd.fi/CorporateFileService'
206
+ ).first
207
+ end
208
+
209
+ def test_should_raise_error_if_unrecognised_command
210
+ @params[:command] = :wrong_command
211
+
212
+ assert_raises(ArgumentError) do
213
+ soap = Sepa::SoapBuilder.new(@params)
214
+ end
215
+ end
216
+
217
+ def test_sender_id_is_properly_set
218
+ assert_equal @params[:customer_id],
219
+ @doc.xpath("//bxd:SenderId", 'bxd' => 'http://model.bxd.fi').first.content
220
+ end
221
+
222
+ # Just testing that the content of the node is an actual hex number and that
223
+ # the length is 30 characters because 35 is the max that can be set
224
+ # according to the schema and Securerandom can generate only some int times 2
225
+ def test_request_id_is_properly_set
226
+ request_id_node = @doc.xpath(
227
+ "//bxd:RequestId", 'bxd' => 'http://model.bxd.fi'
228
+ ).first
229
+
230
+ assert request_id_node.content =~ /^[0-9A-F]+$/i
231
+ assert_equal request_id_node.content.length, 34
232
+ end
233
+
234
+ def test_timestamp_is_set_correctly
235
+ timestamp_node = @doc.xpath(
236
+ "//bxd:Timestamp", 'bxd' => 'http://model.bxd.fi'
237
+ ).first
238
+
239
+ timestamp = Time.strptime(timestamp_node.content, '%Y-%m-%dT%H:%M:%S%z')
240
+
241
+ assert timestamp <= Time.now && timestamp > (Time.now - 60)
242
+ end
243
+
244
+ def test_language_is_set_correctly
245
+ language_node = @doc.xpath(
246
+ "//bxd:Language", 'bxd' => 'http://model.bxd.fi'
247
+ ).first
248
+
249
+ assert_equal language_node.content, @params[:language]
250
+ end
251
+
252
+ def test_user_agent_is_set_correctly
253
+ user_agent_node = @doc.xpath(
254
+ "//bxd:UserAgent", 'bxd' => 'http://model.bxd.fi'
255
+ ).first
256
+
257
+ assert_equal user_agent_node.content,
258
+ "Sepa Transfer Library version " + Sepa::VERSION
259
+ end
260
+
261
+ # I'm quite sure that receiver id and target is are the same
262
+ def test_receiver_is_is_set_correctly
263
+ receiver_id_node = @doc.xpath(
264
+ "//bxd:ReceiverId", 'bxd' => 'http://model.bxd.fi'
265
+ ).first
266
+
267
+ assert_equal receiver_id_node.content, @params[:target_id]
268
+ end
269
+
270
+ # Just test that the content of application request is a base64 encoded xml
271
+ # document and that it's customer is matches the one provided in the params
272
+ def test_application_request_should_be_inserted_properly
273
+ ar_node = @doc.xpath(
274
+ "//bxd:ApplicationRequest", 'bxd' => 'http://model.bxd.fi'
275
+ ).first
276
+
277
+ ar_doc = Nokogiri::XML(Base64.decode64(ar_node.content))
278
+
279
+ assert ar_doc.respond_to?(:canonicalize)
280
+ assert_equal ar_doc.at_css("CustomerId").content, @params[:customer_id]
281
+ end
282
+
283
+ def test_cert_is_added_correctly
284
+ added_cert = @doc.xpath(
285
+ "//wsse:BinarySecurityToken", 'wsse' => 'http://docs.oasis-open.org/wss' \
286
+ '/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
287
+ ).first.content
288
+
289
+ actual_cert = @params.fetch(:cert).to_s
290
+ actual_cert = actual_cert.split('-----BEGIN CERTIFICATE-----')[1]
291
+ actual_cert = actual_cert.split('-----END CERTIFICATE-----')[0]
292
+ actual_cert = actual_cert.gsub(/\s+/, "")
293
+
294
+ assert_equal added_cert, actual_cert
295
+ end
296
+
297
+ def test_body_digest_is_calculated_correctly
298
+ sha1 = OpenSSL::Digest::SHA1.new
299
+
300
+ # Digest which is calculated from the body and added to the header
301
+ added_digest = @doc.xpath(
302
+ "//dsig:Reference[@URI='#sdf6sa7d86f87s6df786sd87f6s8fsda']/dsig:Digest" \
303
+ "Value", 'dsig' => 'http://www.w3.org/2000/09/xmldsig#'
304
+ ).first.content
305
+
306
+ body_node = @doc.xpath(
307
+ "//env:Body", 'env' => 'http://schemas.xmlsoap.org/soap/envelope/'
308
+ ).first
309
+
310
+ body_node = body_node.canonicalize(
311
+ mode=Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0,inclusive_namespaces=nil,
312
+ with_comments=false
313
+ )
314
+
315
+ actual_digest = Base64.encode64(sha1.digest(body_node)).strip
316
+
317
+ assert_equal actual_digest, added_digest
318
+ end
319
+
320
+ def test_header_created_timestamp_is_added_correctly
321
+ timestamp_node = @doc.xpath(
322
+ "//wsu:Created", 'wsu' => 'http://docs.oasis-open.org/wss/2004/01/oasis' \
323
+ '-200401-wss-wssecurity-utility-1.0.xsd'
324
+ ).first
325
+
326
+ timestamp = Time.strptime(timestamp_node.content, '%Y-%m-%dT%H:%M:%S%z')
327
+
328
+ assert timestamp <= Time.now && timestamp > (Time.now - 60)
329
+ end
330
+
331
+ def test_header_expires_timestamp_is_added_correctly
332
+ timestamp_node = @doc.xpath(
333
+ "//wsu:Expires", 'wsu' => 'http://docs.oasis-open.org/wss/2004/01/oasis' \
334
+ '-200401-wss-wssecurity-utility-1.0.xsd'
335
+ ).first
336
+
337
+ timestamp = Time.strptime(timestamp_node.content, '%Y-%m-%dT%H:%M:%S%z')
338
+
339
+ assert timestamp <= (Time.now + 3600) &&
340
+ timestamp > ((Time.now + 3600) - 60)
341
+ end
342
+
343
+ def test_header_timestamps_digest_is_calculated_correctly
344
+ sha1 = OpenSSL::Digest::SHA1.new
345
+
346
+ added_digest = @doc.xpath(
347
+ "//dsig:Reference[@URI='#dsfg8sdg87dsf678g6dsg6ds7fg']/dsig:DigestValue",
348
+ 'dsig' => 'http://www.w3.org/2000/09/xmldsig#'
349
+ ).first.content
350
+
351
+ timestamp_node = @doc.xpath(
352
+ "//wsu:Timestamp", 'wsu' => 'http://docs.oasis-open.org/wss/2004/01/oas' \
353
+ 'is-200401-wss-wssecurity-utility-1.0.xsd'
354
+ ).first
355
+
356
+ timestamp_node = timestamp_node.canonicalize(
357
+ mode=Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0,inclusive_namespaces=nil,
358
+ with_comments=false
359
+ )
360
+
361
+ actual_digest = Base64.encode64(sha1.digest(timestamp_node)).strip
362
+
363
+ assert_equal actual_digest, added_digest
364
+ end
365
+
366
+ def test_signature_is_calculated_correctly
367
+ sha1 = OpenSSL::Digest::SHA1.new
368
+ private_key = @params.fetch(:private_key)
369
+
370
+ added_signature = @doc.xpath(
371
+ "//dsig:SignatureValue", 'dsig' => 'http://www.w3.org/2000/09/xmldsig#'
372
+ ).first.content
373
+
374
+ signed_info_node = @doc.xpath(
375
+ "//dsig:SignedInfo", 'dsig' => 'http://www.w3.org/2000/09/xmldsig#'
376
+ ).first
377
+
378
+ signed_info_node = signed_info_node.canonicalize(
379
+ mode=Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0,inclusive_namespaces=nil,
380
+ with_comments=false
381
+ )
382
+
383
+ actual_signature = Base64.encode64(
384
+ private_key.sign(sha1, signed_info_node)
385
+ ).gsub(/\s+/, "")
386
+
387
+ assert_equal actual_signature, added_signature
388
+ end
389
+
390
+ def test_should_validate_against_schema
391
+ Dir.chdir(@schemas_path) do
392
+ xsd = Nokogiri::XML::Schema(IO.read('soap.xsd'))
393
+ assert xsd.valid?(@doc)
394
+ end
395
+ end
396
+
397
+ def test_schema_validation_should_fail_with_wrong_must_understand_value
398
+ security_node = @doc.xpath(
399
+ '//wsse:Security', 'wsse' => 'http://docs.oasis-open.org/wss/2004/01/oa' \
400
+ 'sis-200401-wss-wssecurity-secext-1.0.xsd'
401
+ ).first
402
+
403
+ security_node['env:mustUnderstand'] = '3'
404
+
405
+ Dir.chdir(@schemas_path) do
406
+ xsd = Nokogiri::XML::Schema(IO.read('soap.xsd'))
407
+ refute xsd.valid?(@doc)
408
+ end
409
+ end
410
+
411
+ def test_should_validate_against_ws_security_schema
412
+ ws_node = @doc.xpath(
413
+ '//wsse:Security', 'wsse' => 'http://docs.oasis-open.org/wss/2004/01/oa' \
414
+ 'sis-200401-wss-wssecurity-secext-1.0.xsd'
415
+ )
416
+
417
+ ws_node = ws_node.to_xml
418
+
419
+ ws_node = Nokogiri::XML(ws_node)
420
+
421
+ Dir.chdir(@schemas_path) do
422
+ xsd = Nokogiri::XML::Schema IO.read 'oasis-200401-wss-wssecurity-secext' \
423
+ '-1.0.xsd'
424
+ assert xsd.valid?(ws_node)
425
+ end
426
+ end
427
+ end
@@ -0,0 +1,27 @@
1
+ Bag Attributes
2
+ localKeyID: 4B 45 59 35 31 38 32 35 62 36 35 30 30 30 30 31 32 35 32 00
3
+ subject=/C=FI/CN=Nordea Demo Certificate/serialNumber=5780860238
4
+ issuer=/C=SE/O=Nordea Bank AB (publ)/CN=Nordea Corporate CA 01/serialNumber=516406-0120
5
+ -----BEGIN CERTIFICATE-----
6
+ MIIDwTCCAqmgAwIBAgIEAX1JuTANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT
7
+ RTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMR8wHQYDVQQDExZOb3Jk
8
+ ZWEgQ29ycG9yYXRlIENBIDAxMRQwEgYDVQQFEws1MTY0MDYtMDEyMDAeFw0xMzA1
9
+ MDIxMjI2MzRaFw0xNTA1MDIxMjI2MzRaMEQxCzAJBgNVBAYTAkZJMSAwHgYDVQQD
10
+ DBdOb3JkZWEgRGVtbyBDZXJ0aWZpY2F0ZTETMBEGA1UEBRMKNTc4MDg2MDIzODCB
11
+ nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwtFEfAtbJuGzQwwRumZkvYh2BjGY
12
+ VsAMUeiKtOne3bZSeisfCq+TXqL1gI9LofyeAQ9I/sDm6tL80yrD5iaSUqVm6A73
13
+ 9MsmpW/iyZcVf7ms8xAN51ESUgN6akwZCU9pH62ngJDj2gUsktY0fpsoVsARdrvO
14
+ Fk0fTSUXKWd6LbcCAwEAAaOCAR0wggEZMAkGA1UdEwQCMAAwEQYDVR0OBAoECEBw
15
+ 2cj7+XMAMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEALddbbzwun
16
+ MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVh
17
+ LnNlL0NDQTAxMA4GA1UdDwEB/wQEAwIFoDCBhQYDVR0fBH4wfDB6oHigdoZ0bGRh
18
+ cCUzQS8vbGRhcC5uYi5zZS9jbiUzRE5vcmRlYStDb3Jwb3JhdGUrQ0ErMDElMkNv
19
+ JTNETm9yZGVhK0JhbmsrQUIrJTI4cHVibCUyOSUyQ2MlM0RTRSUzRmNlcnRpZmlj
20
+ YXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBACLUPB1Gmq6286/s
21
+ ROADo7N+w3eViGJ2fuOTLMy4R0UHOznKZNsuk4zAbS2KycbZsE5py4L8o+IYoaS8
22
+ 8YHtEeckr2oqHnPpz/0Eg7wItj8Ad+AFWJqzbn6Hu/LQhlnl5JEzXzl3eZj9oiiJ
23
+ 1q/2CGXvFomY7S4tgpWRmYULtCK6jode0NhgNnAgOI9uy76pSS16aDoiQWUJqQgV
24
+ ydowAnqS9h9aQ6gedwbOdtkWmwKMDVXU6aRz9Gvk+JeYJhtpuP3OPNGbbC5L7NVd
25
+ no+B6AtwxmG3ozd+mPcMeVuz6kKLAmQyIiBSrRNa5OrTkq/CUzxO9WUgTnm/Sri7
26
+ zReR6mU=
27
+ -----END CERTIFICATE-----
@@ -0,0 +1,19 @@
1
+ Bag Attributes
2
+ localKeyID: 4B 45 59 35 31 38 32 35 62 36 35 30 30 30 30 31 32 35 32 00
3
+ Key Attributes: <No Attributes>
4
+ -----BEGIN PRIVATE KEY-----
5
+ MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMLRRHwLWybhs0MM
6
+ EbpmZL2IdgYxmFbADFHoirTp3t22UnorHwqvk16i9YCPS6H8ngEPSP7A5urS/NMq
7
+ w+YmklKlZugO9/TLJqVv4smXFX+5rPMQDedRElIDempMGQlPaR+tp4CQ49oFLJLW
8
+ NH6bKFbAEXa7zhZNH00lFylnei23AgMBAAECgYEAqt912/7x4jaQTrxlSELLFVp9
9
+ eo1BesVTiPwXvPpsGbbyvGjZ/ztkXNs9zZbh1aCGzZMkiR2U7F5GlsiprlIif4cF
10
+ 6Xz7rCjaAs7iDRt9PjhjVuqNGR2I+VIIlbQ9XWFJ3lJFW3v7TIZ8JbLnn0XOFz+Z
11
+ BBSSGTK1zTNh4TBQtjECQQDe5M3uu9m4RwSw9R6GaDw/IFQZgr0oWSv0WIjRwvwW
12
+ nFnSX2lbkNAjulP0daGsmn7vxIpqZxPxwcrU4wFqTF5dAkEA38DnbCm3YfogzwLH
13
+ Nre2hBmGqjWarhtxqtRarrkgnmOd8W0Z1Hb1dSHrliUSVSrINbK5ZdEV15Rpu7VD
14
+ OePzIwJAPMslS+8alANyyR0iJUC65fDYX1jkZOPldDDNqIDJJxWf/hwd7WaTDpuc
15
+ mHmZDi3ZX2Y45oqUywSzYNtFoIuR1QJAZYUZuyqmSK77SdGB36K1DfSi9AFEQDC1
16
+ fwPAbTwTv6mFFPAiYxLiRZXxVPtW+QtjMXH4ymh2V4y/+GnCqbZyLwJBAJQSDAME
17
+ Sn4Uz7Zjk3UrBIbMYEv0u2mcCypwsb0nGE5/gzDPjGE9cxWW+rXARIs+sNQVClnh
18
+ 45nhdfYxOjgYff0=
19
+ -----END PRIVATE KEY-----