signer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -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
+ ```
@@ -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,3 @@
1
+ class Signer
2
+ VERSION = "1.0.0"
3
+ 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>
@@ -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
@@ -0,0 +1,5 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../lib'
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+ require "signer"
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: