@@ -47,79 +47,62 @@ def sign_document(private_key, certificate, signature_method = RubySaml::XML::Cr
4747 config . options = RubySaml ::XML ::BaseDocument ::NOKOGIRI_OPTIONS
4848 end
4949
50- # Create signature elements using Nokogiri
51- signature_element = Nokogiri ::XML ::Element . new ( 'ds:Signature' , noko )
52- signature_element [ 'xmlns:ds' ] = RubySaml ::XML ::Crypto ::DSIG
53-
54- signed_info_element = Nokogiri ::XML ::Element . new ( 'ds:SignedInfo' , noko )
55- signature_element . add_child ( signed_info_element )
56-
57- canon_method_element = Nokogiri ::XML ::Element . new ( 'ds:CanonicalizationMethod' , noko )
58- canon_method_element [ 'Algorithm' ] = RubySaml ::XML ::Crypto ::C14N
59- signed_info_element . add_child ( canon_method_element )
60-
61- sig_method_element = Nokogiri ::XML ::Element . new ( 'ds:SignatureMethod' , noko )
62- sig_method_element [ 'Algorithm' ] = signature_method
63- signed_info_element . add_child ( sig_method_element )
64-
65- # Add Reference
66- reference_element = Nokogiri ::XML ::Element . new ( 'ds:Reference' , noko )
67- reference_element [ 'URI' ] = "##{ noko . root &.attr ( 'ID' ) } "
68- signed_info_element . add_child ( reference_element )
69-
70- # Add Transforms
71- transforms_element = Nokogiri ::XML ::Element . new ( 'ds:Transforms' , noko )
72- reference_element . add_child ( transforms_element )
73-
74- transform1 = Nokogiri ::XML ::Element . new ( 'ds:Transform' , noko )
75- transform1 [ 'Algorithm' ] = RubySaml ::XML ::Crypto ::ENVELOPED_SIG
76- transforms_element . add_child ( transform1 )
77-
78- transform2 = Nokogiri ::XML ::Element . new ( 'ds:Transform' , noko )
79- transform2 [ 'Algorithm' ] = RubySaml ::XML ::Crypto ::C14N
80- transforms_element . add_child ( transform2 )
81-
82- inc_namespaces = Nokogiri ::XML ::Element . new ( 'ec:InclusiveNamespaces' , noko )
83- inc_namespaces [ 'xmlns:ec' ] = RubySaml ::XML ::Crypto ::C14N
84- inc_namespaces [ 'PrefixList' ] = INC_PREFIX_LIST
85- transform2 . add_child ( inc_namespaces )
50+ # Create the signature structure using Builder
51+ builder = Nokogiri ::XML ::Builder . new do |xml |
52+ xml [ 'ds' ] . Signature ( 'xmlns:ds' => RubySaml ::XML ::Crypto ::DSIG ) do
53+ xml [ 'ds' ] . SignedInfo do
54+ xml [ 'ds' ] . CanonicalizationMethod ( Algorithm : RubySaml ::XML ::Crypto ::C14N )
55+ xml [ 'ds' ] . SignatureMethod ( Algorithm : signature_method )
56+ xml [ 'ds' ] . Reference ( URI : "##{ noko . root . attr ( 'ID' ) } " ) do
57+ xml [ 'ds' ] . Transforms do
58+ xml [ 'ds' ] . Transform ( Algorithm : RubySaml ::XML ::Crypto ::ENVELOPED_SIG )
59+ xml [ 'ds' ] . Transform ( Algorithm : RubySaml ::XML ::Crypto ::C14N ) do
60+ xml [ 'ec' ] . InclusiveNamespaces (
61+ 'xmlns:ec' => RubySaml ::XML ::Crypto ::C14N ,
62+ PrefixList : INC_PREFIX_LIST
63+ )
64+ end
65+ end
66+ xml [ 'ds' ] . DigestMethod ( Algorithm : digest_method )
67+
68+ # We'll compute and add DigestValue after creating the structure
69+ xml [ 'ds' ] . DigestValue
70+ end
71+ end
72+
73+ # We'll add these after the digest computation
74+ xml [ 'ds' ] . SignatureValue
75+ xml [ 'ds' ] . KeyInfo do
76+ xml [ 'ds' ] . X509Data do
77+ xml [ 'ds' ] . X509Certificate
78+ end
79+ end
80+ end
81+ end
8682
87- digest_method_element = Nokogiri ::XML ::Element . new ( 'ds:DigestMethod' , noko )
88- digest_method_element [ 'Algorithm' ] = digest_method
89- reference_element . add_child ( digest_method_element )
83+ # Extract the signature element from the builder
84+ signature_element = builder . doc . root
9085
86+ # Calculate digest
9187 inclusive_namespaces = INC_PREFIX_LIST . split
9288 canon_doc = noko . canonicalize ( RubySaml ::XML ::Crypto . canon_algorithm ( RubySaml ::XML ::Crypto ::C14N ) , inclusive_namespaces )
89+ digest_value = compute_digest ( canon_doc , RubySaml ::XML ::Crypto . hash_algorithm ( digest_method ) )
9390
94- digest_value_element = Nokogiri ::XML ::Element . new ( 'ds:DigestValue' , noko )
95- digest_value_element . content = compute_digest ( canon_doc , RubySaml ::XML ::Crypto . hash_algorithm ( digest_method_element ) )
96- reference_element . add_child ( digest_value_element )
97-
98- # add SignatureValue
99- noko_sig_element = Nokogiri ::XML ( signature_element . to_s ) do |config |
100- config . options = RubySaml ::XML ::BaseDocument ::NOKOGIRI_OPTIONS | Nokogiri ::XML ::ParseOptions ::NOBLANKS
101- end
102-
103- noko_signed_info_element = noko_sig_element . at_xpath ( '//ds:Signature/ds:SignedInfo' , 'ds' => RubySaml ::XML ::Crypto ::DSIG )
104- canon_string = noko_signed_info_element . canonicalize ( RubySaml ::XML ::Crypto . canon_algorithm ( RubySaml ::XML ::Crypto ::C14N ) )
91+ digest_value_element = signature_element . at_xpath ( '//ds:DigestValue' , 'ds' => RubySaml ::XML ::Crypto ::DSIG )
92+ digest_value_element . content = digest_value
10593
94+ # Canonicalize the SignedInfo element for signing
95+ signed_info_element = signature_element . at_xpath ( '//ds:SignedInfo' , 'ds' => RubySaml ::XML ::Crypto ::DSIG )
96+ canon_string = signed_info_element . canonicalize ( RubySaml ::XML ::Crypto . canon_algorithm ( RubySaml ::XML ::Crypto ::C14N ) )
10697 signature = compute_signature ( private_key , RubySaml ::XML ::Crypto . hash_algorithm ( signature_method ) . new , canon_string )
10798
108- sig_value_element = Nokogiri ::XML ::Element . new ( 'ds:SignatureValue' , noko )
99+ # Set the signature value
100+ sig_value_element = signature_element . at_xpath ( '//ds:SignatureValue' , 'ds' => RubySaml ::XML ::Crypto ::DSIG )
109101 sig_value_element . content = signature
110- signature_element . add_child ( sig_value_element )
111-
112- # add KeyInfo
113- key_info_element = Nokogiri ::XML ::Element . new ( 'ds:KeyInfo' , noko )
114- signature_element . add_child ( key_info_element )
115-
116- x509_element = Nokogiri ::XML ::Element . new ( 'ds:X509Data' , noko )
117- key_info_element . add_child ( x509_element )
118-
119- x509_cert_element = Nokogiri ::XML ::Element . new ( 'ds:X509Certificate' , noko )
120- x509_element . add_child ( x509_cert_element )
121102
103+ # Set the certificate
122104 certificate = OpenSSL ::X509 ::Certificate . new ( certificate ) if certificate . is_a? ( String )
105+ x509_cert_element = signature_element . at_xpath ( '//ds:X509Certificate' , 'ds' => RubySaml ::XML ::Crypto ::DSIG )
123106 x509_cert_element . content = Base64 . encode64 ( certificate . to_der ) . delete ( "\n " )
124107
125108 # add the signature
@@ -145,10 +128,15 @@ def compute_digest(document, digest_algorithm)
145128 Base64 . encode64 ( digest ) . strip
146129 end
147130
148- def convert_nokogiri_to_rexml ( noko_element )
149- rexml_element = REXML ::Element . new ( noko_element . name )
131+ # TODO: This is a shim method which will be removed when the
132+ # full Nokogiri conversion is complete
133+ def convert_nokogiri_to_rexml ( noko_element , parent_namespaces = Set . new )
134+ rexml_element = REXML ::Element . new ( "#{ "#{ noko_element . namespace . prefix } :" if noko_element . namespace } #{ noko_element . name } " )
135+
136+ if noko_element . namespace && !parent_namespaces . include? ( noko_element . namespace )
137+ rexml_element . add_namespace ( noko_element . namespace . prefix , noko_element . namespace . href )
138+ end
150139
151- # Copy attributes
152140 noko_element . attributes . each do |name , value |
153141 rexml_element . add_attribute ( name , value )
154142 end
@@ -161,7 +149,7 @@ def convert_nokogiri_to_rexml(noko_element)
161149 # Recursively copy child elements
162150 noko_element . children . each do |child |
163151 if child . element?
164- rexml_element . add_element ( convert_nokogiri_to_rexml ( child ) )
152+ rexml_element . add_element ( convert_nokogiri_to_rexml ( child , parent_namespaces << noko_element . namespace ) )
165153 elsif child . text?
166154 rexml_element . add_text ( child . text )
167155 end
0 commit comments