Commit 590b80f

mo <mo@mokhan.ca>
2017-12-11 21:27:10
promote a new API for injecting signatures.
1 parent d4317d4
lib/saml/kit/builders/templates/authentication_request.builder
@@ -1,5 +1,5 @@
 xml.tag!('samlp:AuthnRequest', request_options) do
   xml.tag!('saml:Issuer', issuer)
-  signature.template(id)
+  signature_for(reference_id: id, xml: xml)
   xml.tag!('samlp:NameIDPolicy', Format: name_id_format)
 end
lib/saml/kit/builders/templates/identity_provider_metadata.builder
@@ -1,6 +1,6 @@
 xml.instruct!
 xml.EntityDescriptor entity_descriptor_options do
-  signature.template(id)
+  signature_for(reference_id: id, xml: xml)
   xml.IDPSSODescriptor idp_sso_descriptor_options do
     if configuration.signing_certificate_pem.present?
       xml.KeyDescriptor use: "signing" do
lib/saml/kit/builders/templates/logout_request.builder
@@ -1,6 +1,6 @@
 xml.instruct!
 xml.LogoutRequest logout_request_options do
   xml.Issuer({ xmlns: Saml::Kit::Namespaces::ASSERTION }, issuer)
-  signature.template(id)
+  signature_for(reference_id: id, xml: xml)
   xml.NameID name_id_options, user.name_id_for(name_id_format)
 end
lib/saml/kit/builders/templates/logout_response.builder
@@ -1,6 +1,6 @@
 xml.LogoutResponse logout_response_options do
   xml.Issuer(issuer, xmlns: Saml::Kit::Namespaces::ASSERTION)
-  signature.template(id)
+  signature_for(reference_id: id, xml: xml)
   xml.Status do
     xml.StatusCode Value: status_code
   end
lib/saml/kit/builders/templates/service_provider_metadata.builder
@@ -1,6 +1,6 @@
 xml.instruct!
 xml.EntityDescriptor entity_descriptor_options do
-  signature.template(id)
+  signature_for(reference_id: id, xml: xml)
   xml.SPSSODescriptor descriptor_options do
     if configuration.signing_certificate_pem.present?
       xml.KeyDescriptor use: "signing" do
lib/saml/kit/builders/templates/xml_signature.builder
@@ -0,0 +1,20 @@
+xml.Signature "xmlns" => Saml::Kit::Namespaces::XMLDSIG do
+  xml.SignedInfo do
+    xml.CanonicalizationMethod Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
+    xml.SignatureMethod Algorithm: signature_method
+    xml.Reference URI: "##{reference_id}" do
+      xml.Transforms do
+        xml.Transform Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
+        xml.Transform Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
+      end
+      xml.DigestMethod Algorithm: digest_method
+      xml.DigestValue ""
+    end
+  end
+  xml.SignatureValue ""
+  xml.KeyInfo do
+    xml.X509Data do
+      xml.X509Certificate stripped_signing_certificate
+    end
+  end
+end
lib/saml/kit/templatable.rb
@@ -1,8 +1,78 @@
 module Saml
   module Kit
+    class XmlSignature
+      SIGNATURE_METHODS = {
+        SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
+        SHA224: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
+        SHA256: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
+        SHA384: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
+        SHA512: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
+      }.freeze
+      DIGEST_METHODS = {
+        SHA1: "http://www.w3.org/2000/09/xmldsig#SHA1",
+        SHA224: "http://www.w3.org/2001/04/xmldsig-more#sha224",
+        SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
+        SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384",
+        SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
+      }.freeze
+
+      attr_reader :sign, :configuration
+      attr_reader :reference_id
+      attr_reader :stripped_signing_certificate
+
+      def initialize(reference_id, configuration:, sign: true)
+        @configuration = configuration
+        @reference_id = reference_id
+        @sign = sign
+        @stripped_signing_certificate = configuration.stripped_signing_certificate
+      end
+
+      def signature_method
+        SIGNATURE_METHODS[configuration.signature_method]
+      end
+
+      def digest_method
+        DIGEST_METHODS[configuration.digest_method]
+      end
+    end
+
+    class Signatures
+      attr_reader :sign, :configuration
+
+      def initialize(configuration:, sign: true)
+        @configuration = configuration
+        @reference_ids = []
+        @sign = sign
+      end
+
+      def build(reference_id)
+        @reference_ids << reference_id
+        XmlSignature.new(reference_id, configuration: configuration, sign: sign)
+      end
+
+      def complete(raw_xml)
+        return raw_xml unless sign
+
+        @reference_ids.each do |reference_id|
+          raw_xml = Xmldsig::SignedDocument.new(raw_xml).sign(configuration.signing_private_key)
+        end
+        raw_xml
+      end
+    end
+
     module Templatable
       def to_xml(xml: ::Builder::XmlMarkup.new)
-        Template.new(self).to_xml(xml: xml)
+        signatures.complete(Template.new(self).to_xml(xml: xml))
+      end
+
+      def signature_for(reference_id: , xml:)
+        return unless sign
+        signature = signatures.build(reference_id)
+        Template.new(signature).to_xml(xml: xml)
+      end
+
+      def signatures
+        @signatures ||= Saml::Kit::Signatures.new(configuration: configuration, sign: sign)
       end
     end
   end
lib/saml/kit/template.rb
@@ -8,9 +8,7 @@ module Saml
       end
 
       def to_xml(xml: ::Builder::XmlMarkup.new)
-        with_signature(xml: xml) do |signature|
-          template.render(target, xml: xml, signature: signature)
-        end
+        template.render(target, xml: xml)
       end
 
       private
@@ -26,13 +24,6 @@ module Saml
       def template
         Tilt.new(template_path)
       end
-
-      def with_signature(xml:)
-        return yield target if target.is_a?(Saml::Kit::Signature)
-
-        signature = Saml::Kit::Signature.new(xml, configuration: target.configuration, sign: target.sign)
-        signature.apply_to(yield signature)
-      end
     end
   end
 end