verifying a WCF signed SOAP message - validation

I have a problem verifying a SOAP message timestamp and body.
Before starting to write any code I'm trying to verify it by myself, these are the steps I followed to verify the timestamp:
1) Extract the timestamp tag, add any used namespace and write it to a file:
<u:Timestamp u:Id="uuid-cd1febd3-a76a-4148-8a3e-367aee62293d-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<u:Created>2009-11-11T17:37:49.000Z</u:Created>
<u:Expires>2009-11-11T17:42:49.000Z</u:Expires>
</u:Timestamp>
2) Use xmllint to canonicalize it
xmllint --exc-c14n timestamp.xml > timestamp.ext-c14n.xml
3) use openssl to get the SHA-1 digest of the file
openssl sha1 timestamp.ext-c14n.xml
4) uudecode the base64 DigestValue of the timestamp reference (jGZkqCNLTnUfbdpoFn19LSYkhts=) and open it with a hex editor
5) the binary value of the DigestValue is different from the sha1 of the canonicalized xml piece.
What am I doing wrong?
Here is the full SOAP Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="uuid-cd1febd3-a76a-4148-8a3e-367aee62293d-1">
<u:Created>2009-11-11T17:37:49.000Z</u:Created>
<u:Expires>2009-11-11T17:42:49.000Z</u:Expires>
</u:Timestamp>
<o:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" u:Id="uuid-ff111e4e-b184-493f-a3a7-1cb85013440a-2">MIIB/TCCAWagAwIBAgIQx9PrVMJZiohOMYoubtFJ4jANBgkqhkiG9w0BAQQFADAVMRMwEQYDVQQDEwpSb290Q0FUZXN0MB4XDTA5MTEwNTE1NTAzN1oXDTM5MTIzMTIzNTk1OVowGTEXMBUGA1UEAxMOdGVtcENlcnRDbGllbnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPXXm8nHsKY7jDaAJ2MVtgj0vd15D4kAFCVrflAGCBDGxku1zVGgTppv8n7i2nJLoXkMpi4HSj9+ci78YMQOKeRq0uIN3AV39hQbjjf5RkV7QY0PYprKYcVKZrWa/LYesI4jYz+ULDnpF7Q2Euk2XFYVLTWPaWU/Zys9K1wNT/n/AgMBAAGjSjBIMEYGA1UdAQQ/MD2AEHNg0Im3hcyQVTxOx1KtRZmhFzAVMRMwEQYDVQQDEwpSb290Q0FUZXN0ghDPzOoIMA8Rkkur9od1bScFMA0GCSqGSIb3DQEBBAUAA4GBAHeTK0GedKo51ZplEfAL+7+NqU5YL9yPhyGqeMUtNBJBJUdbXfvKMZNN+wMHG72boM0HV9jiSKgdjdFDaQ5cLrpLMc48wPs+PPK4KCZynQ/qBCj91w8Vvsprk4EwjGKROGeFhq8FOO8nwukKj1dMCZWELqOPutHjAKgtKpYu4zyt</o:BinarySecurityToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>GFOHIzFb+GV4fj8/sGWx2J5U7ag=</DigestValue>
</Reference>
<Reference URI="#uuid-cd1febd3-a76a-4148-8a3e-367aee62293d-1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>jGZkqCNLTnUfbdpoFn19LSYkhts=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Q6TsGUPlgzfvoh4obnpwTIM5+rG/MynC4Pr8DDkpsClkUBM4+VrR0i7bHdM51779lbLzqj01W1H3GfNehVKxwAi0c0aAKlcVUm0i3PeA2NzmdTPRHy6tHmX2yyLC5TDjhA+jmqRoU/VlWhShD7Komm/9zsyDhQKF4M92rPUo0To=</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference URI="#uuid-ff111e4e-b184-493f-a3a7-1cb85013440a-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"></o:Reference>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
<s:Body u:Id="_1">
<sayHello xmlns="urn:iPhone.Server"></sayHello>
</s:Body>
</s:Envelope>

I removed all the line breaks and spaces between the tags and the digests matched.
The correct XML to use would be:
<u:Timestamp u:Id="uuid-cd1febd3-a76a-4148-8a3e-367aee62293d-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><u:Created>2009-11-11T17:37:49.000Z</u:Created><u:Expires>2009-11-11T17:42:49.000Z</u:Expires></u:Timestamp>

Related

apache fop 2.7 with spring boot 2.7.1 getting failed to generate pdf [duplicate]

I am generating a PDF document with XML file as input using Apache FOP 2.4.
To prevent XXE-Attacks I need to set the secure processing feature (FEATURE_SECURE_PROCESSING) in TransformerFactory:
InputStream xslTransformer = getClass().getClassLoader().getResourceAsStream("foo.xsl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(FEATURE_SECURE_PROCESSING, true);
Transformer transformer = transformerFactory.newTransformer(new StreamSource(xslTransformer));
transformer.transform(new DOMSource(), new SAXResult(fop.getDefaultHandler()));
After setting this feature I can't generate any PDF document and I'm getting warnings:
SystemId Unknown; Line #49; Column #99; "master-name" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "initial-page-number" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "page-height" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "page-width" attribute is not allowed on the fo:simple-page-master element!
etc ...
Here is a section of XSL file (foo.xsl):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-portrait" initial-page-number="1"
page-height="29.7cm" page-width="21.0cm" margin-top="0cm"
margin-left="1cm" margin-right="1.3cm" margin-bottom="0cm">
<fo:region-body margin-top="2.2cm" margin-bottom="1.2cm" margin-left="1.3cm"/>
<fo:region-before region-name="xsl-region-before" extent="2.2cm"/>
<fo:region-after region-name="xsl-region-after" extent="1.2cm"/>
<fo:region-start region-name="xsl-region-start" extent="1.3cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-portrait" font-family="Consolas" font-size="11">
<fo:flow flow-name="xsl-region-body">
<fo:block linefeed-treatment="preserve" font-weight="bold">
foo
</fo:block>
<fo:block linefeed-treatment="preserve">
bar
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
How should I use this feature and make it work? Java version is 8.
This is due to xalan-2.7.2.
Here is the bug in Xalan-J
Switching to xalan-2.7.1 or earlier will solve your problem.
You may have to force exclusions for xalan on an Apache-FO dependency.
You can also overwrite with 2.7.2_3, which patches this problem.
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.xalan</artifactId>
<version>2.7.2_3</version><!--$NO-MVN-MAN-VER$-->
</dependency>
Use of <!--$NO-MVN-MAN-VER$--> prevents overrides.

Mule 3.9 - Unable to fetch xml value using foreach of Xpath3 NODESET

I am unable to retrieve the XML values using the below code snippet in Mule 3.9.5 and it works with the lower versions. I am looking for the solutions in XPath using foreach only not splitter as per my use-case.
Mule flow XML
<foreach collection="#[xpath3('/ParentData/Data', payload, 'NODESET')]">
Sample XML
<ParentData>
<Data>
<test1>value1</test1>
<test2>value2</test2>
</Data>
<Data>
<test1>value1</test1>
<test2>value2</test2>
</Data>
</ParentData>
Actual Output
[]
Expected Output
<Data>
<test1>value1</test1>
<test2>value2</test2>
</Data>
<Data>
<test1>value1</test1>
<test2>value2</test2>
</Data>
Any suggestions ?
Using xpath3() returns a list of nodes of the XML implemented with Java class net.sf.saxon.dom.DOMNodeList. For some reason it doesn't print the details of each node in a <logger>.
I think it is clearer, more intuitive, better documented and portable to future versions of Mule to use DataWeave script instead.
Example:
<dw:transform-message doc:name="Transform Message">
<dw:input-payload mimeType="application/xml" />
<dw:set-variable variableName="data"><![CDATA[
%dw 1.0
%output application/java
---
payload.ParentData.*Data
]]>
</dw:set-variable>
</dw:transform-message>
<foreach collection="#[flowVars.data]" doc:name="For Each">
<logger message="Data=#[payload]" level="INFO" doc:name="Logger"/>
</foreach>
Output:
Data={test1=value1, test2=value2}
Data={test1=value1, test2=value2}
In Mule 4 you can use the DataWeave expression directly in the <foreach>.

Read value from XML within another XML: Mule

I am making a SOAP webservice call and I get the below response. I want to read the value in internal XML, the value is 12345684 in 1234684 in the below XML.
I was able to get internal XML using #[xpath3('//:processaResponse /return[2]')], store it in a flow variable and #[xpath3('/AckReg/DataArea/PRegistration/PRDet/Person/IDSet/:ID[#schemeName="aid"]/text()')].
This works when I try an online parser, but it doesn't read the value in Mule.
Is there any way to extract 1234684 in oa:ID tag using one XPath.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<ns3:TXID xmlns:ns3="http://a.d.r.test.com/"></ns3:TXID>
<ns3:SESSIONID xmlns:ns3="http://a.d.r.test.com/"></ns3:SESSIONID>
</soapenv:Header>
<soapenv:Body>
<ns3:processaResponse xmlns:ns3="http://a.d.r.test.com/" xmlns:ns2="http://p.r.test.com/">
<return>Hi</return>
<return>
<?xml version="1.0" encoding="UTF-8"?>
<AckReg
xmlns="http://www.test.com/e/1" languageCode="en-US" releaseID="normalizedString" systemEnvironmentCode="test" versionID="normalizedString"
xmlns:oa="www.test.com/r/9"
xsi:schemaLocation="http://www.test.com/a/1 ../test/test.xsd">
<Apa>
<oa:CreationDateTime>2018-04-05</oa:CreationDateTime>
</Apa>
<DataArea>
<Ack>
<OArea>
<o:Sender>
<o:LID schemeAgencyName="testi" schemeName="Application ID">test</o:LID>
</o:Sender>
</OArea>
<OriginalActionVerb/>
</Ack>
<PRegistration>
<testids>
<IDSet schemeAgencyName="try">
<oa:ID schemeName="abcid">1234684</oa:ID>
</IDSet>
</testids>
<PRDet>
<Person>
<IDSet schemeAgencyName="try">
<oa:ID schemeName="aid">1364561</oa:ID>
</IDSet>
<IDSet schemeAgencyName="enada">
<oa:ID schemeName="Employee ID">adsad</oa:ID>
</IDSet>
</Person>
<User>
<oa:ID/>
</User>
</PRDet>
</PRegistration>
</DataArea>
</AckReg>
</return>
</ns3:processaResponse>
</soapenv:Body>
</soapenv:Envelope>
In your expressions you were missing namespace prefixes or namespace wildcards *: on some nodes - so your expressions failed.
Is there any way to extract 1234684 in oa:ID tag using one XPath.
Combining both of your partial expressions is possible with namespace wildcards:
//*:processaResponse/return[2]/*:AckReg/*:DataArea/*:PRegistration/*:testids/*:IDSet/*:ID[#schemeName='abcid']/text()
Or you can use an absolute path with namespace wildcards:
/*:Envelope/*:Body/*:processaResponse/return[2]/*:AckReg/*:DataArea/*:PRegistration/*:testids/*:IDSet/*:ID[#schemeName='abcid']/text()
Output in both cases:
1234684
You can even use XmlSlurper class using groovy script to fetch that respective value.
root = new XmlSlurper( false, true).parseText(payload).declareNamespace('soapenv':"http://schemas.xmlsoap.org/soap/envelope/")

Nokogiri XML Searching

I've tried reading the Nokogiri docs, etc, but I've came to a road block.
I get an XML output similar to
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getPoliciesResponse xmlns:ns1="http://policy.api.control.r1soft.com/">
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>bcb68765-a719-4291-912d-2e6af485ea24</diskSafeID>
<enabled>true</enabled>
<id>cdb65427-d6f4-4a89-9f77-8763e22dc74b</id>
<lastReplicationRunTime>2013-06-12T13:29:40.105-05:00</lastReplicationRunTime>
<name>pstueck-passenger ondemand</name>
<replicationScheduleFrequencyType>ON_DEMAND</replicationScheduleFrequencyType>
<state>OK</state>
</return>
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>e8e13555-f577-40d2-99c8-fa8a019d3b55</diskSafeID>
<enabled>true</enabled>
<id>7f55f8d6-92a9-4b14-bff4-631559d92259</id>
<lastReplicationRunTime>2013-06-16T22:00:04.918-05:00</lastReplicationRunTime>
<name>pstueck-mysql daily</name>
<nextReplicationRunTime>2013-06-17T22:00:00-05:00</nextReplicationRunTime>
<replicationScheduleFrequencyType>DAILY</replicationScheduleFrequencyType>
<state>ALERT</state>
<warnings>Policy last completed with alerts</warnings>
</return>
</ns1:getPoliciesResponse>
</soap:Body>
</soap:Envelope>
But I have a large # of 'return' sections that get displayed back. I'm trying to use the .search at the end of string. I'm only wanting it to return the entire 'return' section for a given 'name'. Anyone have any tips?
Current Code:
client = Savon::Client.new do
http.auth.basic "#{opts['api_username']}", "#{opts['api_password']}"
wsdl.document = "#{opts['api_url']}/Policy?wsdl"
end
getPolicyInformation = client.request :getPolicies
getPolicyInformation = Nokogiri::XML(getPolicyInformation.to_xml)
print getPolicyInformation
I'm wanting to return everything in the <return> section if I search for a specified <name>. Example: I only want to see the information relating to <name>pstueck-passenger ondemand</name>, but the entire <return> section that contains that.
You can use XPath to identify a node with a particular value and then specify that an ancestor element is of interest by doing something like the following:
require 'nokogiri'
document = <<-XML
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getPoliciesResponse xmlns:ns1="http://policy.api.control.r1soft.com/">
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>bcb68765-a719-4291-912d-2e6af485ea24</diskSafeID>
<enabled>true</enabled>
<id>cdb65427-d6f4-4a89-9f77-8763e22dc74b</id>
<lastReplicationRunTime>2013-06-12T13:29:40.105-05:00</lastReplicationRunTime>
<name>pstueck-passenger ondemand</name>
<replicationScheduleFrequencyType>ON_DEMAND</replicationScheduleFrequencyType>
<state>OK</state>
</return>
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>e8e13555-f577-40d2-99c8-fa8a019d3b55</diskSafeID>
<enabled>true</enabled>
<id>7f55f8d6-92a9-4b14-bff4-631559d92259</id>
<lastReplicationRunTime>2013-06-16T22:00:04.918-05:00</lastReplicationRunTime>
<name>pstueck-mysql daily</name>
<nextReplicationRunTime>2013-06-17T22:00:00-05:00</nextReplicationRunTime>
<replicationScheduleFrequencyType>DAILY</replicationScheduleFrequencyType>
<state>ALERT</state>
<warnings>Policy last completed with alerts</warnings>
</return>
</ns1:getPoliciesResponse>
</soap:Body>
</soap:Envelope>
XML
doc = Nokogiri::XML(document)
ns = { 'soap' => 'http://schemas.xmlsoap.org/soap/envelope/', 'ns1' => "http://policy.api.control.r1soft.com/" }
ret = doc.xpath('/soap:Envelope/soap:Body/ns1:getPoliciesResponse/return/name[text()="pstueck-passenger ondemand"]/ancestor::return', ns)
puts ret.count
puts ret.at('replicationScheduleFrequencyType').text
EDIT
Updated to reflect updated XML body in question. Now handles namespaces.
Using CSS to find the node:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getPoliciesResponse xmlns:ns1="http://policy.api.control.r1soft.com/">
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>e8e13555-f577-40d2-99c8-fa8a019d3b55</diskSafeID>
<enabled>true</enabled>
<id>7f55f8d6-92a9-4b14-bff4-631559d92259</id>
<lastReplicationRunTime>2013-06-16T22:00:04.918-05:00</lastReplicationRunTime>
<name>pstueck-mysql daily</name>
<nextReplicationRunTime>2013-06-17T22:00:00-05:00</nextReplicationRunTime>
<replicationScheduleFrequencyType>DAILY</replicationScheduleFrequencyType>
<state>ALERT</state>
<warnings>Policy last completed with alerts</warnings>
</return>
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>bcb68765-a719-4291-912d-2e6af485ea24</diskSafeID>
<enabled>true</enabled>
<id>cdb65427-d6f4-4a89-9f77-8763e22dc74b</id>
<lastReplicationRunTime>2013-06-12T13:29:40.105-05:00</lastReplicationRunTime>
<name>pstueck-passenger ondemand</name>
<replicationScheduleFrequencyType>ON_DEMAND</replicationScheduleFrequencyType>
<state>OK</state>
</return>
</ns1:getPoliciesResponse>
</soap:Body>
</soap:Envelope>
EOT
return_tag = doc.at('return name[text()="pstueck-passenger ondemand"]').parent
puts return_tag.to_xml
Which outputs:
<return>
<CDPId>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx</CDPId>
<description/>
<diskSafeID>bcb68765-a719-4291-912d-2e6af485ea24</diskSafeID>
<enabled>true</enabled>
<id>cdb65427-d6f4-4a89-9f77-8763e22dc74b</id>
<lastReplicationRunTime>2013-06-12T13:29:40.105-05:00</lastReplicationRunTime>
<name>pstueck-passenger ondemand</name>
<replicationScheduleFrequencyType>ON_DEMAND</replicationScheduleFrequencyType>
<state>OK</state>
</return>
Nokogiri supports both XPath and CSS. I find CSS easier to read.
I used the at method to find the first matching occurrence, and to show that it was the first matching, I swapped the order of the two <return> blocks. at is the same as search(...).first so when you're looking for the first instance of something in a document at is the way to go.
Nokogiri is usually smart enough to know the difference between XPath and CSS selectors, so we can use the generic at and search. If you need to force CSS or XPath parsing because the selector is gender-unspecific, you can use the specific css or xpath or at_css or at_xpath respectively. They're all documented in the Nokogiri::XML::Node docs.
parent is necessary because we want the parent of the selected node, which was <name>. I just slammed it into reverse and backed up a block. That is easier to do in XPath, where we can use .. to point to the parent node.

SAML Response for Google apps

I am trying to get Google Apps SAML working, I am getting the:
Google Apps - This account cannot be accessed because we could not parse the login request.
Here is my response verbatim:
<?xml version="1.0"?><samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx9c11a3a9-13dc-ff78-7d18-12f795fab19d" Version="2.0" IssueInstant="2011-08-11T05:24:35Z" Destination="https://www.google.com/a/sparxlabs.com/acs" InResponseTo="idnffilcgaeeonionahcpciplkhhhkmlfedkpipl"> <saml:Issuer>http://saml.sparxlabs.com/</saml:Issuer> <ds:Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>Y2E3ZWIyZGEwODFjYjdhZmJjMTZlYmI1NjA4N2IxYzYwMTM5YmEyMA==</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>Eno0HWCgNgxeUhCP0khdEGuLDP3etgzAoKBiK84ENs1ealpgBEOhFTDQQC8qODbAZVxTFYjQLTcW5A7OJ2n02S5tLmg57TeL4+VWyzhwaV9KQ9e1ZU7ZMhPV5aNL4Qm8EIvDyRbPx7mWW70wK1fO+IlPsmxZraL982neOJ8vucc=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNzRENDQWhtZ0F3SUJBZ0lKQUtYZ0tjTy90RktuTUEwR0NTcUdTSWIzRFFFQkJRVUFNRVV4Q3pBSkJnTlYKQkFZVEFrRlZNUk13RVFZRFZRUUlFd3BUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLRXhoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NVEV3T0RFeE1qRXhOelF5V2hjTk1URXdPVEV3TWpFeE56UXlXakJGCk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQk1LVTI5dFpTMVRkR0YwWlRFaE1COEdBMVVFQ2hNWVNXNTAKWlhKdVpYUWdWMmxrWjJsMGN5QlFkSGtnVEhSa01JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQgpnUUMwVTVlVnkxWXJQTXdCNTJvUmk2OFY3cmFWUzR2V1hEd2VQL20wTUwxRkVDL3BUNmxVU01iRUJuWnVranlRClhBOFBrbTkvWFhPcERuU01XN0ZRNXczOUZSeFExY2ZWVXI3dlV6RXNrbm5Sb1p4NXBEck8ybTVVQ25VUFJtNGYKTkljVDRzdERTODAxVzRET24vOEFTUUhKQ1dnTDYwUC9RUGhvU3pmMXVqY1E1UUlEQVFBQm80R25NSUdrTUIwRwpBMVVkRGdRV0JCVDVYbjA1VTdrU3NQbEQyd05yOGlLUTdhQXpYVEIxQmdOVkhTTUViakJzZ0JUNVhuMDVVN2tTCnNQbEQyd05yOGlLUTdhQXpYYUZKcEVjd1JURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdUQ2xOdmJXVXQKVTNSaGRHVXhJVEFmQmdOVkJBb1RHRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpJSUpBS1hnS2NPLwp0RktuTUF3R0ExVWRFd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVGQlFBRGdZRUFzZkYwS0h2T0h6emFoRWd4Cit1NmJJUTRldkxYaXB4VnVYNlZ2RnYxd1BSTmtIRWZEWk9HdmJZc1p1ak5VUVFGdXFzRGR2M3lHelJLQXozRVAKd1RoY29pdEN1cWQrT2dlNGdTNkhpaHBCSzU3cmFaMlpad0NxWXpyQldMMjhaZnFhQW5zNy9KNkY3TEZIeEMvcQpnK25HSldINlVycGpZTGJqajJjMFN0VGVIVTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo></ds:Signature><samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status><saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx9c11a3a9-13dc-ff78-7d18-12f795fab19d" Version="2.0" IssueInstant="2011-08-11T05:24:35Z"> <saml:Issuer>http://saml.sparxlabs.com</saml:Issuer> <ds:Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>ZWRhZGEzYjE4NmZjNWU2ZWE0NDI1NjBkZTFkYzhmN2YzY2QwZGZiMA==</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>QueL4xlp3NOUJou7mIKERgtPRSJboeht9gFfDcOuhmYvh6uyDsk6UR2GLLb0smkuzuy7cgz0MwzjZ4QdhCyIozOyl1TqUqOvISfNV/w0Wx02Sphi0AQJs/R9S9nv+xbVX5dIgjXbf8N/DYgjSMeACSPzpyoeXpHfedY43HsoMZo=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNzRENDQWhtZ0F3SUJBZ0lKQUtYZ0tjTy90RktuTUEwR0NTcUdTSWIzRFFFQkJRVUFNRVV4Q3pBSkJnTlYKQkFZVEFrRlZNUk13RVFZRFZRUUlFd3BUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLRXhoSmJuUmxjbTVsZENCWAphV1JuYVhSeklGQjBlU0JNZEdRd0hoY05NVEV3T0RFeE1qRXhOelF5V2hjTk1URXdPVEV3TWpFeE56UXlXakJGCk1Rc3dDUVlEVlFRR0V3SkJWVEVUTUJFR0ExVUVDQk1LVTI5dFpTMVRkR0YwWlRFaE1COEdBMVVFQ2hNWVNXNTAKWlhKdVpYUWdWMmxrWjJsMGN5QlFkSGtnVEhSa01JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQgpnUUMwVTVlVnkxWXJQTXdCNTJvUmk2OFY3cmFWUzR2V1hEd2VQL20wTUwxRkVDL3BUNmxVU01iRUJuWnVranlRClhBOFBrbTkvWFhPcERuU01XN0ZRNXczOUZSeFExY2ZWVXI3dlV6RXNrbm5Sb1p4NXBEck8ybTVVQ25VUFJtNGYKTkljVDRzdERTODAxVzRET24vOEFTUUhKQ1dnTDYwUC9RUGhvU3pmMXVqY1E1UUlEQVFBQm80R25NSUdrTUIwRwpBMVVkRGdRV0JCVDVYbjA1VTdrU3NQbEQyd05yOGlLUTdhQXpYVEIxQmdOVkhTTUViakJzZ0JUNVhuMDVVN2tTCnNQbEQyd05yOGlLUTdhQXpYYUZKcEVjd1JURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdUQ2xOdmJXVXQKVTNSaGRHVXhJVEFmQmdOVkJBb1RHRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpJSUpBS1hnS2NPLwp0RktuTUF3R0ExVWRFd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVGQlFBRGdZRUFzZkYwS0h2T0h6emFoRWd4Cit1NmJJUTRldkxYaXB4VnVYNlZ2RnYxd1BSTmtIRWZEWk9HdmJZc1p1ak5VUVFGdXFzRGR2M3lHelJLQXozRVAKd1RoY29pdEN1cWQrT2dlNGdTNkhpaHBCSzU3cmFaMlpad0NxWXpyQldMMjhaZnFhQW5zNy9KNkY3TEZIeEMvcQpnK25HSldINlVycGpZTGJqajJjMFN0VGVIVTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo></ds:Signature><saml:Subject> <saml:NameID SPNameQualifier="google.com" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:email">admin</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2011-08-11T06:24:35Z" Recipient="https://www.google.com/a/sparxlabs.com/acs" InResponseTo="idnffilcgaeeonionahcpciplkhhhkmlfedkpipl"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2011-08-11T05:24:35Z" NotOnOrAfter="2011-08-11T06:24:35Z"> <saml:AudienceRestriction> <saml:Audience>google.com</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2011-08-11T05:24:35Z" SessionNotOnOrAfter="2011-08-11T06:24:35Z" SessionIndex="_e409f914997c09cfb1a4dbe461a660209eba5d94ec"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion></samlp:Response>
Some more info that is important:
1.. The X509Certificate I am getting as:
cert = OpenSSL::PKey::RSA.new(File.read("dsacert.pem"))
[cert.to_s].pack("m").gsub(/\n/, "") #Base64 encode
2.. The digest value:
canonical = canonical_form(element)
sha1 = Digest::SHA1.hexdigest(canonical)
[sha1].pack("m").gsub(/\n/, "") #Base64 encode
3.. Finally the signature (digest_value I calculated above):
p key = OpenSSL::PKey::RSA.new(File.read("rsaprivkey.pem"))
sig = pkey.sign(OpenSSL::Digest::SHA1.new, digest_value)
[sig].pack("m").gsub(/\n/, "") #Base64 encode
If I missed anything let me know in the comments I'll update.
Just taking a quick glance I do not believe Google supports signatures on both the Response & Assertion. I would simplify the setup by removing the signature from the Assertion and leave the Response signed as a first step. You may also want to double check the Audience value and see whether "google.com" or "www.google.com/a/sparxlabs.com" is the expected value.
I see some points that may be a problem:
The two Reference ID in your signatures are empty. There is an ambiguity as implicitely
this means that both signature cover the complete XML document,
which is wrong.The SAML specification say that you
should explicitely point to the ID of the signed element.
The code you post seems to suggest that this a custom-made response.
Generating a enveloped XML Digital signature is not that simple as
it needs to be embedded at the exact moment you sign the document.
You only apply the canonization. You should also apply the two
transforms specified in the signature.
As stated there, the Audience element should point to the
EntityID of your ACS, like Ian suggested. It's also possible that
"google.com" is accepted, but this is a violation of the SAML
2.0 specs.
Your NameID attribute seems strange, it should be an email-address.
The previous link gives an example of a valid NameID element.
If you want to generate a custom-made response, you should start from an unsigned template, and then apply the XML DSIG with the ad-hoc library, like XML::Sig. It should be sufficient to sign the Assertion or the Response.
Hope this helps..
all things sk_ pointed out are right, but also :
NEVER include the xml declaration in the samlResponse message
Your digest value is wrong, it should be the base64 of the BINARY digest, not the HEX form
I don't know ruby, but the signature is the same as the digest, b64(BINARY-RSA-SHA1(elem))
It's the canonical form of the whole you have to sign, not just the digest
don't forget to base64 encode the whole samlResponse before sending it over a post-binding
and don't touch a BIT from the relaystate param, just post it as is
Also you may verify yourself the xmldsig signature the (cool-and-life-saver) xmlsec1 tool
And never forget: Xml Sucks, c14n/xmldsig is MORONIC !
GooD Luck !

Resources