savon 0.8.1 → 0.8.2
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.
- data/CHANGELOG.md +28 -2
- data/lib/savon/core_ext/hash.rb +10 -0
- data/lib/savon/core_ext/time.rb +14 -0
- data/lib/savon/soap.rb +0 -3
- data/lib/savon/soap/fault.rb +1 -1
- data/lib/savon/version.rb +1 -1
- data/lib/savon/wsse.rb +73 -24
- data/savon.gemspec +1 -0
- data/spec/savon/core_ext/hash_spec.rb +9 -0
- data/spec/savon/core_ext/time_spec.rb +13 -0
- data/spec/savon/soap_spec.rb +1 -9
- data/spec/savon/wsse_spec.rb +50 -0
- metadata +24 -6
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,34 @@
|
|
1
|
-
## 0.8.
|
1
|
+
## 0.8.2 (2010-01-04)
|
2
|
+
|
3
|
+
* Fix for [issue #127](https://github.com/rubiii/savon/issues/127) ([0eb3da](https://github.com/rubiii/savon/commit/0eb3da4))
|
4
|
+
|
5
|
+
* Changed `Savon::WSSE` to be based on a Hash instead of relying on builder ([4cebc3](https://github.com/rubiii/savon/commit/4cebc3)).
|
6
|
+
|
7
|
+
`Savon::WSSE` now supports wsse:Timestamp headers ([issue #122](https://github.com/rubiii/savon/issues/122)) by setting
|
8
|
+
`Savon::WSSE#timestamp` to `true`:
|
9
|
+
|
10
|
+
client.request :some_method do
|
11
|
+
wsse.timestamp = true
|
12
|
+
end
|
13
|
+
|
14
|
+
or by setting `Savon::WSSE#created_at` or `Savon::WSSE#expires_at`:
|
15
|
+
|
16
|
+
client.request :some_method do
|
17
|
+
wsse.created_at = Time.now
|
18
|
+
wsse.expires_at = Time.now + 60
|
19
|
+
end
|
20
|
+
|
21
|
+
You can also add custom tags to the WSSE header ([issue #69](https://github.com/rubiii/savon/issues/69)):
|
22
|
+
|
23
|
+
client.request :some_method do
|
24
|
+
wsse["wsse:Security"]["wsse:UsernameToken"] = { "Organization" => "ACME", "Domain" => "acme.com" }
|
25
|
+
end
|
26
|
+
|
27
|
+
## 0.8.1 (2010-12-22)
|
2
28
|
|
3
29
|
* Update to depend on HTTPI v0.7.5 which comes with a fallback to use Net::HTTP when no other adapter could be required.
|
4
30
|
|
5
|
-
* Fix for [issue #72](https://github.com/rubiii/savon/issues/72) ([
|
31
|
+
* Fix for [issue #72](https://github.com/rubiii/savon/issues/72) ([22074a](https://github.com/rubiii/savon/commit/22074a8)).
|
6
32
|
|
7
33
|
* Loosen dependency on builder. Should be quite stable.
|
8
34
|
|
data/lib/savon/core_ext/hash.rb
CHANGED
@@ -8,6 +8,16 @@ module Savon
|
|
8
8
|
module CoreExt
|
9
9
|
module Hash
|
10
10
|
|
11
|
+
# Returns a new Hash with +self+ and +other_hash+ merged recursively.
|
12
|
+
# Modifies the receiver in place.
|
13
|
+
def deep_merge!(other_hash)
|
14
|
+
other_hash.each_pair do |k,v|
|
15
|
+
tv = self[k]
|
16
|
+
self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end unless defined? deep_merge!
|
20
|
+
|
11
21
|
# Returns the values from the soap:Body element or an empty Hash in case the soap:Body tag could
|
12
22
|
# not be found.
|
13
23
|
def find_soap_body
|
data/lib/savon/soap.rb
CHANGED
data/lib/savon/soap/fault.rb
CHANGED
data/lib/savon/version.rb
CHANGED
data/lib/savon/wsse.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require "base64"
|
2
2
|
require "digest/sha1"
|
3
|
-
require "builder"
|
4
3
|
|
5
4
|
require "savon/core_ext/string"
|
6
|
-
require "savon/
|
5
|
+
require "savon/core_ext/hash"
|
6
|
+
require "savon/core_ext/time"
|
7
7
|
|
8
8
|
module Savon
|
9
9
|
|
@@ -24,14 +24,25 @@ module Savon
|
|
24
24
|
# URI for "wsse:Password/@Type" #PasswordDigest.
|
25
25
|
PasswordDigestURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
|
26
26
|
|
27
|
-
#
|
27
|
+
# Returns a value from the WSSE Hash.
|
28
|
+
def [](key)
|
29
|
+
hash[key]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sets a value on the WSSE Hash.
|
33
|
+
def []=(key, value)
|
34
|
+
hash[key] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets authentication credentials for a wsse:UsernameToken header.
|
38
|
+
# Also accepts whether to use WSSE digest authentication.
|
28
39
|
def credentials(username, password, digest = false)
|
29
40
|
self.username = username
|
30
41
|
self.password = password
|
31
42
|
self.digest = digest
|
32
43
|
end
|
33
44
|
|
34
|
-
attr_accessor :username, :password
|
45
|
+
attr_accessor :username, :password, :created_at, :expires_at
|
35
46
|
|
36
47
|
# Returns whether to use WSSE digest. Defaults to +false+.
|
37
48
|
def digest?
|
@@ -40,26 +51,64 @@ module Savon
|
|
40
51
|
|
41
52
|
attr_writer :digest
|
42
53
|
|
43
|
-
# Returns
|
44
|
-
|
54
|
+
# Returns whether to generate a wsse:UsernameToken header.
|
55
|
+
def username_token?
|
56
|
+
username && password
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns whether to generate a wsse:Timestamp header.
|
60
|
+
def timestamp?
|
61
|
+
created_at || expires_at || @wsse_timestamp
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sets whether to generate a wsse:Timestamp header.
|
65
|
+
def timestamp=(timestamp)
|
66
|
+
@wsse_timestamp = timestamp
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the XML for a WSSE header.
|
45
70
|
def to_xml
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
xml.wsse :Nonce, nonce
|
53
|
-
xml.wsu :Created, timestamp
|
54
|
-
xml.wsse :Password, password_node, :Type => password_type
|
55
|
-
end
|
71
|
+
if username_token?
|
72
|
+
Gyoku.xml wsse_username_token.merge!(hash)
|
73
|
+
elsif timestamp?
|
74
|
+
Gyoku.xml wsse_timestamp.merge!(hash)
|
75
|
+
else
|
76
|
+
""
|
56
77
|
end
|
57
78
|
end
|
58
79
|
|
59
80
|
private
|
60
81
|
|
82
|
+
# Returns a Hash containing wsse:UsernameToken details.
|
83
|
+
def wsse_username_token
|
84
|
+
wsse_security "UsernameToken",
|
85
|
+
"wsse:Username" => username,
|
86
|
+
"wsse:Nonce" => nonce,
|
87
|
+
"wsu:Created" => timestamp,
|
88
|
+
"wsse:Password" => password_value,
|
89
|
+
:attributes! => { "wsse:Password" => { "Type" => password_type } }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns a Hash containing wsse:Timestamp details.
|
93
|
+
def wsse_timestamp
|
94
|
+
wsse_security "Timestamp",
|
95
|
+
"wsu:Created" => (created_at || Time.now).xs_datetime,
|
96
|
+
"wsu:Expires" => (expires_at || (created_at || Time.now) + 60).xs_datetime
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns a Hash containing wsse:Security details for a given +tag+ and +hash+.
|
100
|
+
def wsse_security(tag, hash)
|
101
|
+
{
|
102
|
+
"wsse:Security" => {
|
103
|
+
"wsse:#{tag}" => hash,
|
104
|
+
:attributes! => { "wsse:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSUNamespace } }
|
105
|
+
},
|
106
|
+
:attributes! => { "wsse:Security" => { "xmlns:wsse" => WSENamespace } }
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
61
110
|
# Returns the WSSE password. Encrypts the password for digest authentication.
|
62
|
-
def
|
111
|
+
def password_value
|
63
112
|
return password unless digest?
|
64
113
|
|
65
114
|
token = nonce + timestamp + password
|
@@ -83,19 +132,19 @@ module Savon
|
|
83
132
|
|
84
133
|
# Returns a WSSE timestamp.
|
85
134
|
def timestamp
|
86
|
-
@timestamp ||= Time.now.
|
87
|
-
end
|
88
|
-
|
89
|
-
# Returns the "wsu:Id" attribute.
|
90
|
-
def wsu_id
|
91
|
-
"UsernameToken-#{count}"
|
135
|
+
@timestamp ||= Time.now.xs_datetime
|
92
136
|
end
|
93
137
|
|
94
|
-
#
|
138
|
+
# Returns a new number with every call.
|
95
139
|
def count
|
96
140
|
@count ||= 0
|
97
141
|
@count += 1
|
98
142
|
end
|
99
143
|
|
144
|
+
# Returns a memoized and autovivificating Hash.
|
145
|
+
def hash
|
146
|
+
@hash ||= Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
|
147
|
+
end
|
148
|
+
|
100
149
|
end
|
101
150
|
end
|
data/savon.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency "rspec", "~> 2.0.0"
|
23
23
|
s.add_development_dependency "autotest"
|
24
24
|
s.add_development_dependency "mocha", "~> 0.9.7"
|
25
|
+
s.add_development_dependency "timecop", "~> 0.3.5"
|
25
26
|
|
26
27
|
s.files = `git ls-files`.split("\n")
|
27
28
|
s.require_path = "lib"
|
@@ -2,6 +2,15 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Hash do
|
4
4
|
|
5
|
+
describe "#deep_merge!" do
|
6
|
+
it "should recursively merge two Hashes" do
|
7
|
+
hash = { :one => 1, "two" => { "three" => 3 } }
|
8
|
+
other_hash = { :four => 4, "two" => { "three" => "merge", :five => 5 } }
|
9
|
+
|
10
|
+
hash.merge!(other_hash).should == { :one => 1, :four => 4, "two" => { "three" => "merge", :five => 5 } }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
describe "find_soap_body" do
|
6
15
|
it "should return the content from the 'soap:Body' element" do
|
7
16
|
soap_body = { "soap:Envelope" => { "soap:Body" => "content" } }
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Time do
|
4
|
+
|
5
|
+
describe "#xs_datetime" do
|
6
|
+
let(:time) { Time.utc(2011, 01, 04, 13, 45, 55) }
|
7
|
+
|
8
|
+
it "should return an xs:dateTime formatted String" do
|
9
|
+
time.xs_datetime.should == "2011-01-04T13:45:55UTC"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/spec/savon/soap_spec.rb
CHANGED
@@ -13,17 +13,9 @@ describe Savon::SOAP do
|
|
13
13
|
Savon::SOAP::Versions.should == (1..2)
|
14
14
|
end
|
15
15
|
|
16
|
-
it "should contain the xs:dateTime format" do
|
17
|
-
Savon::SOAP::DateTimeFormat.should be_a(String)
|
18
|
-
Savon::SOAP::DateTimeFormat.should_not be_empty
|
19
|
-
|
20
|
-
DateTime.new(2012, 03, 22, 16, 22, 33).strftime(Savon::SOAP::DateTimeFormat).
|
21
|
-
should == "2012-03-22T16:22:33+00:00"
|
22
|
-
end
|
23
|
-
|
24
16
|
it "should contain a Regexp matching the xs:dateTime format" do
|
25
17
|
Savon::SOAP::DateTimeRegexp.should be_a(Regexp)
|
26
18
|
(Savon::SOAP::DateTimeRegexp === "2012-03-22T16:22:33").should be_true
|
27
19
|
end
|
28
|
-
|
20
|
+
|
29
21
|
end
|
data/spec/savon/wsse_spec.rb
CHANGED
@@ -158,6 +158,56 @@ describe Savon::WSSE do
|
|
158
158
|
wsse.to_xml.should include(Savon::WSSE::PasswordDigestURI)
|
159
159
|
end
|
160
160
|
end
|
161
|
+
|
162
|
+
context "with #timestamp set to true" do
|
163
|
+
before { wsse.timestamp = true }
|
164
|
+
|
165
|
+
it "should contain a wsse:Timestamp node" do
|
166
|
+
wsse.to_xml.should include('<wsse:Timestamp wsu:Id="Timestamp-1" ' +
|
167
|
+
'xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">')
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should contain a wsu:Created node defaulting to Time.now" do
|
171
|
+
created_at = Time.now
|
172
|
+
Timecop.freeze created_at do
|
173
|
+
wsse.to_xml.should include("<wsu:Created>#{created_at.xs_datetime}</wsu:Created>")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should contain a wsu:Expires node defaulting to Time.now + 60 seconds" do
|
178
|
+
created_at = Time.now
|
179
|
+
Timecop.freeze created_at do
|
180
|
+
wsse.to_xml.should include("<wsu:Expires>#{(created_at + 60).xs_datetime}</wsu:Expires>")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context "with #created_at" do
|
186
|
+
before { wsse.created_at = Time.now + 86400 }
|
187
|
+
|
188
|
+
it "should contain a wsu:Created node with the given time" do
|
189
|
+
wsse.to_xml.should include("<wsu:Created>#{wsse.created_at.xs_datetime}</wsu:Created>")
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should contain a wsu:Expires node set to #created_at + 60 seconds" do
|
193
|
+
wsse.to_xml.should include("<wsu:Expires>#{(wsse.created_at + 60).xs_datetime}</wsu:Expires>")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "with #expires_at" do
|
198
|
+
before { wsse.expires_at = Time.now + 86400 }
|
199
|
+
|
200
|
+
it "should contain a wsu:Created node defaulting to Time.now" do
|
201
|
+
created_at = Time.now
|
202
|
+
Timecop.freeze created_at do
|
203
|
+
wsse.to_xml.should include("<wsu:Created>#{created_at.xs_datetime}</wsu:Created>")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should contain a wsu:Expires node set to the given time" do
|
208
|
+
wsse.to_xml.should include("<wsu:Expires>#{wsse.expires_at.xs_datetime}</wsu:Expires>")
|
209
|
+
end
|
210
|
+
end
|
161
211
|
end
|
162
212
|
|
163
213
|
end
|
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:
|
5
|
-
prerelease:
|
4
|
+
hash: 59
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 2
|
10
|
+
version: 0.8.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Daniel Harrington
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-04 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -128,6 +128,22 @@ dependencies:
|
|
128
128
|
version: 0.9.7
|
129
129
|
type: :development
|
130
130
|
version_requirements: *id007
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: timecop
|
133
|
+
prerelease: false
|
134
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ~>
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
hash: 25
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
- 3
|
143
|
+
- 5
|
144
|
+
version: 0.3.5
|
145
|
+
type: :development
|
146
|
+
version_requirements: *id008
|
131
147
|
description: Savon is the heavy metal Ruby SOAP client.
|
132
148
|
email: me@rubiii.com
|
133
149
|
executables: []
|
@@ -151,6 +167,7 @@ files:
|
|
151
167
|
- lib/savon/core_ext/hash.rb
|
152
168
|
- lib/savon/core_ext/object.rb
|
153
169
|
- lib/savon/core_ext/string.rb
|
170
|
+
- lib/savon/core_ext/time.rb
|
154
171
|
- lib/savon/error.rb
|
155
172
|
- lib/savon/global.rb
|
156
173
|
- lib/savon/http/error.rb
|
@@ -180,6 +197,7 @@ files:
|
|
180
197
|
- spec/savon/core_ext/hash_spec.rb
|
181
198
|
- spec/savon/core_ext/object_spec.rb
|
182
199
|
- spec/savon/core_ext/string_spec.rb
|
200
|
+
- spec/savon/core_ext/time_spec.rb
|
183
201
|
- spec/savon/http/error_spec.rb
|
184
202
|
- spec/savon/savon_spec.rb
|
185
203
|
- spec/savon/soap/fault_spec.rb
|
@@ -224,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
242
|
requirements: []
|
225
243
|
|
226
244
|
rubyforge_project: savon
|
227
|
-
rubygems_version: 1.
|
245
|
+
rubygems_version: 1.4.1
|
228
246
|
signing_key:
|
229
247
|
specification_version: 3
|
230
248
|
summary: Heavy metal Ruby SOAP client
|