savon 0.9.4 → 0.9.5

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.
@@ -1,3 +1,7 @@
1
+ ## 0.9.5 (2011-07-03)
2
+
3
+ * Refactoring: Extracted WSSE authentication out into the [akami](http://rubygems.org/gems/akami) gem.
4
+
1
5
  ## 0.9.4 (2011-07-03)
2
6
 
3
7
  * Refactoring: Extracted the WSDL parser out into the [wasabi](http://rubygems.org/gems/wasabi) gem.
@@ -1,9 +1,10 @@
1
1
  require "httpi/request"
2
+ require "akami"
3
+
2
4
  require "savon/wasabi/document"
3
5
  require "savon/soap/xml"
4
6
  require "savon/soap/request"
5
7
  require "savon/soap/response"
6
- require "savon/wsse"
7
8
 
8
9
  module Savon
9
10
 
@@ -44,9 +45,9 @@ module Savon
44
45
  @http ||= HTTPI::Request.new
45
46
  end
46
47
 
47
- # Returns the <tt>Savon::WSSE</tt> object.
48
+ # Returns the <tt>Akami::WSSE</tt> object.
48
49
  def wsse
49
- @wsse ||= WSSE.new
50
+ @wsse ||= Akami.wsse
50
51
  end
51
52
 
52
53
  # Returns the <tt>Savon::SOAP::XML</tt> object. Please notice, that this object is only available
@@ -16,21 +16,6 @@ module Savon
16
16
  str
17
17
  end unless method_defined?(:snakecase)
18
18
 
19
- # Returns the String in lowerCamelCase.
20
- def lower_camelcase
21
- str = dup
22
- str.gsub!(/\/(.?)/) { "::#{$1.upcase}" }
23
- str.gsub!(/(?:_+|-+)([a-z])/) { $1.upcase }
24
- str.gsub!(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
25
- str
26
- end
27
-
28
- # Returns whether the String starts with a given +prefix+.
29
- def starts_with?(prefix)
30
- prefix = prefix.to_s
31
- self[0, prefix.length] == prefix
32
- end unless method_defined?(:starts_with?)
33
-
34
19
  end
35
20
  end
36
21
  end
@@ -1,5 +1,5 @@
1
1
  module Savon
2
2
 
3
- Version = "0.9.4"
3
+ Version = "0.9.5"
4
4
 
5
5
  end
@@ -6,7 +6,7 @@ module Savon
6
6
 
7
7
  # = Savon::Wasabi::Document
8
8
  #
9
- # Extends the <tt>Wasabi::Document</tt> to extend its document handling by
9
+ # Extends the document handling of the <tt>Wasabi::Document</tt> by
10
10
  # adding support for remote and local WSDL documents.
11
11
  class Document < ::Wasabi::Document
12
12
 
@@ -15,6 +15,11 @@ module Savon
15
15
  @xml ||= document.kind_of?(String) ? resolve_document : document
16
16
  end
17
17
 
18
+ # Sets the <tt>HTTPI::Request</tt> for remote WSDL documents.
19
+ attr_writer :request
20
+
21
+ private
22
+
18
23
  # Sets up and returns the <tt>HTTPI::Request</tt>.
19
24
  def request
20
25
  @request ||= HTTPI::Request.new
@@ -22,11 +27,6 @@ module Savon
22
27
  @request
23
28
  end
24
29
 
25
- # Sets the <tt>HTTPI::Request</tt> for remote WSDL documents.
26
- attr_writer :request
27
-
28
- private
29
-
30
30
  # Resolves and returns the raw WSDL document.
31
31
  def resolve_document
32
32
  case document
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_dependency "nori", "~> 1.0"
19
19
  s.add_dependency "httpi", "~> 0.9"
20
20
  s.add_dependency "wasabi", "~> 1.0"
21
+ s.add_dependency "akami", "~> 1.0"
21
22
  s.add_dependency "gyoku", ">= 0.4.0"
22
23
  s.add_dependency "nokogiri", ">= 1.4.0"
23
24
 
@@ -32,7 +32,7 @@ describe Savon::Client do
32
32
  Savon::Client.new do |wsdl, http, wsse|
33
33
  wsdl.should be_an(Savon::Wasabi::Document)
34
34
  http.should be_an(HTTPI::Request)
35
- wsse.should be_an(Savon::WSSE)
35
+ wsse.should be_an(Akami::WSSE)
36
36
  end
37
37
  end
38
38
  end
@@ -47,7 +47,7 @@ describe Savon::Client do
47
47
  end
48
48
 
49
49
  it "should let you access the WSSE object" do
50
- Savon::Client.new { wsse.should be_a(Savon::WSSE) }
50
+ Savon::Client.new { wsse.should be_a(Akami::WSSE) }
51
51
  end
52
52
  end
53
53
  end
@@ -65,8 +65,8 @@ describe Savon::Client do
65
65
  end
66
66
 
67
67
  describe "#wsse" do
68
- it "should return the Savon::WSSE object" do
69
- client.wsse.should be_a(Savon::WSSE)
68
+ it "should return the Akami::WSSE object" do
69
+ client.wsse.should be_a(Akami::WSSE)
70
70
  end
71
71
  end
72
72
 
@@ -171,7 +171,7 @@ describe Savon::Client do
171
171
  soap.should be_a(Savon::SOAP::XML)
172
172
  wsdl.should be_a(Savon::Wasabi::Document)
173
173
  http.should be_an(HTTPI::Request)
174
- wsse.should be_a(Savon::WSSE)
174
+ wsse.should be_a(Akami::WSSE)
175
175
  end
176
176
  end
177
177
  end
@@ -186,7 +186,7 @@ describe Savon::Client do
186
186
  end
187
187
 
188
188
  it "should let you access the WSSE object" do
189
- client.request(:authenticate) { wsse.should be_a(Savon::WSSE) }
189
+ client.request(:authenticate) { wsse.should be_a(Akami::WSSE) }
190
190
  end
191
191
 
192
192
  it "should let you access the WSDL object" do
@@ -222,10 +222,6 @@ describe Savon::Client do
222
222
  let(:client) { Savon::Client.new { wsdl.document = Endpoint.wsdl } }
223
223
  before { HTTPI.expects(:get).returns(new_response(:body => Fixture.wsdl(:authentication))) }
224
224
 
225
- it "should return a list of available SOAP actions" do
226
- client.wsdl.soap_actions.should == [:authenticate]
227
- end
228
-
229
225
  it "adds a SOAPAction header containing the SOAP action name" do
230
226
  HTTPI.stubs(:post).returns(new_response)
231
227
 
@@ -248,10 +244,6 @@ describe Savon::Client do
248
244
 
249
245
  before { HTTPI.expects(:get).never }
250
246
 
251
- it "should return a list of available SOAP actions" do
252
- client.wsdl.soap_actions.should == [:authenticate]
253
- end
254
-
255
247
  it "adds a SOAPAction header containing the SOAP action name" do
256
248
  HTTPI.stubs(:post).returns(new_response)
257
249
 
@@ -260,13 +252,6 @@ describe Savon::Client do
260
252
  end
261
253
  end
262
254
 
263
- it "should get #element_form_default from the WSDL" do
264
- HTTPI.stubs(:post).returns(new_response)
265
- Savon::Wasabi::Document.any_instance.expects(:element_form_default).returns(:qualified)
266
-
267
- client.request :authenticate
268
- end
269
-
270
255
  it "should execute SOAP requests and return the response" do
271
256
  HTTPI.expects(:post).returns(new_response)
272
257
  response = client.request(:authenticate)
@@ -298,13 +283,6 @@ describe Savon::Client do
298
283
  end
299
284
  end
300
285
 
301
- it "should not get #element_form_default from the WSDL" do
302
- HTTPI.stubs(:post).returns(new_response)
303
- Savon::Wasabi::Document.any_instance.expects(:element_form_default).never
304
-
305
- client.request :authenticate
306
- end
307
-
308
286
  it "should execute SOAP requests and return the response" do
309
287
  HTTPI.expects(:post).returns(new_response)
310
288
  response = client.request(:authenticate)
@@ -34,17 +34,4 @@ describe String do
34
34
  end
35
35
  end
36
36
 
37
- describe "lower_camelcase" do
38
- it "converts a snakecase String to lowerCamelCase" do
39
- "lower_camel_case".lower_camelcase.should == "lowerCamelCase"
40
- end
41
- end
42
-
43
- describe "starts_with?" do
44
- it "should return whether it starts with a given suffix" do
45
- "authenticate".starts_with?("auth").should be_true
46
- "authenticate".starts_with?("cate").should be_false
47
- end
48
- end
49
-
50
37
  end
@@ -98,9 +98,9 @@ describe Savon::SOAP::XML do
98
98
  end
99
99
 
100
100
  describe "#wsse" do
101
- it "should set the Savon::WSSE object" do
102
- xml.wsse = Savon::WSSE.new
103
- xml.wsse.should be_a(Savon::WSSE)
101
+ it "should set the Akami::WSSE object" do
102
+ xml.wsse = Akami.wsse
103
+ xml.wsse.should be_a(Akami::WSSE)
104
104
  end
105
105
  end
106
106
 
@@ -235,7 +235,7 @@ describe Savon::SOAP::XML do
235
235
 
236
236
  context "with WSSE authentication" do
237
237
  it "should containg a SOAP header with WSSE authentication details" do
238
- xml.wsse = Savon::WSSE.new
238
+ xml.wsse = Akami.wsse
239
239
  xml.wsse.credentials "username", "password"
240
240
 
241
241
  xml.to_xml.should include("<env:Header><wsse:Security")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: savon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
4
+ hash: 49
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 4
10
- version: 0.9.4
9
+ - 5
10
+ version: 0.9.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Harrington
@@ -79,9 +79,24 @@ dependencies:
79
79
  type: :runtime
80
80
  version_requirements: *id004
81
81
  - !ruby/object:Gem::Dependency
82
- name: gyoku
82
+ name: akami
83
83
  prerelease: false
84
84
  requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 15
90
+ segments:
91
+ - 1
92
+ - 0
93
+ version: "1.0"
94
+ type: :runtime
95
+ version_requirements: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ name: gyoku
98
+ prerelease: false
99
+ requirement: &id006 !ruby/object:Gem::Requirement
85
100
  none: false
86
101
  requirements:
87
102
  - - ">="
@@ -93,11 +108,11 @@ dependencies:
93
108
  - 0
94
109
  version: 0.4.0
95
110
  type: :runtime
96
- version_requirements: *id005
111
+ version_requirements: *id006
97
112
  - !ruby/object:Gem::Dependency
98
113
  name: nokogiri
99
114
  prerelease: false
100
- requirement: &id006 !ruby/object:Gem::Requirement
115
+ requirement: &id007 !ruby/object:Gem::Requirement
101
116
  none: false
102
117
  requirements:
103
118
  - - ">="
@@ -109,11 +124,11 @@ dependencies:
109
124
  - 0
110
125
  version: 1.4.0
111
126
  type: :runtime
112
- version_requirements: *id006
127
+ version_requirements: *id007
113
128
  - !ruby/object:Gem::Dependency
114
129
  name: rake
115
130
  prerelease: false
116
- requirement: &id007 !ruby/object:Gem::Requirement
131
+ requirement: &id008 !ruby/object:Gem::Requirement
117
132
  none: false
118
133
  requirements:
119
134
  - - ~>
@@ -125,11 +140,11 @@ dependencies:
125
140
  - 7
126
141
  version: 0.8.7
127
142
  type: :development
128
- version_requirements: *id007
143
+ version_requirements: *id008
129
144
  - !ruby/object:Gem::Dependency
130
145
  name: rspec
131
146
  prerelease: false
132
- requirement: &id008 !ruby/object:Gem::Requirement
147
+ requirement: &id009 !ruby/object:Gem::Requirement
133
148
  none: false
134
149
  requirements:
135
150
  - - ~>
@@ -141,11 +156,11 @@ dependencies:
141
156
  - 0
142
157
  version: 2.5.0
143
158
  type: :development
144
- version_requirements: *id008
159
+ version_requirements: *id009
145
160
  - !ruby/object:Gem::Dependency
146
161
  name: mocha
147
162
  prerelease: false
148
- requirement: &id009 !ruby/object:Gem::Requirement
163
+ requirement: &id010 !ruby/object:Gem::Requirement
149
164
  none: false
150
165
  requirements:
151
166
  - - ~>
@@ -157,11 +172,11 @@ dependencies:
157
172
  - 8
158
173
  version: 0.9.8
159
174
  type: :development
160
- version_requirements: *id009
175
+ version_requirements: *id010
161
176
  - !ruby/object:Gem::Dependency
162
177
  name: timecop
163
178
  prerelease: false
164
- requirement: &id010 !ruby/object:Gem::Requirement
179
+ requirement: &id011 !ruby/object:Gem::Requirement
165
180
  none: false
166
181
  requirements:
167
182
  - - ~>
@@ -173,11 +188,11 @@ dependencies:
173
188
  - 5
174
189
  version: 0.3.5
175
190
  type: :development
176
- version_requirements: *id010
191
+ version_requirements: *id011
177
192
  - !ruby/object:Gem::Dependency
178
193
  name: autotest
179
194
  prerelease: false
180
- requirement: &id011 !ruby/object:Gem::Requirement
195
+ requirement: &id012 !ruby/object:Gem::Requirement
181
196
  none: false
182
197
  requirements:
183
198
  - - ">="
@@ -187,7 +202,7 @@ dependencies:
187
202
  - 0
188
203
  version: "0"
189
204
  type: :development
190
- version_requirements: *id011
205
+ version_requirements: *id012
191
206
  description: Ruby's heavy metal SOAP client
192
207
  email: me@rubiii.com
193
208
  executables: []
@@ -210,7 +225,6 @@ files:
210
225
  - lib/savon/client.rb
211
226
  - lib/savon/core_ext/object.rb
212
227
  - lib/savon/core_ext/string.rb
213
- - lib/savon/core_ext/time.rb
214
228
  - lib/savon/error.rb
215
229
  - lib/savon/global.rb
216
230
  - lib/savon/http/error.rb
@@ -221,7 +235,6 @@ files:
221
235
  - lib/savon/soap/xml.rb
222
236
  - lib/savon/version.rb
223
237
  - lib/savon/wasabi/document.rb
224
- - lib/savon/wsse.rb
225
238
  - savon.gemspec
226
239
  - spec/fixtures/gzip/message.gz
227
240
  - spec/fixtures/response/another_soap_fault.xml
@@ -232,15 +245,9 @@ files:
232
245
  - spec/fixtures/response/soap_fault.xml
233
246
  - spec/fixtures/response/soap_fault12.xml
234
247
  - spec/fixtures/wsdl/authentication.xml
235
- - spec/fixtures/wsdl/geotrust.xml
236
- - spec/fixtures/wsdl/namespaced_actions.xml
237
- - spec/fixtures/wsdl/no_namespace.xml
238
- - spec/fixtures/wsdl/soap12.xml
239
- - spec/fixtures/wsdl/two_bindings.xml
240
248
  - spec/savon/client_spec.rb
241
249
  - spec/savon/core_ext/object_spec.rb
242
250
  - spec/savon/core_ext/string_spec.rb
243
- - spec/savon/core_ext/time_spec.rb
244
251
  - spec/savon/http/error_spec.rb
245
252
  - spec/savon/savon_spec.rb
246
253
  - spec/savon/soap/fault_spec.rb
@@ -249,7 +256,6 @@ files:
249
256
  - spec/savon/soap/xml_spec.rb
250
257
  - spec/savon/soap_spec.rb
251
258
  - spec/savon/wasabi/document_spec.rb
252
- - spec/savon/wsse_spec.rb
253
259
  - spec/spec_helper.rb
254
260
  - spec/support/endpoint.rb
255
261
  - spec/support/fixture.rb
@@ -1,22 +0,0 @@
1
- module Savon
2
- module CoreExt
3
- module Time
4
-
5
- # Returns an xs:dateTime formatted String.
6
- def xs_datetime
7
- zone = if utc_offset < 0
8
- "-#{"%02d" % (- utc_offset / 3600)}:#{"%02d" % ((- utc_offset % 3600) / 60)}"
9
- elsif utc_offset > 0
10
- "+#{"%02d" % (utc_offset / 3600)}:#{"%02d" % ((utc_offset % 3600) / 60)}"
11
- else
12
- "Z"
13
- end
14
-
15
- strftime "%Y-%m-%dT%H:%M:%S#{zone}"
16
- end
17
-
18
- end
19
- end
20
- end
21
-
22
- Time.send :include, Savon::CoreExt::Time
@@ -1,156 +0,0 @@
1
- require "base64"
2
- require "digest/sha1"
3
-
4
- require "savon/core_ext/string"
5
- require "savon/core_ext/time"
6
-
7
- module Savon
8
-
9
- # = Savon::WSSE
10
- #
11
- # Provides WSSE authentication.
12
- class WSSE
13
-
14
- # Namespace for WS Security Secext.
15
- WSENamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
16
-
17
- # Namespace for WS Security Utility.
18
- WSUNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
19
-
20
- # URI for "wsse:Password/@Type" #PasswordText.
21
- PasswordTextURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
22
-
23
- # URI for "wsse:Password/@Type" #PasswordDigest.
24
- PasswordDigestURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
25
-
26
- # Returns a value from the WSSE Hash.
27
- def [](key)
28
- hash[key]
29
- end
30
-
31
- # Sets a value on the WSSE Hash.
32
- def []=(key, value)
33
- hash[key] = value
34
- end
35
-
36
- # Sets authentication credentials for a wsse:UsernameToken header.
37
- # Also accepts whether to use WSSE digest authentication.
38
- def credentials(username, password, digest = false)
39
- self.username = username
40
- self.password = password
41
- self.digest = digest
42
- end
43
-
44
- attr_accessor :username, :password, :created_at, :expires_at
45
-
46
- # Returns whether to use WSSE digest. Defaults to +false+.
47
- def digest?
48
- !!@digest
49
- end
50
-
51
- attr_writer :digest
52
-
53
- # Returns whether to generate a wsse:UsernameToken header.
54
- def username_token?
55
- username && password
56
- end
57
-
58
- # Returns whether to generate a wsu:Timestamp header.
59
- def timestamp?
60
- created_at || expires_at || @wsu_timestamp
61
- end
62
-
63
- # Sets whether to generate a wsu:Timestamp header.
64
- def timestamp=(timestamp)
65
- @wsu_timestamp = timestamp
66
- end
67
-
68
- # Returns the XML for a WSSE header.
69
- def to_xml
70
- if username_token? && timestamp?
71
- Gyoku.xml wsse_username_token.merge!(wsu_timestamp) {
72
- |key, v1, v2| v1.merge!(v2) {
73
- |key, v1, v2| v1.merge!(v2)
74
- }
75
- }
76
- elsif username_token?
77
- Gyoku.xml wsse_username_token.merge!(hash)
78
- elsif timestamp?
79
- Gyoku.xml wsu_timestamp.merge!(hash)
80
- else
81
- ""
82
- end
83
- end
84
-
85
- private
86
-
87
- # Returns a Hash containing wsse:UsernameToken details.
88
- def wsse_username_token
89
- if digest?
90
- security_hash :wsse, "UsernameToken",
91
- "wsse:Username" => username,
92
- "wsse:Nonce" => nonce,
93
- "wsu:Created" => timestamp,
94
- "wsse:Password" => digest_password,
95
- :attributes! => { "wsse:Password" => { "Type" => PasswordDigestURI } }
96
- else
97
- security_hash :wsse, "UsernameToken",
98
- "wsse:Username" => username,
99
- "wsse:Password" => password,
100
- :attributes! => { "wsse:Password" => { "Type" => PasswordTextURI } }
101
- end
102
- end
103
-
104
- # Returns a Hash containing wsu:Timestamp details.
105
- def wsu_timestamp
106
- security_hash :wsu, "Timestamp",
107
- "wsu:Created" => (created_at || Time.now).xs_datetime,
108
- "wsu:Expires" => (expires_at || (created_at || Time.now) + 60).xs_datetime
109
- end
110
-
111
- # Returns a Hash containing wsse/wsu Security details for a given
112
- # +namespace+, +tag+ and +hash+.
113
- def security_hash(namespace, tag, hash)
114
- {
115
- "wsse:Security" => {
116
- "#{namespace}:#{tag}" => hash,
117
- :attributes! => { "#{namespace}:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSUNamespace } }
118
- },
119
- :attributes! => { "wsse:Security" => { "xmlns:wsse" => WSENamespace } }
120
- }
121
- end
122
-
123
- # Returns the WSSE password, encrypted for digest authentication.
124
- def digest_password
125
- token = nonce + timestamp + password
126
- Base64.encode64(Digest::SHA1.hexdigest(token)).chomp!
127
- end
128
-
129
- # Returns a WSSE nonce.
130
- def nonce
131
- @nonce ||= Digest::SHA1.hexdigest random_string + timestamp
132
- end
133
-
134
- # Returns a random String of 100 characters.
135
- def random_string
136
- (0...100).map { ("a".."z").to_a[rand(26)] }.join
137
- end
138
-
139
- # Returns a WSSE timestamp.
140
- def timestamp
141
- @timestamp ||= Time.now.xs_datetime
142
- end
143
-
144
- # Returns a new number with every call.
145
- def count
146
- @count ||= 0
147
- @count += 1
148
- end
149
-
150
- # Returns a memoized and autovivificating Hash.
151
- def hash
152
- @hash ||= Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
153
- end
154
-
155
- end
156
- end