signer 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +6 -1
- data/lib/signer.rb +32 -5
- data/lib/signer/version.rb +1 -1
- data/spec/fixtures/output_2_with_ds_prefix.xml +31 -0
- data/spec/signer_spec.rb +22 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a37c55f9fdbf134383fd475503fbd47cee739f42
|
4
|
+
data.tar.gz: 60999a93aa7427c4a132c75985a915f7d18a2995
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47fdf2988627bbf355ac5ab6a1ffe80bbe660d7bd6315ec65c3ed96978191653d1f3919270b960685364487910f846970e21f00738c456affea72b6d31695378
|
7
|
+
data.tar.gz: 00e6ba00e46ab22ef6a9029d0cc1f28b00c04a8b90cfd2a512a84b2d444bea9b627806d5059efd74f7f66312e8b0465adeb66716abb5733941268ab83b87dfb7
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -229,9 +229,14 @@ signer.sign! # No need to pass a :security_token option, as we already construct
|
|
229
229
|
|
230
230
|
If you need to use canonicalization with inclusive namespaces you can pass array of namespace prefixes in `:inclusive_namespaces` option in both `digest!` and `sign!` methods.
|
231
231
|
|
232
|
+
If you need `Signature` tags to be in explicit namespace (say, `<ds:Signature>`) instead of to be in implicit default namespace you can specify next option:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
signer.ds_namespace_prefix = 'ds'
|
236
|
+
```
|
232
237
|
|
233
238
|
Every new instance of signer has Nokogiri `noblanks` set as default in process of parsing xml file. If you need to disable it, pass opional argument `noblanks: false`.
|
234
239
|
|
235
|
-
```
|
240
|
+
```ruby
|
236
241
|
Signer.new(File.read("example.xml"), noblanks: false)
|
237
242
|
```
|
data/lib/signer.rb
CHANGED
@@ -7,12 +7,13 @@ require "signer/digester"
|
|
7
7
|
require "signer/version"
|
8
8
|
|
9
9
|
class Signer
|
10
|
-
attr_accessor :document, :private_key, :signature_algorithm_id
|
10
|
+
attr_accessor :document, :private_key, :signature_algorithm_id, :ds_namespace_prefix
|
11
11
|
attr_reader :cert
|
12
12
|
attr_writer :security_node, :signature_node, :security_token_id
|
13
13
|
|
14
14
|
WSU_NAMESPACE = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
|
15
15
|
WSSE_NAMESPACE = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
|
16
|
+
DS_NAMESPACE = 'http://www.w3.org/2000/09/xmldsig#'
|
16
17
|
|
17
18
|
def initialize(document, noblanks: true)
|
18
19
|
self.document = Nokogiri::XML(document.to_s) do |config|
|
@@ -81,10 +82,10 @@ class Signer
|
|
81
82
|
# <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
82
83
|
def signature_node
|
83
84
|
@signature_node ||= begin
|
84
|
-
@signature_node = security_node.at_xpath('ds:Signature', ds:
|
85
|
+
@signature_node = security_node.at_xpath('ds:Signature', ds: DS_NAMESPACE)
|
85
86
|
unless @signature_node
|
86
87
|
@signature_node = Nokogiri::XML::Node.new('Signature', document)
|
87
|
-
@signature_node
|
88
|
+
set_namespace_for_node(@signature_node, DS_NAMESPACE, ds_namespace_prefix)
|
88
89
|
security_node.add_child(@signature_node)
|
89
90
|
end
|
90
91
|
@signature_node
|
@@ -97,16 +98,19 @@ class Signer
|
|
97
98
|
# ...
|
98
99
|
# </SignedInfo>
|
99
100
|
def signed_info_node
|
100
|
-
node = signature_node.at_xpath('ds:SignedInfo', ds:
|
101
|
+
node = signature_node.at_xpath('ds:SignedInfo', ds: DS_NAMESPACE)
|
101
102
|
unless node
|
102
103
|
node = Nokogiri::XML::Node.new('SignedInfo', document)
|
103
104
|
signature_node.add_child(node)
|
105
|
+
set_namespace_for_node(node, DS_NAMESPACE, ds_namespace_prefix)
|
104
106
|
canonicalization_method_node = Nokogiri::XML::Node.new('CanonicalizationMethod', document)
|
105
107
|
canonicalization_method_node['Algorithm'] = 'http://www.w3.org/2001/10/xml-exc-c14n#'
|
106
108
|
node.add_child(canonicalization_method_node)
|
109
|
+
set_namespace_for_node(canonicalization_method_node, DS_NAMESPACE, ds_namespace_prefix)
|
107
110
|
signature_method_node = Nokogiri::XML::Node.new('SignatureMethod', document)
|
108
111
|
signature_method_node['Algorithm'] = self.signature_algorithm_id
|
109
112
|
node.add_child(signature_method_node)
|
113
|
+
set_namespace_for_node(signature_method_node, DS_NAMESPACE, ds_namespace_prefix)
|
110
114
|
end
|
111
115
|
node
|
112
116
|
end
|
@@ -136,6 +140,7 @@ class Signer
|
|
136
140
|
key_info_node = Nokogiri::XML::Node.new('KeyInfo', document)
|
137
141
|
security_token_reference_node = Nokogiri::XML::Node.new("#{wsse_ns}:SecurityTokenReference", document)
|
138
142
|
key_info_node.add_child(security_token_reference_node)
|
143
|
+
set_namespace_for_node(key_info_node, DS_NAMESPACE, ds_namespace_prefix)
|
139
144
|
reference_node = Nokogiri::XML::Node.new("#{wsse_ns}:Reference", document)
|
140
145
|
reference_node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'
|
141
146
|
reference_node['URI'] = "##{security_token_id}"
|
@@ -177,6 +182,13 @@ class Signer
|
|
177
182
|
|
178
183
|
signed_info_node.add_next_sibling(key_info_node)
|
179
184
|
|
185
|
+
set_namespace_for_node(key_info_node, DS_NAMESPACE, ds_namespace_prefix)
|
186
|
+
set_namespace_for_node(data_node, DS_NAMESPACE, ds_namespace_prefix)
|
187
|
+
set_namespace_for_node(issuer_serial_node, DS_NAMESPACE, ds_namespace_prefix)
|
188
|
+
set_namespace_for_node(cetificate_node, DS_NAMESPACE, ds_namespace_prefix)
|
189
|
+
set_namespace_for_node(issuer_name_node, DS_NAMESPACE, ds_namespace_prefix)
|
190
|
+
set_namespace_for_node(issuer_number_node, DS_NAMESPACE, ds_namespace_prefix)
|
191
|
+
|
180
192
|
data_node
|
181
193
|
end
|
182
194
|
|
@@ -215,11 +227,14 @@ class Signer
|
|
215
227
|
reference_node = Nokogiri::XML::Node.new('Reference', document)
|
216
228
|
reference_node['URI'] = id.to_s.size > 0 ? "##{id}" : ""
|
217
229
|
signed_info_node.add_child(reference_node)
|
230
|
+
set_namespace_for_node(reference_node, DS_NAMESPACE, ds_namespace_prefix)
|
218
231
|
|
219
232
|
transforms_node = Nokogiri::XML::Node.new('Transforms', document)
|
220
233
|
reference_node.add_child(transforms_node)
|
234
|
+
set_namespace_for_node(transforms_node, DS_NAMESPACE, ds_namespace_prefix)
|
221
235
|
|
222
236
|
transform_node = Nokogiri::XML::Node.new('Transform', document)
|
237
|
+
set_namespace_for_node(transform_node, DS_NAMESPACE, ds_namespace_prefix)
|
223
238
|
if options[:enveloped]
|
224
239
|
transform_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
|
225
240
|
else
|
@@ -236,10 +251,12 @@ class Signer
|
|
236
251
|
digest_method_node = Nokogiri::XML::Node.new('DigestMethod', document)
|
237
252
|
digest_method_node['Algorithm'] = @digester.digest_id
|
238
253
|
reference_node.add_child(digest_method_node)
|
254
|
+
set_namespace_for_node(digest_method_node, DS_NAMESPACE, ds_namespace_prefix)
|
239
255
|
|
240
256
|
digest_value_node = Nokogiri::XML::Node.new('DigestValue', document)
|
241
257
|
digest_value_node.content = target_digest
|
242
258
|
reference_node.add_child(digest_value_node)
|
259
|
+
set_namespace_for_node(digest_value_node, DS_NAMESPACE, ds_namespace_prefix)
|
243
260
|
self
|
244
261
|
end
|
245
262
|
|
@@ -263,7 +280,7 @@ class Signer
|
|
263
280
|
end
|
264
281
|
|
265
282
|
if options[:inclusive_namespaces]
|
266
|
-
c14n_method_node = signed_info_node.at_xpath('ds:CanonicalizationMethod', ds:
|
283
|
+
c14n_method_node = signed_info_node.at_xpath('ds:CanonicalizationMethod', ds: DS_NAMESPACE)
|
267
284
|
inclusive_namespaces_node = Nokogiri::XML::Node.new('ec:InclusiveNamespaces', document)
|
268
285
|
inclusive_namespaces_node.add_namespace_definition('ec', c14n_method_node['Algorithm'])
|
269
286
|
inclusive_namespaces_node['PrefixList'] = options[:inclusive_namespaces].join(' ')
|
@@ -278,6 +295,7 @@ class Signer
|
|
278
295
|
signature_value_node = Nokogiri::XML::Node.new('SignatureValue', document)
|
279
296
|
signature_value_node.content = signature_value_digest
|
280
297
|
signed_info_node.add_next_sibling(signature_value_node)
|
298
|
+
set_namespace_for_node(signature_value_node, DS_NAMESPACE, ds_namespace_prefix)
|
281
299
|
self
|
282
300
|
end
|
283
301
|
|
@@ -306,4 +324,13 @@ class Signer
|
|
306
324
|
end
|
307
325
|
end
|
308
326
|
|
327
|
+
##
|
328
|
+
# Searches for namespace with given +href+ within +node+ ancestors and assigns it to this node.
|
329
|
+
# If there is no such namespace, it will create it with +desired_prefix+ if present or as default namespace otherwise.
|
330
|
+
# In most cases you should insert +node+ in the document tree before calling this method to avoid duplicating namespace definitions
|
331
|
+
def set_namespace_for_node(node, href, desired_prefix = nil)
|
332
|
+
return node.namespace if node.namespace && node.namespace.href == href # This node already in target namespace, done
|
333
|
+
namespace = node.namespace_scopes.find { |ns| ns.href == href }
|
334
|
+
node.namespace = namespace || node.add_namespace_definition(desired_prefix, href)
|
335
|
+
end
|
309
336
|
end
|
data/lib/signer/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<ApplicationRequest xmlns="http://bxd.fi/xmldata/">
|
3
|
+
<CustomerId>679155330</CustomerId>
|
4
|
+
<Command>GetUserInfo</Command>
|
5
|
+
<Timestamp>2010-05-10T13:22:19.847+03:00</Timestamp>
|
6
|
+
<Environment>PRODUCTION</Environment>
|
7
|
+
<SoftwareId>Petri</SoftwareId>
|
8
|
+
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
9
|
+
<ds:SignedInfo>
|
10
|
+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
11
|
+
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
12
|
+
<ds:Reference URI="">
|
13
|
+
<ds:Transforms>
|
14
|
+
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
15
|
+
</ds:Transforms>
|
16
|
+
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
17
|
+
<ds:DigestValue>U9tsT4lrRMp8ZdKMnblgeMCGfvI=</ds:DigestValue>
|
18
|
+
</ds:Reference>
|
19
|
+
</ds:SignedInfo>
|
20
|
+
<ds:SignatureValue>rOCe8McbIFa4Ul3pnzd/dBjFWoT4JtSghJgzZGLrz17K/j0W1JyaopcZeMD+8M5/GplAlQrJg3ZSkQvY9Sf7WpqZeLYHW17J0ZJpwas+/OOXUEdyUiec7q9OgWsFLH9DBNuJdLKE3CO6w/8tTKQ/kidYnPBXT6FKioNlSJVZsuI=</ds:SignatureValue>
|
21
|
+
<ds:KeyInfo>
|
22
|
+
<ds:X509Data>
|
23
|
+
<ds:X509IssuerSerial>
|
24
|
+
<ds:X509IssuerName>C=AU,ST=Some-State,O=Internet Widgits Pty Ltd</ds:X509IssuerName>
|
25
|
+
<ds:X509SerialNumber>16503368396260674861</ds:X509SerialNumber>
|
26
|
+
</ds:X509IssuerSerial>
|
27
|
+
<ds:X509Certificate>MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuVwyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEbgDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0GA1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4oho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnNJJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpTBmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0jlyrGYJlLli1NxHiBz7FCEJaVI8=</ds:X509Certificate>
|
28
|
+
</ds:X509Data>
|
29
|
+
</ds:KeyInfo>
|
30
|
+
</ds:Signature>
|
31
|
+
</ApplicationRequest>
|
data/spec/signer_spec.rb
CHANGED
@@ -139,6 +139,28 @@ describe Signer do
|
|
139
139
|
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
|
140
140
|
end
|
141
141
|
|
142
|
+
it "should sign simple XML with custom DS namespace prefix" do
|
143
|
+
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input_2.xml')
|
144
|
+
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
|
145
|
+
private_key_file = File.join(File.dirname(__FILE__), 'fixtures', 'key.pem')
|
146
|
+
|
147
|
+
signer = Signer.new(File.read(input_xml_file))
|
148
|
+
signer.cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
|
149
|
+
signer.private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file), "test")
|
150
|
+
signer.security_node = signer.document.root
|
151
|
+
signer.security_token_id = ""
|
152
|
+
signer.ds_namespace_prefix = 'ds'
|
153
|
+
signer.digest!(signer.document.root, :id => "", :enveloped => true)
|
154
|
+
signer.sign!(:issuer_serial => true)
|
155
|
+
|
156
|
+
# File.open(File.join(File.dirname(__FILE__), 'fixtures', 'output_2_with_ds_prefix.xml'), "w") do |f|
|
157
|
+
# f.write signer.document.to_s
|
158
|
+
# end
|
159
|
+
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'output_2_with_ds_prefix.xml')
|
160
|
+
|
161
|
+
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
|
162
|
+
end
|
163
|
+
|
142
164
|
it "should digest and sign SOAP XML with security node and digested binary token with noblanks diabled" do
|
143
165
|
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input_4_with_nested_signatures.xml')
|
144
166
|
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: signer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edgars Beigarts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- spec/fixtures/output_1_inclusive_namespaces.xml
|
76
76
|
- spec/fixtures/output_1_sha256.xml
|
77
77
|
- spec/fixtures/output_2.xml
|
78
|
+
- spec/fixtures/output_2_with_ds_prefix.xml
|
78
79
|
- spec/fixtures/output_3_c14n_comments.xml
|
79
80
|
- spec/fixtures/output_4_with_nested_signatures.xml
|
80
81
|
- spec/fixtures/output_4_with_nested_signatures_with_noblanks_disabled.xml
|
@@ -99,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
100
|
version: '0'
|
100
101
|
requirements: []
|
101
102
|
rubyforge_project:
|
102
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.6.8
|
103
104
|
signing_key:
|
104
105
|
specification_version: 4
|
105
106
|
summary: WS Security XML signer
|
@@ -114,6 +115,7 @@ test_files:
|
|
114
115
|
- spec/fixtures/output_1_inclusive_namespaces.xml
|
115
116
|
- spec/fixtures/output_1_sha256.xml
|
116
117
|
- spec/fixtures/output_2.xml
|
118
|
+
- spec/fixtures/output_2_with_ds_prefix.xml
|
117
119
|
- spec/fixtures/output_3_c14n_comments.xml
|
118
120
|
- spec/fixtures/output_4_with_nested_signatures.xml
|
119
121
|
- spec/fixtures/output_4_with_nested_signatures_with_noblanks_disabled.xml
|