signer 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.md +201 -0
- data/lib/signer.rb +138 -0
- data/lib/signer/version.rb +3 -0
- data/spec/fixtures/cert.pem +17 -0
- data/spec/fixtures/input.xml +24 -0
- data/spec/fixtures/key.pem +18 -0
- data/spec/fixtures/output.xml +51 -0
- data/spec/signer_spec.rb +30 -0
- data/spec/spec_helper.rb +5 -0
- metadata +110 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Edgars Beigarts
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
# Signer
|
2
|
+
|
3
|
+
[![Continuous Integration status](https://secure.travis-ci.org/ebeigarts/signer.png)](http://travis-ci.org/ebeigarts/signer)
|
4
|
+
|
5
|
+
WS Security XML Certificate signing for Ruby
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```bash
|
10
|
+
gem install signer
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require "signer"
|
17
|
+
|
18
|
+
signer = Signer.new(File.read("example.xml"))
|
19
|
+
signer.cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
|
20
|
+
signer.private_key = OpenSSL::PKey::RSA.new(File.read("key.pem"), "password")
|
21
|
+
|
22
|
+
signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
|
23
|
+
signer.digest!(node)
|
24
|
+
end
|
25
|
+
|
26
|
+
signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
|
27
|
+
signer.digest!(node)
|
28
|
+
end
|
29
|
+
|
30
|
+
signer.sign!
|
31
|
+
|
32
|
+
signer.to_xml
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage with Savon
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
client = Savon::Client.new do |wsdl, http|
|
39
|
+
wsdl.document = "..."
|
40
|
+
wsdl.endpoint = "..."
|
41
|
+
end
|
42
|
+
|
43
|
+
response = client.request(:search_documents) do
|
44
|
+
soap.version = 2
|
45
|
+
soap.xml do
|
46
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
47
|
+
xml.send("s:Envelope",
|
48
|
+
"xmlns:s" => "http://www.w3.org/2003/05/soap-envelope",
|
49
|
+
"xmlns:a" => "http://www.w3.org/2005/08/addressing",
|
50
|
+
"xmlns:u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
51
|
+
) do
|
52
|
+
xml.send("s:Header") do
|
53
|
+
xml.send("a:Action", "s:mustUnderstand" => "1") do
|
54
|
+
xml.text "http://tempuri.org/IDocumentService/SearchDocuments"
|
55
|
+
end
|
56
|
+
xml.send("a:MessageID") do
|
57
|
+
xml.text "urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b"
|
58
|
+
end
|
59
|
+
xml.send("a:ReplyTo") do
|
60
|
+
xml.send("a:Address") do
|
61
|
+
xml.text "http://www.w3.org/2005/08/addressing/anonymous"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
xml.send("a:To", "a:mustUnderstand" => "1") do
|
65
|
+
xml.text "..."
|
66
|
+
end
|
67
|
+
xml.send("o:Security",
|
68
|
+
"xmlns:o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
|
69
|
+
"s:mustUnderstand" => "1"
|
70
|
+
) do
|
71
|
+
xml.send("u:Timestamp") do
|
72
|
+
time = Time.now.utc
|
73
|
+
xml.send("u:Created") do
|
74
|
+
xml.text(time.xmlschema)
|
75
|
+
end
|
76
|
+
xml.send("u:Expires") do
|
77
|
+
xml.text((time + 5.minutes).xmlschema)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
xml.send("s:Body") do
|
83
|
+
xml.send("SearchDocuments", "xmlns" => "http://tempuri.org/") do
|
84
|
+
xml.send("searchCriteria",
|
85
|
+
"xmlns:b" => "http://schemas.datacontract.org/2004/07/ZMDVS.BusinessLogic.Data.Documents.Integration",
|
86
|
+
"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
|
87
|
+
) do
|
88
|
+
xml.send("b:RegistrationNo") do
|
89
|
+
xml.text "1"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
signer = Signer.new(builder.to_xml)
|
98
|
+
signer.cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
|
99
|
+
signer.private_key = OpenSSL::PKey::RSA.new(File.read("key.pem"), "test")
|
100
|
+
|
101
|
+
signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
|
102
|
+
signer.digest!(node)
|
103
|
+
end
|
104
|
+
|
105
|
+
signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
|
106
|
+
signer.digest!(node)
|
107
|
+
end
|
108
|
+
|
109
|
+
signer.sign!
|
110
|
+
|
111
|
+
signer.to_xml
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
## Example
|
117
|
+
|
118
|
+
Input:
|
119
|
+
|
120
|
+
```xml
|
121
|
+
<?xml version="1.0"?>
|
122
|
+
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
123
|
+
<s:Header>
|
124
|
+
<a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
|
125
|
+
<a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
|
126
|
+
<a:ReplyTo>
|
127
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
128
|
+
</a:ReplyTo>
|
129
|
+
<To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
|
130
|
+
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
|
131
|
+
<u:Timestamp>
|
132
|
+
<u:Created>2012-05-02T18:17:14.467Z</u:Created>
|
133
|
+
<u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
|
134
|
+
</u:Timestamp>
|
135
|
+
</o:Security>
|
136
|
+
</s:Header>
|
137
|
+
<s:Body>
|
138
|
+
<SearchDocuments xmlns="http://tempuri.org/">
|
139
|
+
<searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
140
|
+
<b:RegistrationNo>1</b:RegistrationNo>
|
141
|
+
</searchCriteria>
|
142
|
+
</SearchDocuments>
|
143
|
+
</s:Body>
|
144
|
+
</s:Envelope>
|
145
|
+
```
|
146
|
+
|
147
|
+
Output:
|
148
|
+
|
149
|
+
```xml
|
150
|
+
<?xml version="1.0"?>
|
151
|
+
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
152
|
+
<s:Header>
|
153
|
+
<a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
|
154
|
+
<a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
|
155
|
+
<a:ReplyTo>
|
156
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
157
|
+
</a:ReplyTo>
|
158
|
+
<To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1" u:Id="_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
|
159
|
+
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
|
160
|
+
<u:Timestamp u:Id="_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
|
161
|
+
<u:Created>2012-05-02T18:17:14.467Z</u:Created>
|
162
|
+
<u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
|
163
|
+
</u:Timestamp>
|
164
|
+
<o:BinarySecurityToken u:Id="uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuVwyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEbgDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0GA1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4oho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnNJJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpTBmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0jlyrGYJlLli1NxHiBz7FCEJaVI8=</o:BinarySecurityToken>
|
165
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
166
|
+
<SignedInfo>
|
167
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
168
|
+
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
169
|
+
<Reference URI="#_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
|
170
|
+
<Transforms>
|
171
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
172
|
+
</Transforms>
|
173
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
174
|
+
<DigestValue>Oz29YgZk14+nchoqv9zGzhJcDUo=</DigestValue>
|
175
|
+
</Reference>
|
176
|
+
<Reference URI="#_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">
|
177
|
+
<Transforms>
|
178
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
179
|
+
</Transforms>
|
180
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
181
|
+
<DigestValue>leV/RNYhwuCuD7/DBzn3IgQzUxI=</DigestValue>
|
182
|
+
</Reference>
|
183
|
+
</SignedInfo>
|
184
|
+
<SignatureValue>en7YYAIn90ofH08aF917jNngMuse+vK6bihF0v6UsXFnGGMOflWfRTZ6mFmC2HwLmb2lSrhZ3eth3cs2fCBlEr/K2ZDMQfJo6CPxmbzfX/fxR/isCTDz+HIJd13J0HK4n+CzkndwplkCmT8SQlduUruUFUUmlQiiZQ7nryR+XyM=</SignatureValue>
|
185
|
+
<KeyInfo>
|
186
|
+
<o:SecurityTokenReference>
|
187
|
+
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"/>
|
188
|
+
</o:SecurityTokenReference>
|
189
|
+
</KeyInfo>
|
190
|
+
</Signature>
|
191
|
+
</o:Security>
|
192
|
+
</s:Header>
|
193
|
+
<s:Body>
|
194
|
+
<SearchDocuments xmlns="http://tempuri.org/">
|
195
|
+
<searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
196
|
+
<b:RegistrationNo>1</b:RegistrationNo>
|
197
|
+
</searchCriteria>
|
198
|
+
</SearchDocuments>
|
199
|
+
</s:Body>
|
200
|
+
</s:Envelope>
|
201
|
+
```
|
data/lib/signer.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "base64"
|
3
|
+
require "digest/sha1"
|
4
|
+
require "openssl"
|
5
|
+
|
6
|
+
require "signer/version"
|
7
|
+
|
8
|
+
class Signer
|
9
|
+
attr_accessor :document, :cert, :private_key
|
10
|
+
|
11
|
+
def initialize(document)
|
12
|
+
self.document = Nokogiri::XML(document.to_s, &:noblanks)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
document.to_xml(:save_with => 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def security_token_id
|
20
|
+
"uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"
|
21
|
+
end
|
22
|
+
|
23
|
+
def security_node
|
24
|
+
document.xpath("//o:Security", "o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").first
|
25
|
+
end
|
26
|
+
|
27
|
+
# <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
28
|
+
def signature_node
|
29
|
+
node = document.xpath("//ds:Signature", "ds" => "http://www.w3.org/2000/09/xmldsig#").first
|
30
|
+
unless node
|
31
|
+
node = Nokogiri::XML::Node.new('Signature', document)
|
32
|
+
node.default_namespace = 'http://www.w3.org/2000/09/xmldsig#'
|
33
|
+
security_node.add_child(node)
|
34
|
+
end
|
35
|
+
node
|
36
|
+
end
|
37
|
+
|
38
|
+
# <SignedInfo>
|
39
|
+
# <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
40
|
+
# <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
41
|
+
# ...
|
42
|
+
# </SignedInfo>
|
43
|
+
def signed_info_node
|
44
|
+
node = signature_node.xpath("//ds:SignedInfo", "ds" => 'http://www.w3.org/2000/09/xmldsig#').first
|
45
|
+
unless node
|
46
|
+
node = Nokogiri::XML::Node.new('SignedInfo', document)
|
47
|
+
signature_node.add_child(node)
|
48
|
+
canonicalization_method_node = Nokogiri::XML::Node.new('CanonicalizationMethod', document)
|
49
|
+
canonicalization_method_node['Algorithm'] = 'http://www.w3.org/2001/10/xml-exc-c14n#'
|
50
|
+
node.add_child(canonicalization_method_node)
|
51
|
+
signature_method_node = Nokogiri::XML::Node.new('SignatureMethod', document)
|
52
|
+
signature_method_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
|
53
|
+
node.add_child(signature_method_node)
|
54
|
+
end
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
# <o:BinarySecurityToken u:Id="" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
|
59
|
+
# ...
|
60
|
+
# </o:BinarySecurityToken>
|
61
|
+
# <SignedInfo>
|
62
|
+
# ...
|
63
|
+
# </SignedInfo>
|
64
|
+
# <KeyInfo>
|
65
|
+
# <o:SecurityTokenReference>
|
66
|
+
# <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"/>
|
67
|
+
# </o:SecurityTokenReference>
|
68
|
+
# </KeyInfo>
|
69
|
+
def binary_security_token_node
|
70
|
+
node = document.xpath("//o:BinarySecurityToken", "o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").first
|
71
|
+
unless node
|
72
|
+
node = Nokogiri::XML::Node.new('BinarySecurityToken', document)
|
73
|
+
node['u:Id'] = security_token_id
|
74
|
+
node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'
|
75
|
+
node['EncodingType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'
|
76
|
+
node.content = Base64.encode64(cert.to_der).gsub("\n", '')
|
77
|
+
security_node.add_child(node)
|
78
|
+
key_info_node = Nokogiri::XML::Node.new('KeyInfo', document)
|
79
|
+
security_token_reference_node = Nokogiri::XML::Node.new('o:SecurityTokenReference', document)
|
80
|
+
key_info_node.add_child(security_token_reference_node)
|
81
|
+
reference_node = Nokogiri::XML::Node.new('o:Reference', document)
|
82
|
+
reference_node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'
|
83
|
+
reference_node['URI'] = "##{security_token_id}"
|
84
|
+
security_token_reference_node.add_child(reference_node)
|
85
|
+
signed_info_node.add_next_sibling(key_info_node)
|
86
|
+
end
|
87
|
+
node
|
88
|
+
end
|
89
|
+
|
90
|
+
# <Reference URI="#_0">
|
91
|
+
# <Transforms>
|
92
|
+
# <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
93
|
+
# </Transforms>
|
94
|
+
# <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
95
|
+
# <DigestValue>aeqXriJuUCk4tPNPAGDXGqHj6ao=</DigestValue>
|
96
|
+
# </Reference>
|
97
|
+
def digest!(target_node)
|
98
|
+
binary_security_token_node
|
99
|
+
|
100
|
+
id = "_#{Digest::SHA1.hexdigest(target_node.to_s)}"
|
101
|
+
target_node['u:Id'] = id
|
102
|
+
|
103
|
+
reference_node = Nokogiri::XML::Node.new('Reference', document)
|
104
|
+
reference_node['URI'] = "##{id}"
|
105
|
+
signed_info_node.add_child(reference_node)
|
106
|
+
|
107
|
+
transforms_node = Nokogiri::XML::Node.new('Transforms', document)
|
108
|
+
reference_node.add_child(transforms_node)
|
109
|
+
|
110
|
+
transform_node = Nokogiri::XML::Node.new('Transform', document)
|
111
|
+
transform_node['Algorithm'] = 'http://www.w3.org/2001/10/xml-exc-c14n#'
|
112
|
+
transforms_node.add_child(transform_node)
|
113
|
+
|
114
|
+
digest_method_node = Nokogiri::XML::Node.new('DigestMethod', document)
|
115
|
+
digest_method_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#sha1'
|
116
|
+
reference_node.add_child(digest_method_node)
|
117
|
+
|
118
|
+
digest_value_node = Nokogiri::XML::Node.new('DigestValue', document)
|
119
|
+
target_canon = target_node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
|
120
|
+
target_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(target_canon)).strip
|
121
|
+
digest_value_node.content = target_digest
|
122
|
+
reference_node.add_child(digest_value_node)
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
# <SignatureValue>...</SignatureValue>
|
127
|
+
def sign!
|
128
|
+
signed_info_canon = signed_info_node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
|
129
|
+
|
130
|
+
signature = private_key.sign(OpenSSL::Digest::SHA1.new, signed_info_canon)
|
131
|
+
signature_value_digest = Base64.encode64(signature).gsub("\n", '')
|
132
|
+
|
133
|
+
signature_value_node = Nokogiri::XML::Node.new('SignatureValue', document)
|
134
|
+
signature_value_node.content = signature_value_digest
|
135
|
+
signed_info_node.add_next_sibling(signature_value_node)
|
136
|
+
self
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
3
|
+
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
4
|
+
aWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBF
|
5
|
+
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
|
6
|
+
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
7
|
+
gQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuV
|
8
|
+
wyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEb
|
9
|
+
gDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0G
|
10
|
+
A1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8
|
11
|
+
Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
|
12
|
+
U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4o
|
13
|
+
ho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnN
|
14
|
+
JJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpT
|
15
|
+
BmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0
|
16
|
+
jlyrGYJlLli1NxHiBz7FCEJaVI8=
|
17
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
3
|
+
<s:Header>
|
4
|
+
<a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
|
5
|
+
<a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
|
6
|
+
<a:ReplyTo>
|
7
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
8
|
+
</a:ReplyTo>
|
9
|
+
<To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
|
10
|
+
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
|
11
|
+
<u:Timestamp>
|
12
|
+
<u:Created>2012-05-02T18:17:14.467Z</u:Created>
|
13
|
+
<u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
|
14
|
+
</u:Timestamp>
|
15
|
+
</o:Security>
|
16
|
+
</s:Header>
|
17
|
+
<s:Body>
|
18
|
+
<SearchDocuments xmlns="http://tempuri.org/">
|
19
|
+
<searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
20
|
+
<b:RegistrationNo>1</b:RegistrationNo>
|
21
|
+
</searchCriteria>
|
22
|
+
</SearchDocuments>
|
23
|
+
</s:Body>
|
24
|
+
</s:Envelope>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
Proc-Type: 4,ENCRYPTED
|
3
|
+
DEK-Info: DES-EDE3-CBC,D53BEDA3FEA82258
|
4
|
+
|
5
|
+
a9x4N5JZ6qwza28OAEBWyS4s4GysgbiJf11wX2e1Ol/rHt9/PGvZCK9PSyW/haRn
|
6
|
+
l5iT95n8Ohyr16Ngx/p02Jq3TEbs/Jsxz7+z55R5E3LvGKGZIB8Yh8dvI4ArzPsK
|
7
|
+
QiwoegJnSWdTQnfybbbpv+11RrKtb1/H0/i9fIHDJUhch9HwNn/yZGs9uYRxVBGe
|
8
|
+
OFLAdnCB+JG5Q5p24aWeYEWQLbYB69uc9kiV60qgfp4ZxRgdeU55eLZe48d9clG7
|
9
|
+
8vFAjM3+Q5WcgAgthKgD2HbjgcQ11WIZyHsshRvdWukk7iir7ogbOR/20sIWc+mY
|
10
|
+
hVdWfctYfWuheq7qwAfbvc8gSpgBRMziSI+5dFF4Ge80ahy7sxdlWJ4zNrqzTEIf
|
11
|
+
5CyN2cC6h8fbJ95bifJFUIKDi+rpkmFtnW4eh11BOL6vYlSFaL35Kw2teRmFCk6M
|
12
|
+
iBmIStavcfVj61ZClla3Xso5gl8Ei8EGBSuSSLT1Uq3WJ6eLh5JWkpV3+mir1HWO
|
13
|
+
vNIl6L4zm2kngwL73NFeG7ZFMTv2yAuif3Hpr3akZudp/+qDcIcnqnmY47HsOtOb
|
14
|
+
ArLwBalIu4zsKF5IzqGiZ6tbMgRHDbLw/HAuuYHlJF5TeMDqnQFGi09LpO6IHPBh
|
15
|
+
ZqVKuZ1LVLgCRpvkW12z0sxfByFHKK6RvgPgR9tPdVmCBJLwCbLa7AqNDVrJNe6q
|
16
|
+
OEwp95+7OTx1b7jVXiZ3wO0XpPWKAMXWAEGDd9YeNVdfXPgypSe4p/wJgtoCiPtz
|
17
|
+
Mm0NNYkrl2J/brj2jd5WRk6D2BWxf6pQKULzovTCX04pNxfLBBXBlQ==
|
18
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
3
|
+
<s:Header>
|
4
|
+
<a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
|
5
|
+
<a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
|
6
|
+
<a:ReplyTo>
|
7
|
+
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
|
8
|
+
</a:ReplyTo>
|
9
|
+
<To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1" u:Id="_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
|
10
|
+
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
|
11
|
+
<u:Timestamp u:Id="_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
|
12
|
+
<u:Created>2012-05-02T18:17:14.467Z</u:Created>
|
13
|
+
<u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
|
14
|
+
</u:Timestamp>
|
15
|
+
<o:BinarySecurityToken u:Id="uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuVwyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEbgDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0GA1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4oho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnNJJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpTBmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0jlyrGYJlLli1NxHiBz7FCEJaVI8=</o:BinarySecurityToken>
|
16
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
17
|
+
<SignedInfo>
|
18
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
19
|
+
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
20
|
+
<Reference URI="#_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
|
21
|
+
<Transforms>
|
22
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
23
|
+
</Transforms>
|
24
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
25
|
+
<DigestValue>Oz29YgZk14+nchoqv9zGzhJcDUo=</DigestValue>
|
26
|
+
</Reference>
|
27
|
+
<Reference URI="#_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">
|
28
|
+
<Transforms>
|
29
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
30
|
+
</Transforms>
|
31
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
32
|
+
<DigestValue>leV/RNYhwuCuD7/DBzn3IgQzUxI=</DigestValue>
|
33
|
+
</Reference>
|
34
|
+
</SignedInfo>
|
35
|
+
<SignatureValue>en7YYAIn90ofH08aF917jNngMuse+vK6bihF0v6UsXFnGGMOflWfRTZ6mFmC2HwLmb2lSrhZ3eth3cs2fCBlEr/K2ZDMQfJo6CPxmbzfX/fxR/isCTDz+HIJd13J0HK4n+CzkndwplkCmT8SQlduUruUFUUmlQiiZQ7nryR+XyM=</SignatureValue>
|
36
|
+
<KeyInfo>
|
37
|
+
<o:SecurityTokenReference>
|
38
|
+
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"/>
|
39
|
+
</o:SecurityTokenReference>
|
40
|
+
</KeyInfo>
|
41
|
+
</Signature>
|
42
|
+
</o:Security>
|
43
|
+
</s:Header>
|
44
|
+
<s:Body>
|
45
|
+
<SearchDocuments xmlns="http://tempuri.org/">
|
46
|
+
<searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
|
47
|
+
<b:RegistrationNo>1</b:RegistrationNo>
|
48
|
+
</searchCriteria>
|
49
|
+
</SearchDocuments>
|
50
|
+
</s:Body>
|
51
|
+
</s:Envelope>
|
data/spec/signer_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Signer do
|
4
|
+
it "should digest and sign the XML" do
|
5
|
+
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input.xml')
|
6
|
+
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
|
7
|
+
private_key_file = File.join(File.dirname(__FILE__), 'fixtures', 'key.pem')
|
8
|
+
|
9
|
+
signer = Signer.new(File.read(input_xml_file))
|
10
|
+
signer.cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
|
11
|
+
signer.private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file), "test")
|
12
|
+
|
13
|
+
signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
|
14
|
+
signer.digest!(node)
|
15
|
+
end
|
16
|
+
|
17
|
+
signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
|
18
|
+
signer.digest!(node)
|
19
|
+
end
|
20
|
+
|
21
|
+
signer.sign!
|
22
|
+
|
23
|
+
# File.open(File.join(File.dirname(__FILE__), 'fixtures', 'output.xml'), "w") do |f|
|
24
|
+
# f.write signer.document.to_s
|
25
|
+
# end
|
26
|
+
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'output.xml')
|
27
|
+
|
28
|
+
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
|
29
|
+
end
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: signer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Edgars Beigarts
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.5.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.5.1
|
62
|
+
description: WS Security XML signer
|
63
|
+
email:
|
64
|
+
- edgars.beigarts@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/signer/version.rb
|
70
|
+
- lib/signer.rb
|
71
|
+
- README.md
|
72
|
+
- LICENSE
|
73
|
+
- spec/fixtures/cert.pem
|
74
|
+
- spec/fixtures/input.xml
|
75
|
+
- spec/fixtures/key.pem
|
76
|
+
- spec/fixtures/output.xml
|
77
|
+
- spec/signer_spec.rb
|
78
|
+
- spec/spec_helper.rb
|
79
|
+
homepage: ''
|
80
|
+
licenses: []
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.8.21
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: WS Security XML signer
|
103
|
+
test_files:
|
104
|
+
- spec/fixtures/cert.pem
|
105
|
+
- spec/fixtures/input.xml
|
106
|
+
- spec/fixtures/key.pem
|
107
|
+
- spec/fixtures/output.xml
|
108
|
+
- spec/signer_spec.rb
|
109
|
+
- spec/spec_helper.rb
|
110
|
+
has_rdoc:
|