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 CHANGED
@@ -27,7 +27,7 @@ signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing"
27
27
  signer.digest!(node)
28
28
  end
29
29
 
30
- signer.sign!
30
+ signer.sign!(:security_token => true)
31
31
 
32
32
  signer.to_xml
33
33
  ```
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
- security_node.add_child(node)
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
- binary_security_token_node
99
-
100
- id = "_#{Digest::SHA1.hexdigest(target_node.to_s)}"
101
- target_node['u:Id'] = id
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
- signed_info_canon = signed_info_node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
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", '')
@@ -1,3 +1,3 @@
1
1
  class Signer
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
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 the XML" do
5
- input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input.xml')
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', 'output.xml'), "w") do |f|
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', 'output.xml')
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.0.0
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-05-03 00:00:00.000000000 Z
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/input.xml
74
+ - spec/fixtures/input_1.xml
75
+ - spec/fixtures/input_2.xml
75
76
  - spec/fixtures/key.pem
76
- - spec/fixtures/output.xml
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.21
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/input.xml
107
+ - spec/fixtures/input_1.xml
108
+ - spec/fixtures/input_2.xml
106
109
  - spec/fixtures/key.pem
107
- - spec/fixtures/output.xml
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: