From 0701a22d6fc192845a48f99903e1c1bcba9f42c4 Mon Sep 17 00:00:00 2001 From: goromlagche Date: Mon, 11 Oct 2021 11:58:43 +0530 Subject: [PATCH] support ID attrs with names other than 'ID' --- README.md | 4 ++++ lib/signed_xml.rb | 4 ++-- lib/signed_xml/document.rb | 5 +++-- lib/signed_xml/reference.rb | 8 ++++---- lib/signed_xml/signature.rb | 5 +++-- .../signed_saml_response_with_custom_attribute.xml | 8 ++++++++ spec/signed_xml_document_spec.rb | 12 ++++++++++-- 7 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 spec/resources/signed_saml_response_with_custom_attribute.xml diff --git a/README.md b/README.md index 09ab066..631ca8c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,10 @@ private_key = OpenSSL::PKey::RSA.new(File.new 'private_key.pem') certificate = OpenSSL::X509::Certificate.new(File.read 'certificate.pem') doc.sign(private_key, certificate) File.open('signed_doc.xml', 'w') { |file| file.puts doc.to_xml } + +# Custom ID attribute +signed_document = SignedXml::Document(File.read('some_signed_doc.xml'), id_attr: "some_id") +signed_doc.is_verified? ``` Contributing diff --git a/lib/signed_xml.rb b/lib/signed_xml.rb index d1891c3..3145e10 100644 --- a/lib/signed_xml.rb +++ b/lib/signed_xml.rb @@ -5,8 +5,8 @@ module SignedXml XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#" XML_EXC_C14N_NS = "http://www.w3.org/2001/10/xml-exc-c14n#" - def self.Document(thing) - Document.new(thing) + def self.Document(thing, id_attr: nil) + Document.new(thing, id_attr: id_attr) end # Logger that does nothing diff --git a/lib/signed_xml/document.rb b/lib/signed_xml/document.rb index 6a0d3e3..4ae9e7c 100644 --- a/lib/signed_xml/document.rb +++ b/lib/signed_xml/document.rb @@ -7,12 +7,13 @@ class Document attr_reader :doc - def initialize(thing) + def initialize(thing, id_attr: nil) if thing.is_a? Nokogiri::XML::Document @doc = thing else @doc = Nokogiri::XML(thing) end + @id_attr = id_attr end def is_verifiable? @@ -54,7 +55,7 @@ def signatures def init_signatures signatures = [] doc.xpath("//ds:Signature", ds: XMLDSIG_NS).each do |signature_node| - signatures << Signature.new(signature_node) + signatures << Signature.new(signature_node, id_attr: @id_attr) end signatures end diff --git a/lib/signed_xml/reference.rb b/lib/signed_xml/reference.rb index 8327424..876d73e 100644 --- a/lib/signed_xml/reference.rb +++ b/lib/signed_xml/reference.rb @@ -5,7 +5,7 @@ class Reference attr_reader :here, :start - def initialize(here) + def initialize(here, id_attr: nil) @here = here uri = here['URI'] @@ -15,9 +15,9 @@ def initialize(here) when /^#/ id = uri.split('#').last raise ArgumentError, "XPointer expressions like #{id} are not yet supported" if id =~ /^xpointer/ - # TODO: handle ID attrs with names other than 'ID' - @start = here.document.at_xpath("//*[@ID='#{id}']") - raise ArgumentError, "no match found for ID #{id}" if @start.nil? + id_attr ||= 'ID' + @start = here.document.at_xpath("//*[@#{id_attr}='#{id}']") + raise ArgumentError, "no match found for #{id_attr} #{id}" if @start.nil? else raise ArgumentError, "unsupported Reference URI #{uri}" end diff --git a/lib/signed_xml/signature.rb b/lib/signed_xml/signature.rb index 3a74c1e..ab5d691 100644 --- a/lib/signed_xml/signature.rb +++ b/lib/signed_xml/signature.rb @@ -10,8 +10,9 @@ class Signature attr_accessor :public_key attr_accessor :certificate_store - def initialize(here) + def initialize(here, id_attr: nil) @here = here + @id_attr = id_attr end def is_verified? @@ -66,7 +67,7 @@ def init_references references = [] here.xpath('//ds:Reference', ds: XMLDSIG_NS).each do |reference_node| - references << Reference.new(reference_node) + references << Reference.new(reference_node, id_attr: @id_attr) end references diff --git a/spec/resources/signed_saml_response_with_custom_attribute.xml b/spec/resources/signed_saml_response_with_custom_attribute.xml new file mode 100644 index 0000000..e9c361d --- /dev/null +++ b/spec/resources/signed_saml_response_with_custom_attribute.xml @@ -0,0 +1,8 @@ + +http://localhost/simplesaml/saml2/idp/metadata.php + + + + + +http://localhost/simplesaml/saml2/idp/metadata.php_3c448bd72f639960c116dc6339a4930e7a4a3e9f3chttp://localhost:3000/urn:oasis:names:tc:SAML:2.0:ac:classes:Passwordtodd.thomas@openlogic.com diff --git a/spec/signed_xml_document_spec.rb b/spec/signed_xml_document_spec.rb index 4486d31..9de6cdf 100644 --- a/spec/signed_xml_document_spec.rb +++ b/spec/signed_xml_document_spec.rb @@ -14,6 +14,10 @@ SignedXml::Document(File.read(File.join(resources_path, 'signed_saml_response.xml'))) end + let(:signed_doc_custom_id) do + SignedXml::Document(File.read(File.join(resources_path, 'signed_saml_response_with_custom_attribute.xml')), id_attr: 'CustomID') + end + it "knows which documents can be verified" do unsigned_doc.is_verifiable?.should be false signed_doc.is_verifiable?.should be true @@ -57,11 +61,15 @@ signed_doc.send(:signatures).first.send(:is_signed_info_verified?).should be true end + it "supports id attrs with names other than 'ID'" do + signed_doc_custom_id.sign(test_private_key, test_certificate).is_verified?.should be true + end + it "verifies docs with one enveloped-signature Resource element and embedded X.509 key" do signed_doc.is_verified?.should be true end - let(:passed_in_nokogiri_doc) do + let(:passed_in_nokogiri_doc) do SignedXml::Document(Nokogiri::XML(File.read(File.join(resources_path, 'signed_saml_response.xml')))) end @@ -153,4 +161,4 @@ it "signs template documents" do signed_doc_template.sign(test_private_key, test_certificate).is_verified?.should be true end -end \ No newline at end of file +end