sepafm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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-----