savon 2.10.1 → 2.12.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="www.example.com/XML" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s1="http://microsoft.com/wsdl/types/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="www.example.com/XML" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
3
+ <wsdl:types>
4
+ <s:schema elementFormDefault="qualified" targetNamespace="www.example.com/XML">
5
+ <s:complexType name="Transaction" abstract="true">
6
+ <s:sequence>
7
+ <s:element minOccurs="0" maxOccurs="1" name="Qualified" type="s:string" />
8
+ </s:sequence>
9
+ </s:complexType>
10
+ <s:complexType name="TopLevelTransaction">
11
+ <s:complexContent mixed="false">
12
+ <s:extension base="tns:Transaction">
13
+ </s:extension>
14
+ </s:complexContent>
15
+ </s:complexType>
16
+ <s:element name="TopLevelTransaction">
17
+ <s:complexType>
18
+ <s:sequence>
19
+ <s:element minOccurs="0" maxOccurs="1" name="TopLevelTransaction" type="tns:TopLevelTransaction" />
20
+ </s:sequence>
21
+ </s:complexType>
22
+ </s:element>
23
+ </s:schema>
24
+ </wsdl:types>
25
+ <wsdl:message name="TopLevelTransactionSoapIn">
26
+ <wsdl:part name="parameters" element="tns:TopLevelTransaction" />
27
+ </wsdl:message>
28
+ <wsdl:portType name="XMLTESoap">
29
+ <wsdl:operation name="TopLevelTransaction">
30
+ <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">TopLevelTransaction.</wsdl:documentation>
31
+ <wsdl:input message="tns:TopLevelTransactionSoapIn" />
32
+ </wsdl:operation>
33
+ </wsdl:portType>
34
+ <wsdl:binding name="XMLTESoap12" type="tns:XMLTESoap">
35
+ <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
36
+ <wsdl:operation name="TopLevelTransaction">
37
+ <soap12:operation soapAction="www.example.com/XML/TopLevelTransaction" style="document" />
38
+ <wsdl:input>
39
+ <soap12:body use="literal" />
40
+ </wsdl:input>
41
+ </wsdl:operation>
42
+ </wsdl:binding>
43
+ </wsdl:definitions>
@@ -2,14 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  module LogInterceptor
4
4
  @@intercepted_request = ""
5
- def self.debug(message)
5
+ def self.debug(message = nil)
6
+ message ||= yield if block_given?
7
+
6
8
  # save only the first XMLly message
7
9
  if message.include? "xml version"
8
10
  @@intercepted_request = message if @@intercepted_request == ""
9
11
  end
10
12
  end
11
13
 
12
- def self.info(message)
14
+ def self.info(message = nil)
13
15
  end
14
16
 
15
17
  def self.get_intercepted_request
@@ -27,6 +29,7 @@ describe 'Correct translation of attributes to XML' do
27
29
 
28
30
  client = Savon.client(
29
31
  :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
32
+ :log => true,
30
33
  :logger => LogInterceptor
31
34
  )
32
35
 
@@ -48,14 +51,12 @@ describe 'Correct translation of attributes to XML' do
48
51
 
49
52
  client = Savon.client(
50
53
  :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
54
+ :log => true,
51
55
  :logger => LogInterceptor
52
56
  )
53
57
 
54
58
  response = nil
55
- begin
56
- response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => {}, :attributes! => { :user => { :userID => "test" } } })
57
- rescue
58
- end
59
+ response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => {}, :attributes! => { :user => { :userID => "test" } } })
59
60
 
60
61
  xml_doc = Nokogiri::XML(LogInterceptor.get_intercepted_request)
61
62
  xml_doc.remove_namespaces!
@@ -16,7 +16,7 @@ describe 'rpc/encoded binding test' do
16
16
  $stderr.puts e.to_hash.inspect
17
17
  f_c = e.to_hash[:fault][:faultstring]
18
18
  expect(f_c).not_to eq('No such operation \'getQuoteRequest\'')
19
- expect(f_c).to eq('soapenv:Server.userException')
19
+ expect(f_c).to eq('lucee.runtime.exp.DatabaseException: ')
20
20
  pending e
21
21
  end
22
22
  end
@@ -19,6 +19,12 @@ describe "Stockquote example" do
19
19
 
20
20
  cdata = response.body[:get_quote_response][:get_quote_result]
21
21
 
22
+ if cdata == "exception"
23
+ # Fallback to not fail the specs when the service's API limit is reached,
24
+ # but to mark the spec as pending instead.
25
+ pending "Exception on API"
26
+ end
27
+
22
28
  nori_options = { :convert_tags_to => lambda { |tag| tag.snakecase.to_sym } }
23
29
  result = Nori.new(nori_options).parse(cdata)
24
30
 
@@ -1,4 +1,4 @@
1
- require "rack/builder"
1
+ require "rack"
2
2
  require "json"
3
3
 
4
4
  class IntegrationServer
@@ -83,10 +83,19 @@ describe Savon::Builder do
83
83
  end
84
84
 
85
85
  describe "#wsse_signature" do
86
- let(:private_key) { "spec/fixtures/ssl/client_key.pem" }
87
- let(:cert) { "spec/fixtures/ssl/client_cert.pem" }
88
- let(:signature) { Akami::WSSE::Signature.new(Akami::WSSE::Certs.new(:cert_file => cert, :private_key_file => private_key))}
89
- let(:globals) { Savon::GlobalOptions.new(wsse_signature: signature) }
86
+ fixture_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssl')
87
+
88
+ let(:cert) { File.join(fixture_dir, 'client_cert.pem') }
89
+ let(:private_key) { File.join(fixture_dir, 'client_key.pem') }
90
+ let(:signature) do
91
+ Akami::WSSE::Signature.new(
92
+ Akami::WSSE::Certs.new(
93
+ :cert_file => cert,
94
+ :private_key_file => private_key
95
+ )
96
+ )
97
+ end
98
+ let(:globals) { Savon::GlobalOptions.new(wsse_signature: signature) }
90
99
 
91
100
  subject(:signed_message_nn) {Nokogiri::XML(builder.to_s).remove_namespaces!}
92
101
  subject(:signed_message) {Nokogiri::XML(builder.to_s)}
@@ -21,9 +21,15 @@ describe Savon::LogMessage do
21
21
  expect(message).to include("\n <body>")
22
22
  end
23
23
 
24
- it "filters tags in a given message" do
24
+ it "filters tags in a given message without pretty printing" do
25
25
  message = log_message("<root><password>secret</password></root>", [:password], false).to_s
26
26
  expect(message).to include("<password>***FILTERED***</password>")
27
+ expect(message).to_not include("\n <password>***FILTERED***</password>") # no pretty printing
28
+ end
29
+
30
+ it "filters tags in a given message with pretty printing" do
31
+ message = log_message("<root><password>secret</password></root>", [:password], true).to_s
32
+ expect(message).to include("\n <password>***FILTERED***</password>")
27
33
  end
28
34
 
29
35
  it "properly applies Proc filter" do
@@ -23,6 +23,17 @@ describe "Savon's mock interface" do
23
23
  expect(response.http.body).to eq("<fixture/>")
24
24
  end
25
25
 
26
+ it "can verify a request with any parameters and return a fixture response" do
27
+ message = { :username => "luke", :password => :any }
28
+ savon.expects(:authenticate).with(:message => message).returns("<fixture/>")
29
+
30
+ response = new_client.call(:authenticate) do
31
+ message(:username => "luke", :password => "secret")
32
+ end
33
+
34
+ expect(response.http.body).to eq("<fixture/>")
35
+ end
36
+
26
37
  it "accepts a Hash to specify the response code, headers and body" do
27
38
  soap_fault = Fixture.response(:soap_fault)
28
39
  response = { :code => 500, :headers => { "X-Result" => "invalid" }, :body => soap_fault }
@@ -114,6 +114,15 @@ describe "Options" do
114
114
  end
115
115
  end
116
116
 
117
+ context "global :host" do
118
+ it "overrides the WSDL endpoint host" do
119
+ client = new_client(:wsdl => Fixture.wsdl(:no_message_tag), host: "https://example.com:8080")
120
+
121
+ request = client.build_request(:update_orders)
122
+ expect(request.url.to_s).to eq "https://example.com:8080/webserviceexternal/contracts.asmx"
123
+ end
124
+ end
125
+
117
126
  context "global :headers" do
118
127
  it "sets the HTTP headers for the next request" do
119
128
  client = new_client(:endpoint => @server.url(:inspect_request), :headers => { "X-Token" => "secret" })
@@ -210,6 +219,17 @@ describe "Options" do
210
219
  expect(response.http.body).to include("<user>lea</user>")
211
220
  expect(response.http.body).to include("<password>top-secret</password>")
212
221
  end
222
+
223
+ it "qualifies elements embedded in complex types" do
224
+ client = new_client(:endpoint => @server.url(:repeat),
225
+ :wsdl => Fixture.wsdl(:elements_in_types))
226
+ msg = {":TopLevelTransaction"=>{":Qualified"=>"A Value"}}
227
+
228
+ response = client.call(:top_level_transaction, :message => msg)
229
+
230
+ expect(response.http.body.scan(/<tns:Qualified>/).count).to eq(1)
231
+ end
232
+
213
233
  end
214
234
 
215
235
  context "global :env_namespace" do
@@ -380,18 +400,27 @@ describe "Options" do
380
400
 
381
401
  context "global :ssl_version" do
382
402
  it "sets the SSL version to use" do
383
- HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:SSLv3).twice
403
+ HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:TLSv1).twice
384
404
 
385
- client = new_client(:endpoint => @server.url, :ssl_version => :SSLv3)
405
+ client = new_client(:endpoint => @server.url, :ssl_version => :TLSv1)
386
406
  client.call(:authenticate)
387
407
  end
388
408
  end
389
409
 
390
410
  context "global :ssl_verify_mode" do
391
411
  it "sets the verify mode to use" do
392
- HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:none).twice
412
+ HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:peer).twice
413
+
414
+ client = new_client(:endpoint => @server.url, :ssl_verify_mode => :peer)
415
+ client.call(:authenticate)
416
+ end
417
+ end
418
+
419
+ context "global :ssl_ciphers" do
420
+ it "sets the ciphers to use" do
421
+ HTTPI::Auth::SSL.any_instance.expects(:ciphers=).with(:none).twice
393
422
 
394
- client = new_client(:endpoint => @server.url, :ssl_verify_mode => :none)
423
+ client = new_client(:endpoint => @server.url, :ssl_ciphers => :none)
395
424
  client.call(:authenticate)
396
425
  end
397
426
  end
@@ -460,6 +489,26 @@ describe "Options" do
460
489
  end
461
490
  end
462
491
 
492
+ context "global :ssl_ca_cert_path" do
493
+ it "sets the ca cert path to use" do
494
+ ca_cert_path = "../../fixtures/ssl"
495
+ HTTPI::Auth::SSL.any_instance.expects(:ca_cert_path=).with(ca_cert_path).twice
496
+
497
+ client = new_client(:endpoint => @server.url, :ssl_ca_cert_path => ca_cert_path)
498
+ client.call(:authenticate)
499
+ end
500
+ end
501
+
502
+ context "global :ssl_ca_cert_store" do
503
+ it "sets the cert store to use" do
504
+ cert_store = OpenSSL::X509::Store.new
505
+ HTTPI::Auth::SSL.any_instance.expects(:cert_store=).with(cert_store).twice
506
+
507
+ client = new_client(:endpoint => @server.url, :ssl_cert_store => cert_store)
508
+ client.call(:authenticate)
509
+ end
510
+ end
511
+
463
512
  context "global :ssl_ca_cert" do
464
513
  it "sets the ca cert file to use" do
465
514
  ca_cert = File.open(File.expand_path("../../fixtures/ssl/client_cert.pem", __FILE__)).read
@@ -578,7 +627,7 @@ describe "Options" do
578
627
  expect(request).to include("<wsse:Username>#{username}</wsse:Username>")
579
628
 
580
629
  # the nonce node
581
- expect(request).to match(/<wsse:Nonce.*>.+\n<\/wsse:Nonce>/)
630
+ expect(request).to match(/<wsse:Nonce.*>.+\n?<\/wsse:Nonce>/)
582
631
 
583
632
  # the created node with a timestamp
584
633
  expect(request).to match(/<wsu:Created>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Created>/)
@@ -1037,6 +1086,17 @@ describe "Options" do
1037
1086
  end
1038
1087
  end
1039
1088
 
1089
+ context "request :headers" do
1090
+ it "sets headers" do
1091
+ client = new_client(:endpoint => @server.url(:inspect_request))
1092
+
1093
+ response = client.call(:authenticate, :headers => { "X-Token" => "secret" })
1094
+ x_token = inspect_request(response).x_token
1095
+
1096
+ expect(x_token).to eq("secret")
1097
+ end
1098
+ end
1099
+
1040
1100
  def new_client(globals = {}, &block)
1041
1101
  globals = { :wsdl => Fixture.wsdl(:authentication), :log => false }.merge(globals)
1042
1102
  Savon.client(globals, &block)
@@ -4,15 +4,96 @@ module Savon
4
4
  describe QualifiedMessage, "#to_hash" do
5
5
 
6
6
  context "if a key ends with !" do
7
- it "restores the ! in a key" do
8
- used_namespaces = {}
9
- key_converter = :camelcase
10
- types = {}
7
+ let(:used_namespaces) { {} }
8
+ let(:key_converter) { :camelcase }
9
+ let(:types) { {} }
11
10
 
11
+ it "restores the ! in a key" do
12
12
  message = described_class.new(types, used_namespaces, key_converter)
13
13
  resulting_hash = message.to_hash({:Metal! => "<Nice/>"}, ["Rock"])
14
14
 
15
- expect(resulting_hash).to eq({"Metal!" => "<Nice/>"})
15
+ expect(resulting_hash).to eq({ :Metal! => "<Nice/>" })
16
+ end
17
+
18
+ it "properly handles special keys when namespaces are present" do
19
+ used_namespaces = {
20
+ %w(tns Foo) => 'ns',
21
+ %w(tns Foo Bar) => 'ns'
22
+ }
23
+
24
+ hash = {
25
+ :foo => {
26
+ :bar => {
27
+ :zing => 'pow'
28
+ },
29
+ :cash => {
30
+ :@attr1 => 'val1',
31
+ :content! => 'Chunky Bacon'
32
+ },
33
+ :attributes! => {
34
+ :bar => { :attr2 => 'val2' },
35
+ },
36
+ :"self_closing/" => '',
37
+ :order! => [:cash, :bar, :"self_closing/"]
38
+ }
39
+ }
40
+
41
+ good_result = {
42
+ "ns:Foo" => {
43
+ 'ns:Bar' => { :zing => "pow" },
44
+ :cash => {
45
+ :@attr1 => "val1",
46
+ :content! => "Chunky Bacon"
47
+ },
48
+ :attributes! => {
49
+ 'ns:Bar' => { :attr2 => 'val2' }
50
+ },
51
+ :"self_closing/" => '',
52
+ :order! => [:cash, 'ns:Bar', :"self_closing/"]
53
+ }
54
+ }
55
+
56
+ good_xml = %(<ns:Foo><Cash attr1="val1">Chunky Bacon</Cash><ns:Bar attr2="val2"><Zing>pow</Zing></ns:Bar><SelfClosing/></ns:Foo>)
57
+
58
+ message = described_class.new(types, used_namespaces, key_converter)
59
+ resulting_hash = message.to_hash(hash, ['tns'])
60
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
61
+
62
+ expect(resulting_hash).to eq good_result
63
+ expect(xml).to eq good_xml
64
+ end
65
+
66
+ it "properly handles boolean false" do
67
+ used_namespaces = {
68
+ %w(tns Foo) => 'ns'
69
+ }
70
+
71
+ hash = {
72
+ :foo => {
73
+ :falsey => {
74
+ :@attr1 => false,
75
+ :content! => false
76
+ }
77
+ }
78
+ }
79
+
80
+ good_result = {
81
+ "ns:Foo" => {
82
+ :falsey => {
83
+ :@attr1 => false,
84
+ :content! => false
85
+ }
86
+ }
87
+ }
88
+
89
+ good_xml = %(<ns:Foo><Falsey attr1="false">false</Falsey></ns:Foo>)
90
+
91
+ message = described_class.new(types, used_namespaces, key_converter)
92
+ resulting_hash = message.to_hash(hash, ['tns'])
93
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
94
+
95
+ expect(resulting_hash).to eq good_result
96
+ expect(xml).to eq good_xml
16
97
  end
17
98
  end
18
99
 
@@ -5,6 +5,7 @@ describe Savon::WSDLRequest do
5
5
 
6
6
  let(:globals) { Savon::GlobalOptions.new }
7
7
  let(:http_request) { HTTPI::Request.new }
8
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
8
9
 
9
10
  def new_wsdl_request
10
11
  Savon::WSDLRequest.new(globals, http_request)
@@ -16,6 +17,20 @@ describe Savon::WSDLRequest do
16
17
  expect(wsdl_request.build).to be_an(HTTPI::Request)
17
18
  end
18
19
 
20
+ describe "headers" do
21
+ it "are set when specified" do
22
+ globals.headers("Proxy-Authorization" => "Basic auth")
23
+ configured_http_request = new_wsdl_request.build
24
+
25
+ expect(configured_http_request.headers["Proxy-Authorization"]).to eq("Basic auth")
26
+ end
27
+
28
+ it "are not set otherwise" do
29
+ configured_http_request = new_wsdl_request.build
30
+ expect(configured_http_request.headers).to_not include("Proxy-Authorization")
31
+ end
32
+ end
33
+
19
34
  describe "proxy" do
20
35
  it "is set when specified" do
21
36
  globals.proxy("http://proxy.example.com")
@@ -60,8 +75,8 @@ describe Savon::WSDLRequest do
60
75
 
61
76
  describe "ssl version" do
62
77
  it "is set when specified" do
63
- globals.ssl_version(:SSLv3)
64
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
78
+ globals.ssl_version(:TLSv1)
79
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
65
80
 
66
81
  new_wsdl_request.build
67
82
  end
@@ -74,8 +89,8 @@ describe Savon::WSDLRequest do
74
89
 
75
90
  describe "ssl verify mode" do
76
91
  it "is set when specified" do
77
- globals.ssl_verify_mode(:none)
78
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
92
+ globals.ssl_verify_mode(:peer)
93
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
79
94
 
80
95
  new_wsdl_request.build
81
96
  end
@@ -86,6 +101,20 @@ describe Savon::WSDLRequest do
86
101
  end
87
102
  end
88
103
 
104
+ describe "ssl ciphers" do
105
+ it "is set when specified" do
106
+ globals.ssl_ciphers(ciphers)
107
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
108
+
109
+ new_wsdl_request.build
110
+ end
111
+
112
+ it "is not set otherwise" do
113
+ http_request.auth.ssl.expects(:ciphers=).never
114
+ new_wsdl_request.build
115
+ end
116
+ end
117
+
89
118
  describe "ssl cert key file" do
90
119
  it "is set when specified" do
91
120
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)
@@ -232,6 +261,7 @@ describe Savon::SOAPRequest do
232
261
 
233
262
  let(:globals) { Savon::GlobalOptions.new }
234
263
  let(:http_request) { HTTPI::Request.new }
264
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
235
265
 
236
266
  def new_soap_request
237
267
  Savon::SOAPRequest.new(globals, http_request)
@@ -364,8 +394,8 @@ describe Savon::SOAPRequest do
364
394
 
365
395
  describe "ssl version" do
366
396
  it "is set when specified" do
367
- globals.ssl_version(:SSLv3)
368
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
397
+ globals.ssl_version(:TLSv1)
398
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
369
399
 
370
400
  new_soap_request.build
371
401
  end
@@ -378,8 +408,8 @@ describe Savon::SOAPRequest do
378
408
 
379
409
  describe "ssl verify mode" do
380
410
  it "is set when specified" do
381
- globals.ssl_verify_mode(:none)
382
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
411
+ globals.ssl_verify_mode(:peer)
412
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
383
413
 
384
414
  new_soap_request.build
385
415
  end
@@ -390,6 +420,20 @@ describe Savon::SOAPRequest do
390
420
  end
391
421
  end
392
422
 
423
+ describe "ssl ciphers" do
424
+ it "is set when specified" do
425
+ globals.ssl_ciphers(ciphers)
426
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
427
+
428
+ new_soap_request.build
429
+ end
430
+
431
+ it "is not set otherwise" do
432
+ http_request.auth.ssl.expects(:ciphers=).never
433
+ new_soap_request.build
434
+ end
435
+ end
436
+
393
437
  describe "ssl cert key file" do
394
438
  it "is set when specified" do
395
439
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)