signer 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/lib/signer.rb +59 -13
- data/lib/signer/version.rb +1 -1
- data/spec/fixtures/{input.xml → input_1.xml} +0 -0
- data/spec/fixtures/input_2.xml +7 -0
- data/spec/fixtures/{output.xml → output_1.xml} +0 -0
- data/spec/fixtures/output_2.xml +31 -0
- data/spec/signer_spec.rb +26 -5
- metadata +11 -8
data/README.md
CHANGED
data/lib/signer.rb
CHANGED
@@ -7,6 +7,7 @@ require "signer/version"
|
|
7
7
|
|
8
8
|
class Signer
|
9
9
|
attr_accessor :document, :cert, :private_key
|
10
|
+
attr_writer :security_node, :security_token_id
|
10
11
|
|
11
12
|
def initialize(document)
|
12
13
|
self.document = Nokogiri::XML(document.to_s, &:noblanks)
|
@@ -17,11 +18,15 @@ class Signer
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def security_token_id
|
20
|
-
"uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"
|
21
|
+
@security_token_id ||= "uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"
|
21
22
|
end
|
22
23
|
|
23
24
|
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
|
+
@security_node ||= document.xpath("//o:Security", "o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").first
|
26
|
+
end
|
27
|
+
|
28
|
+
def canonicalize(node = document)
|
29
|
+
node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
|
25
30
|
end
|
26
31
|
|
27
32
|
# <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
@@ -74,7 +79,7 @@ class Signer
|
|
74
79
|
node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'
|
75
80
|
node['EncodingType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'
|
76
81
|
node.content = Base64.encode64(cert.to_der).gsub("\n", '')
|
77
|
-
|
82
|
+
signature_node.add_previous_sibling(node)
|
78
83
|
key_info_node = Nokogiri::XML::Node.new('KeyInfo', document)
|
79
84
|
security_token_reference_node = Nokogiri::XML::Node.new('o:SecurityTokenReference', document)
|
80
85
|
key_info_node.add_child(security_token_reference_node)
|
@@ -87,6 +92,41 @@ class Signer
|
|
87
92
|
node
|
88
93
|
end
|
89
94
|
|
95
|
+
# <KeyInfo>
|
96
|
+
# <X509Data>
|
97
|
+
# <X509IssuerSerial>
|
98
|
+
# <X509IssuerName>System.Security.Cryptography.X509Certificates.X500DistinguishedName</X509IssuerName>
|
99
|
+
# <X509SerialNumber>13070789</X509SerialNumber>
|
100
|
+
# </X509IssuerSerial>
|
101
|
+
# <X509Certificate>MIID+jCCAuKgAwIBAgIEAMdxxTANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJTRTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMScwJQYDVQQDEx5Ob3JkZWEgcm9sZS1jZXJ0aWZpY2F0ZXMgQ0EgMDExFDASBgNVBAUTCzUxNjQwNi0wMTIwMB4XDTA5MDYxMTEyNTAxOVoXDTExMDYxMTEyNTAxOVowcjELMAkGA1UEBhMCU0UxIDAeBgNVBAMMF05vcmRlYSBEZW1vIENlcnRpZmljYXRlMRQwEgYDVQQEDAtDZXJ0aWZpY2F0ZTEUMBIGA1UEKgwLTm9yZGVhIERlbW8xFTATBgNVBAUTDDAwOTU1NzI0Mzc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwcgz5AzbxTbsCE51No7fPnSqmQBIMW9OiPkiHotwYQTl+H9qwDvQRyBqHN26tnw7hNvEShd1ZRGUg4drMEXDV5CmKqsAevs9lauWDaHnGKPNHZJ1hNNYXHwymksEz5zMnG8eqRdhb4vOV2FzreJeYpsgx31Bv0aTofHcHVz4uGcCAwEAAaOCASAwggEcMAkGA1UdEwQCMAAwEQYDVR0OBAoECEj6Y9/vU03WMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEIFjfLBeTpRMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVhLnNlL1JDQTAxMA4GA1UdDwEB/wQEAwIGQDCBiAYDVR0fBIGAMH4wfKB6oHiGdmxkYXA6Ly9sZGFwLm5iLnNlL2NuPU5vcmRlYSUyMHJvbGUtY2VydGlmaWNhdGVzJTIwQ0ElMjAwMSxvPU5vcmRlYSUyMEJhbmslMjBBQiUyMChwdWJsKSxjPVNFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBAEXUv87VpHk51y3TqkMb1MYDqeKvQRE1cNcvhEJhIzdDpXMA9fG0KqvSTT1e0ZI2r78mXDvtTZnpic44jX2XMSmKO6n+1taAXq940tJUhF4arYMUxwDKOso0Doanogug496gipqMlpLgvIhGt06sWjNrvHzp2eGydUFdCsLr2ULqbDcut7g6eMcmrsnrOntjEU/J3hO8gyCeldJ+fI81qarrK/I0MZLR5LWCyVG/SKduoxHLX7JohsbIGyK1qAh9fi8l6X1Rcu80v5inpu71E/DnjbkAZBo7vsj78zzdk7KNliBIqBcIszdJ3dEHRWSI7FspRxyiR0NDm4lpyLwFtfw=</X509Certificate>
|
102
|
+
# </X509Data>
|
103
|
+
# </KeyInfo>
|
104
|
+
def x509_data_node
|
105
|
+
issuer_name_node = Nokogiri::XML::Node.new('X509IssuerName', document)
|
106
|
+
issuer_name_node.content = "System.Security.Cryptography.X509Certificates.X500DistinguishedName"
|
107
|
+
|
108
|
+
issuer_number_node = Nokogiri::XML::Node.new('X509SerialNumber', document)
|
109
|
+
issuer_number_node.content = cert.serial
|
110
|
+
|
111
|
+
issuer_serial_node = Nokogiri::XML::Node.new('X509IssuerSerial', document)
|
112
|
+
issuer_serial_node.add_child(issuer_name_node)
|
113
|
+
issuer_serial_node.add_child(issuer_number_node)
|
114
|
+
|
115
|
+
cetificate_node = Nokogiri::XML::Node.new('X509Certificate', document)
|
116
|
+
cetificate_node.content = Base64.encode64(cert.to_der).gsub("\n", '')
|
117
|
+
|
118
|
+
data_node = Nokogiri::XML::Node.new('X509Data', document)
|
119
|
+
data_node.add_child(issuer_serial_node)
|
120
|
+
data_node.add_child(cetificate_node)
|
121
|
+
|
122
|
+
key_info_node = Nokogiri::XML::Node.new('KeyInfo', document)
|
123
|
+
key_info_node.add_child(data_node)
|
124
|
+
|
125
|
+
signed_info_node.add_next_sibling(key_info_node)
|
126
|
+
|
127
|
+
data_node
|
128
|
+
end
|
129
|
+
|
90
130
|
# <Reference URI="#_0">
|
91
131
|
# <Transforms>
|
92
132
|
# <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
@@ -94,14 +134,14 @@ class Signer
|
|
94
134
|
# <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
95
135
|
# <DigestValue>aeqXriJuUCk4tPNPAGDXGqHj6ao=</DigestValue>
|
96
136
|
# </Reference>
|
97
|
-
def digest!(target_node)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
137
|
+
def digest!(target_node, options = {})
|
138
|
+
id = options[:id] || "_#{Digest::SHA1.hexdigest(target_node.to_s)}"
|
139
|
+
target_node['u:Id'] = id if id.size > 0
|
140
|
+
target_canon = canonicalize(target_node)
|
141
|
+
target_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(target_canon)).strip
|
102
142
|
|
103
143
|
reference_node = Nokogiri::XML::Node.new('Reference', document)
|
104
|
-
reference_node['URI'] = "##{id}"
|
144
|
+
reference_node['URI'] = id.size > 0 ? "##{id}" : ""
|
105
145
|
signed_info_node.add_child(reference_node)
|
106
146
|
|
107
147
|
transforms_node = Nokogiri::XML::Node.new('Transforms', document)
|
@@ -116,16 +156,22 @@ class Signer
|
|
116
156
|
reference_node.add_child(digest_method_node)
|
117
157
|
|
118
158
|
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
159
|
digest_value_node.content = target_digest
|
122
160
|
reference_node.add_child(digest_value_node)
|
123
161
|
self
|
124
162
|
end
|
125
163
|
|
126
164
|
# <SignatureValue>...</SignatureValue>
|
127
|
-
def sign!
|
128
|
-
|
165
|
+
def sign!(options = {})
|
166
|
+
if options[:security_token]
|
167
|
+
binary_security_token_node
|
168
|
+
end
|
169
|
+
|
170
|
+
if options[:issuer_serial]
|
171
|
+
x509_data_node
|
172
|
+
end
|
173
|
+
|
174
|
+
signed_info_canon = canonicalize(signed_info_node)
|
129
175
|
|
130
176
|
signature = private_key.sign(OpenSSL::Digest::SHA1.new, signed_info_canon)
|
131
177
|
signature_value_digest = Base64.encode64(signature).gsub("\n", '')
|
data/lib/signer/version.rb
CHANGED
File without changes
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<ApplicationRequest xmlns="http://bxd.fi/xmldata/">
|
2
|
+
<CustomerId>679155330</CustomerId>
|
3
|
+
<Command>GetUserInfo</Command>
|
4
|
+
<Timestamp>2010-05-10T13:22:19.847+03:00</Timestamp>
|
5
|
+
<Environment>PRODUCTION</Environment>
|
6
|
+
<SoftwareId>Petri</SoftwareId>
|
7
|
+
</ApplicationRequest>
|
File without changes
|
@@ -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
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
9
|
+
<SignedInfo>
|
10
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
11
|
+
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
12
|
+
<Reference URI="">
|
13
|
+
<Transforms>
|
14
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
15
|
+
</Transforms>
|
16
|
+
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
17
|
+
<DigestValue>U9tsT4lrRMp8ZdKMnblgeMCGfvI=</DigestValue>
|
18
|
+
</Reference>
|
19
|
+
</SignedInfo>
|
20
|
+
<SignatureValue>GoikOue0l0ZZBkEoZ+kDvFJ0YJl1nW4zFLe8IsMcqPFFE2xOK1lO/YHKpc49CNQFs2ZhOiGwCseOg0F/8FUWp9hiAOTLlYrKVd61FErifakLw/mirP2SB3J9npPh6Idt9LMQWU+O+aRdyJMF7HLpx03GML2IF9ejKVUBTWTrcpU=</SignatureValue>
|
21
|
+
<KeyInfo>
|
22
|
+
<X509Data>
|
23
|
+
<X509IssuerSerial>
|
24
|
+
<X509IssuerName>System.Security.Cryptography.X509Certificates.X500DistinguishedName</X509IssuerName>
|
25
|
+
<X509SerialNumber>16503368396260674861</X509SerialNumber>
|
26
|
+
</X509IssuerSerial>
|
27
|
+
<X509Certificate>MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuVwyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEbgDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0GA1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4oho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnNJJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpTBmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0jlyrGYJlLli1NxHiBz7FCEJaVI8=</X509Certificate>
|
28
|
+
</X509Data>
|
29
|
+
</KeyInfo>
|
30
|
+
</Signature>
|
31
|
+
</ApplicationRequest>
|
data/spec/signer_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Signer do
|
4
|
-
it "should digest and sign
|
5
|
-
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', '
|
4
|
+
it "should digest and sign SOAP XML with security node and binary token" do
|
5
|
+
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input_1.xml')
|
6
6
|
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
|
7
7
|
private_key_file = File.join(File.dirname(__FILE__), 'fixtures', 'key.pem')
|
8
8
|
|
@@ -18,12 +18,33 @@ describe Signer do
|
|
18
18
|
signer.digest!(node)
|
19
19
|
end
|
20
20
|
|
21
|
-
signer.sign!
|
21
|
+
signer.sign!(:security_token => true)
|
22
22
|
|
23
|
-
# File.open(File.join(File.dirname(__FILE__), 'fixtures', '
|
23
|
+
# File.open(File.join(File.dirname(__FILE__), 'fixtures', 'output_1.xml'), "w") do |f|
|
24
24
|
# f.write signer.document.to_s
|
25
25
|
# end
|
26
|
-
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', '
|
26
|
+
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'output_1.xml')
|
27
|
+
|
28
|
+
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should sign simple XML" do
|
32
|
+
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input_2.xml')
|
33
|
+
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
|
34
|
+
private_key_file = File.join(File.dirname(__FILE__), 'fixtures', 'key.pem')
|
35
|
+
|
36
|
+
signer = Signer.new(File.read(input_xml_file))
|
37
|
+
signer.cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
|
38
|
+
signer.private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file), "test")
|
39
|
+
signer.security_node = signer.document.root
|
40
|
+
signer.security_token_id = ""
|
41
|
+
signer.digest!(signer.document, :id => "")
|
42
|
+
signer.sign!(:issuer_serial => true)
|
43
|
+
|
44
|
+
# File.open(File.join(File.dirname(__FILE__), 'fixtures', 'output_2.xml'), "w") do |f|
|
45
|
+
# f.write signer.document.to_s
|
46
|
+
# end
|
47
|
+
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'output_2.xml')
|
27
48
|
|
28
49
|
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
|
29
50
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: signer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -71,9 +71,11 @@ files:
|
|
71
71
|
- README.md
|
72
72
|
- LICENSE
|
73
73
|
- spec/fixtures/cert.pem
|
74
|
-
- spec/fixtures/
|
74
|
+
- spec/fixtures/input_1.xml
|
75
|
+
- spec/fixtures/input_2.xml
|
75
76
|
- spec/fixtures/key.pem
|
76
|
-
- spec/fixtures/
|
77
|
+
- spec/fixtures/output_1.xml
|
78
|
+
- spec/fixtures/output_2.xml
|
77
79
|
- spec/signer_spec.rb
|
78
80
|
- spec/spec_helper.rb
|
79
81
|
homepage: ''
|
@@ -96,15 +98,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
98
|
version: '0'
|
97
99
|
requirements: []
|
98
100
|
rubyforge_project:
|
99
|
-
rubygems_version: 1.8.
|
101
|
+
rubygems_version: 1.8.24
|
100
102
|
signing_key:
|
101
103
|
specification_version: 3
|
102
104
|
summary: WS Security XML signer
|
103
105
|
test_files:
|
104
106
|
- spec/fixtures/cert.pem
|
105
|
-
- spec/fixtures/
|
107
|
+
- spec/fixtures/input_1.xml
|
108
|
+
- spec/fixtures/input_2.xml
|
106
109
|
- spec/fixtures/key.pem
|
107
|
-
- spec/fixtures/
|
110
|
+
- spec/fixtures/output_1.xml
|
111
|
+
- spec/fixtures/output_2.xml
|
108
112
|
- spec/signer_spec.rb
|
109
113
|
- spec/spec_helper.rb
|
110
|
-
has_rdoc:
|