Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Added support for inclusive namespaces #1

Merged
merged 4 commits into from

3 participants

@bluemango

I working on getting the ruby-saml gem to play nicely with Salesforce. Salesforce SAML assertions use inclusive namespaces so I had to add support to the canonix gem for this. I have included inclusive namespace support as well as some additional tests for verify the update.

Thanks,
Greg DeVore

@brendon
Owner

Hi Greg, thanks for the pull request. I've adopted this gem but have next to no idea of the detail of how the code works. I've had a look through though and wondered if you could fix a couple of things (or let me know why they shouldn't be fixed) :D

There appears to be some abandoned code around the @inclusive_namespaces variable that you've abandoned in your patch. Would you be able to remove those references also? They exist on line 135 and also in the initialiser line 111.

Also, would you be able to remove the reference to salesforce in the test and just say should "canonicalize a saml file with inclusive ns assertions" :)

This is my first pull request, so let me know if I'm doing this all wrong :)

Owner

Also, if you're making changes/adding features to the ruby-saml gem itself, it might pay to check out relevances fork of that project as they've already done heaps of enhancements and I'm just waiting on them to push them up to the master.

Would you be able to link me to some documentation on ns assertions? I've tried to find some info but have come up dry :) Either that or a quick explanation of what's going on in the patch would be great :) Sorry for the ignorance :)

@brendon
Owner

Hi Greg, thanks for the info. I agree, I find this whole SAML thing a huge drama for something so simple! The mere fact that ruby support is so underdeveloped speaks volumes as to its adoption in the trendier real world!

I just had a look back at the code and that mention of @inclusive_namespaces in canonicalize_element is only invoked if @prefix_list is not false. I've traced @prefix_list through the whole script and it is initialised as nil, and never gets changed or used, so I guess it's safe to remove both references to @inclusive_namespaces and @prefix_list. Would you be happy to do that? Definitely have a doublecheck also just in case I've missed something big :)

@brendon
Owner

You're right regarding the relevance fork, but it would still pay to double check it before you reinvent the wheel just in case :) I'll give the guy a message and see where he's at with prepping the code to be pushed up to master :)

@bluemango
@brendon
Owner

Hi Greg, thanks for that. I just meant for you to remove lines 111, 112 and 134. I'm pretty sure that no one currently uses the canonicalize_element function, but just incase someone decides to drop their usage of xmlcanonicalizer in favour of this gem, I'd prefer to keep the functionality just in case. I'll just accept this commit and revert those changes for you :D

Thanks heaps for your help! :D

Brendon

@brendon brendon merged commit 92880e9 into brendon:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 28, 2011
  1. @gdevore
  2. @gdevore

    updated gemspec

    gdevore authored
Commits on Jun 29, 2011
  1. @gdevore
Commits on Jul 1, 2011
  1. @gdevore
This page is out of date. Refresh to see the latest.
View
10 canonix.gemspec
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
s.version = "0.1.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
- s.authors = [%q{Brendon Muir}]
- s.date = %q{2011-06-16}
+ s.authors = ["Brendon Muir"]
+ s.date = %q{2011-06-28}
s.description = %q{This is based on andrewferk's rewrite for Ruby 1.9 compatibility, but applies
relevance's fix to ensure proper canonicalisation. It is intended that this be the new official
Ruby Canonicaliser as the other project seems to be abandoned.}
@@ -32,12 +32,14 @@ Gem::Specification.new do |s|
"test/helper.rb",
"test/saml_assertion.xml",
"test/saml_expected_canonical_form.xml",
+ "test/saml_with_inclusive_ns_assertion.xml",
+ "test/saml_with_inclusive_ns_expected_canonical_form.xml",
"test/test_xmlcanonicalizer.rb",
"tests.watchr"
]
s.homepage = %q{http://github.com/brendon/canonix}
- s.require_paths = [%q{lib}]
- s.rubygems_version = %q{1.8.5}
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.5.0}
s.summary = %q{XML Canonicalizer for Ruby >= 1.92}
if s.respond_to? :specification_version then
View
54 lib/xml/util/xmlcanonicalizer.rb
@@ -86,7 +86,7 @@ def initialize(prefix, uri)
end
class XmlCanonicalizer
- attr_accessor :prefix_list, :logger
+ attr_accessor :prefix_list, :logger, :inclusive_namespaces
BEFORE_DOC_ELEMENT = 0
INSIDE_DOC_ELEMENT = 1
@@ -108,8 +108,6 @@ def initialize(with_comments, excl_c14n)
@prevVisibleNamespacesStart = 0
@prevVisibleNamespacesEnd = 0
@visibleNamespaces = Array.new()
- @inclusive_namespaces = Array.new()
- @prefix_list = nil
end
def add_inclusive_namespaces(prefix_list, element, visible_namespaces)
@@ -131,22 +129,6 @@ def canonicalize(document)
@res
end
- def canonicalize_element(element, logging = true)
- @inclusive_namespaces = add_inclusive_namespaces(@prefix_list, element, @inclusive_namespaces) if (@prefix_list)
- @preserve_document = element.document()
- tmp_parent = element.parent()
- body_string = remove_whitespace(element.to_s().gsub("\n","").gsub("\t","").gsub("\r",""))
- document = Document.new(body_string)
- tmp_parent.delete_element(element)
- element = tmp_parent.add_element(document.root())
- @preserve_element = element
- document = Document.new(element.to_s())
- ns = element.namespace(element.prefix())
- document.root().add_namespace(element.prefix(), ns)
- write_document_node(document)
- @res
- end
-
def write_document_node(document)
@state = BEFORE_DOC_ELEMENT
if (document.class().to_s() == "REXML::Element")
@@ -228,17 +210,14 @@ def write_namespace_axis(node, visible)
if (visible && !has_empty_namespace && !is_namespace_rendered(nil, nil))
@res = @res + ' xmlns=""'
end
- #TODO: ns of inclusive_list
-#=begin
- if ((@prefix_list) && (node.to_s() == node.parent().to_s()))
- #list.push(node.prefix())
- @inclusive_namespaces.each{|ns|
- prefix = ns.prefix().split(":")[1]
- list.push(prefix) if (!list.include?(prefix) && (!node.attributes.prefixes.include?(prefix)))
+
+ #: ns of inclusive_list
+ if self.inclusive_namespaces && !self.inclusive_namespaces.empty?
+ self.inclusive_namespaces.each{|prefix|
+ list.push(prefix) if (!list.include?(prefix) && (node.attributes.prefixes.include?(prefix)))
}
- @prefix_list = nil
end
-#=end
+
list.sort!()
list.each{|prefix|
next if (prefix == "")
@@ -402,23 +381,8 @@ def remove_whitespace(string)
document = Document.new(File.new(ARGV[0]))
body = nil
c = WSS4R::Security::Util::XmlCanonicalizer.new(false, true)
-
- if (ARGV.size() == 3)
- body = ARGV[2]
- if (body == "true")
- element = XPath.match(document, "/soap:Envelope/soap:Body")[0]
- element = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security/Signature/SignedInfo")
- result = c.canonicalize_element(element)
- puts("-----")
- puts(result)
- puts("-----")
- puts(result.size())
- puts("-----")
- puts(CryptHash.new().digest_b64(result))
- end
- else
- result = c.canonicalize(document)
- end
+
+ result = c.canonicalize(document)
file = File.new(ARGV[1], "wb")
file.write(result)
View
39 test/saml_with_inclusive_ns_assertion.xml
@@ -0,0 +1,39 @@
+<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0" Destination="http://dev.example.com:8080/sessions/saml" ID="_400c66cfbb96b81e87d6bc96fefdb9b01308849650183" InResponseTo="_107c07d0-7feb-012e-8cc0-001ec2c1cafd" IssueInstant="2011-06-23T17:20:50.183Z">
+ <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://dev.example.com:8080/sessions/saml</saml:Issuer>
+ <samlp:Status>
+ <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+ </samlp:Status>
+ <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="_b197baba4544550444357b2b18de57961308849650183" IssueInstant="2011-06-23T17:20:50.183Z">
+ <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://dev.example.com:8080/sessions/saml</saml:Issuer>
+ <saml:Subject>
+ <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">mail@example.com</saml:NameID>
+ <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+ <saml:SubjectConfirmationData InResponseTo="_107c07d0-7feb-012e-8cc0-001ec2c1cafd" NotOnOrAfter="2011-06-23T17:25:50.183Z" Recipient="http://bmls.screenstepslive.dev/sessions/saml"/>
+ </saml:SubjectConfirmation>
+ </saml:Subject>
+ <saml:Conditions NotOnOrAfter="2011-06-23T17:25:50.183Z" NotBefore="2011-06-23T17:20:50.183Z">
+ <saml:AudienceRestriction>
+ <saml:Audience>Audience</saml:Audience>
+ </saml:AudienceRestriction>
+ </saml:Conditions>
+ <saml:AuthnStatement AuthnInstant="2011-06-23T17:20:50.183Z">
+ <saml:AuthnContext>
+ <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
+ </saml:AuthnContext>
+ </saml:AuthnStatement>
+ <saml:AttributeStatement>
+ <saml:Attribute Name="userId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:anyType">00550000001b7Kf</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="username" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:anyType">mail@example.com</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:anyType">mail@example.com</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="is_portal_user" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:anyType">false</saml:AttributeValue>
+ </saml:Attribute>
+ </saml:AttributeStatement>
+ </saml:Assertion>
+</samlp:Response>
View
39 test/saml_with_inclusive_ns_expected_canonical_form.xml
@@ -0,0 +1,39 @@
+<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://dev.example.com:8080/sessions/saml" ID="_400c66cfbb96b81e87d6bc96fefdb9b01308849650183" InResponseTo="_107c07d0-7feb-012e-8cc0-001ec2c1cafd" IssueInstant="2011-06-23T17:20:50.183Z" Version="2.0">
+ <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://dev.example.com:8080/sessions/saml</saml:Issuer>
+ <samlp:Status>
+ <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode>
+ </samlp:Status>
+ <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_b197baba4544550444357b2b18de57961308849650183" IssueInstant="2011-06-23T17:20:50.183Z" Version="2.0">
+ <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://dev.example.com:8080/sessions/saml</saml:Issuer>
+ <saml:Subject>
+ <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">mail@example.com</saml:NameID>
+ <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+ <saml:SubjectConfirmationData InResponseTo="_107c07d0-7feb-012e-8cc0-001ec2c1cafd" NotOnOrAfter="2011-06-23T17:25:50.183Z" Recipient="http://bmls.screenstepslive.dev/sessions/saml"></saml:SubjectConfirmationData>
+ </saml:SubjectConfirmation>
+ </saml:Subject>
+ <saml:Conditions NotBefore="2011-06-23T17:20:50.183Z" NotOnOrAfter="2011-06-23T17:25:50.183Z">
+ <saml:AudienceRestriction>
+ <saml:Audience>Audience</saml:Audience>
+ </saml:AudienceRestriction>
+ </saml:Conditions>
+ <saml:AuthnStatement AuthnInstant="2011-06-23T17:20:50.183Z">
+ <saml:AuthnContext>
+ <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
+ </saml:AuthnContext>
+ </saml:AuthnStatement>
+ <saml:AttributeStatement>
+ <saml:Attribute Name="userId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">00550000001b7Kf</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="username" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">mail@example.com</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">mail@example.com</saml:AttributeValue>
+ </saml:Attribute>
+ <saml:Attribute Name="is_portal_user" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
+ <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">false</saml:AttributeValue>
+ </saml:Attribute>
+ </saml:AttributeStatement>
+ </saml:Assertion>
+</samlp:Response>
View
22 test/test_xmlcanonicalizer.rb
@@ -54,5 +54,27 @@ class TestXmlcanonicalizer < Test::Unit::TestCase
assert_equal xml_expect, xml_canonicalized
end
+
+ should "canonicalize a saml file with inclusive namespaces" do
+ fp = File.new(File.dirname(File.expand_path(__FILE__))+'/saml_with_inclusive_ns_assertion.xml','r')
+ xml = ''
+ while (l = fp.gets)
+ xml += l
+ end
+ fp.close
+
+ xml_canonicalizer = XML::Util::XmlCanonicalizer.new(false,true)
+ rexml = REXML::Document.new(xml);
+ xml_canonicalizer.inclusive_namespaces = %w(ds saml samlp xs)
+ xml_canonicalized = xml_canonicalizer.canonicalize(rexml);
+
+ fp = File.new(File.dirname(File.expand_path(__FILE__))+'/saml_with_inclusive_ns_expected_canonical_form.xml','r')
+ xml_expect = ''
+ while (l = fp.gets)
+ xml_expect += l
+ end
+ fp.close
+ assert_equal xml_expect, xml_canonicalized #, (xml_canonicalized.to_s + "\n\n" + xml_expect)
+ end
end
Something went wrong with that request. Please try again.