Add X509Certificate Tag under KeyInfo Tag Soap Signed Envelope Spring Boot Spring-ws-security and wss4jSecurityInterceptor - soap

Im trying to add X509Certificate, a public key under KeyInfo Tag while Digitally signing a soap enevelope. I have tried many way, still not look. PFB my Code SNIP and the signed envlope generated.
CODE
#Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
cryptoFactoryBean.setKeyStorePassword(Constants.JKS_KEYSTORE_PASSWORD);
cryptoFactoryBean.setKeyStoreLocation(context.getResource("classpath:certificate/api_cert.p12"));
return cryptoFactoryBean;
}
#Bean
public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
securityInterceptor.setSecurementActions("Signature Timestamp");
securityInterceptor.setSecurementTimeToLive(900000);
securityInterceptor.setTimestampPrecisionInMilliseconds(true);
securityInterceptor.setSecurementUsername("api.cert");
securityInterceptor.setSecurementPassword(Constants.JKS_KEYSTORE_PASSWORD);
securityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());
securityInterceptor.setSecurementSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
securityInterceptor.setSecurementSignatureDigestAlgorithm("http://www.w3.org/2001/04/xmlenc#sha256");
securityInterceptor.setSecurementMustUnderstand(false);
securityInterceptor.setSecurementSignatureParts(
"{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body;{Content}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp");
return securityInterceptor;
}
GENERATED SIGNED ENVELOPE SNIP
<ds:KeyInfo Id="KI-1dca42c9-9ff1-463e-a221-cb88577dd3f5">
<wsse:SecurityTokenReference wsu:Id="STR-5c7abb21-666f-40d2-9f43-ec74f40cc35b">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=DigiCert TLS RSA SHA256 2020 CA1,O=DigiCert Inc,C=US</ds:X509IssuerName>
<ds:X509SerialNumber>8989....</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
DESIRED SIGNED ENVELOP SNIP
<KeyInfo>
<X509Data>
<X509Certificate>MIIGpzCCBY+....</X509Certificate>
<X509IssuerSerial>
<X509IssuerName>CN=DigiCert SHA2 Extended Validation Server CA, OU=www.digicert.com, O=DigiCert Inc, C=US</X509IssuerName>
<X509SerialNumber>206281...</X509SerialNumber>
</X509IssuerSerial>
</X509Data>
</KeyInfo>

Related

Verifying Signed Xml Generated From Java In NET

I have the below XML,
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Response xmlns="http://www.site.ae/g">
<Message xml:id="message">
<Header>
<Service>Read</Service>
<Action>SomeAction</Action>
</Header>
<Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SomeDataType">
<Status>Success</Status>
<Data>
<Id>123</Id>
</Data>
</Body>
</Message>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="#message">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>SomeValue</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
SomeValue
</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>
SomeValue
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Response>
The above XML genereted from a java application. The java application team provided us 3 certificate to verify the above xml. I have created 3 objects in C#,
var clientCert = new X509Certificate2("clientCert.cer");
var intermediateCert = new X509Certificate2("intermediateCert.cer");
var rootCert = new X509Certificate2("rootCert.cer");
One is root, second one is intermediate and third one is certificate. I have created the below code,
var xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("above.xml");
bool result = VerifyXml(xmlDoc, clientCert);
private static Boolean VerifyXml(XmlDocument Doc, X509Certificate2 Key)
{
// Create a new SignedXml object and pass it
// the XML document class.
var signedXml = new System.Security.Cryptography.Xml.SignedXml(Doc);
// Find the "Signature" node and create a new XmlNodeList object.
XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");
// Throw an exception if no signature was found.
if (nodeList.Count <= 0)
{
throw new CryptographicException("Verification failed: No Signature was found in the document.");
}
// Though it is possible to have multiple signatures on
// an XML document, this app only supports one signature for
// the entire XML document. Throw an exception
// if more than one signature was found.
if (nodeList.Count >= 2)
{
throw new CryptographicException("Verification failed: More that one signature was found for the document.");
}
// Load the first <signature> node.
signedXml.LoadXml((XmlElement)nodeList[0]);
// Check the signature and return the result.
return signedXml.CheckSignature(Key, true);
}
But the above code result is always return false. Is there is something I am missing? Is .NET support verifying the xml generated from java?
Got Answer from
Verify SignatureValue And DigestValue Using Sha256 RSA

JSESSIONIDSSO cookie is not getting written upon login

I have a number of applications currently running on Wildfly 10 and using the Picketbox security system with SSO. I am currently upgrading to Wildfly 17 and have converted the security configuration to use the Elytron subsystem, but am having issues getting the SSO cookie to write. I am not upgrading to the JEE8 security APIs.
One of the apps ("app1") being migrated is quite simple, using stock standard form posts via a login-config section in web.xml. This app works correctly: I get the login form, submit my credentials, and the response includes the JSESSIONIDSSO cookie. A second app ("app2") is implemented a bit differently. It also uses login-config but the login page submits to a custom servlet which logs in programmatically using HttpServletRequest.login(username, password). When I submit my credentials in this app they are authenticated correctly but no JSESSIONIDSSO cookie is written.
Wildfly Config
(it's originally set up for AD, but is temporarily set to read users from a file for simpler testing)
<subsystem ...>
...
<application-security-domains>
<application-security-domain name="active-directory" http-authentication-factory="ad-http-auth">
<single-sign-on domain="localhost" key-store="sso-ad-keystore" key-alias="localhost">
<credential-reference clear-text="ssopass"/>
</single-sign-on>
</application-security-domain>
</application-security-domains>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:7.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<security-domains>
...
<security-domain name="LocalFileDomain" default-realm="LocalFileRealm" permission-mapper="default-permission-mapper">
<realm name="LocalFileRealm"/>
</security-domain>
</security-domains>
<security-realms>
...
<filesystem-realm name="LocalFileRealm">
<file path="fs-realm-users" relative-to="jboss.server.config.dir"/>
</filesystem-realm>
</security-realms>
<http>
...
<http-authentication-factory name="ad-http-auth" security-domain="LocalFileDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="FORM">
<mechanism-realm realm-name="active-directory"/>
</mechanism>
<mechanism mechanism-name="BASIC">
<mechanism-realm realm-name="active-directory"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
</subsystem>
App1
<login-config>
<auth-method>BASIC?silent=true,FORM</auth-method>
<realm-name>App Realm</realm-name>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/noAccess.html</form-error-page>
</form-login-config>
</login-config>
<form action="j_security_check" method="post">
Username: <input name="j_username" type="text"/>
Password: <input name="j_password" type="password"/>
<input type="submit"/>
</form>
App2
<login-config>
<auth-method>BASIC?silent=true,FORM</auth-method>
<realm-name>App Realm</realm-name>
<form-login-config>
<form-login-page>/login</form-login-page>
<form-error-page>/login</form-error-page>
</form-login-config>
</login-config>
Login form uses Angular to post to the login servlet, which looks like this:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (req.getUserPrincipal() == null) {
String username = req.getParameter(USERNAME_FIELD);
String password = req.getParameter(PASSWORD_FIELD);
if (username == null || password == null) {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
return;
}
try {
Person person = this.personRepository.findByLogin(username);
if (person != null) {
req.login(username, password);
req.authenticate(resp); // I've tried with and without this line
setResponseStatusAndOutput(LoginResultStatus.SUCCESS, resp);
} else {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
}
} catch (ServletException ex) {
setResponseStatusAndOutput(LoginResultStatus.UNAUTHORISED, resp);
}
} else {
setResponseStatusAndOutput(LoginResultStatus.SUCCESS, resp);
}
}
private void setResponseStatusAndOutput(LoginResultStatus loginResultStatus, HttpServletResponse response) throws IOException {
response.setContentType("application/json");
response.setStatus(loginResultStatus.getCode());
response.getOutputStream().print(String.format("{ \"status\": \"%s\" }", loginResultStatus.getValue()));
}
Does Undertow not apply the SSO stuff to requests that are authenticated this way, maybe because I've missed the spot in the filter chain where it's set? Or is there something else I'm not doing right?
Edit 1: I've done some more testing to try and narrow down the issue.
Wildfly 17 Elytron, posting to j_security_check: Logs in OK, writes the JSESSIONIDSSO cookie.
Wildfly 17 Elytron, posting to custom login servlet: Logs in OK, does not write the JSESSIONIDSSO cookie.
Wildfly 10 Legacy, posting to j_security_check: Logs in OK, writes the JSESSIONIDSSO cookie.
Wildfly 10 Legacy, posting to custom login servlet: Logs in OK, writes the JSESSIONIDSSO cookie.
I've created a test project to demonstrate this, which includes the config files for Wildfly 10 and 17.

Digital Signature Verification failed using SHA256withRSA in Python [duplicate]

This question already has answers here:
Digital Signature Verification failed using SHA256withRSA in Python
(3 answers)
Closed 4 years ago.
I am trying to validate the digital signature with given certificate files for the offline aadhaar KYC verification application.
This instruction is given in the documentation for the verification.
Aadhaar Paperless Offline e-KYC when downloaded has the following XML :
<OKY v=""n=""r=""i=""d=""e=""m=""g=""a=""s="" />
XSD for the above xml
<?xml version="1.0" encoding="UTF-8"?>
<xs:schemaxmlns:xs="http: www.w3.org="" 2001="" xmlschema"="" attributeformdefault="unqualified" elementformdefault="qualified" targetnamespace="http://www.uidai.gov.in/offlinePaperlesseKYC/1.0">
<xs:element name="OKY">
<xs:complextype>
<xs:attribute name="v" type="xs:string"/>
<xs:attribute name="n" type="xs:string"/>
<xs:attribute name="i" type="xs:string"/>
<xs:attribute name="d" type="xs:string"/>
<xs:attribute name="e" type="xs:string"/>
<xs:attribute name="m" type="xs:string"/>
<xs:attribute name="g" type="xs:string"/>
<xs:attribute name="a" type="xs:string"/>
<xs:attribute name="r" type="xs:string"/>
<xs:attribute name="s" type="xs:string"/>
</xs:complextype>
</xs:element>
</xs:schema>
Read the entire XML and separate the s=”xxxx” tag from it.
Use a signature validation algorithm leveraging “SHA256withRSA” based hashing and encryption technique
Signature value present in “s” tag, remaining XML (without "s" tag) and UIDAI public key (available here.) is to be fed to the algorithm to validate the digital signature.
Sample C# code snippets provided by the organization. (PS :which is also not working)
using System;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
namespace test
{
class MainClass
{
public static void Main(string[] args)
{
// link -> https://drive.google.com/file/d/1aSv3HJUFf5_42Z-FqpdVHEk5b3VA3T3D/view
string XMLFilePath = "offlineaadhaar.xml"; //Get the XML file
// link -> https://drive.google.com/file/d/1FW4ciIhZqJuelOcGF2x6VaBCSDO9J-gM/view
string KeyFilePath = "okyc-publickey.cer"; //Get the public key certificate file
XmlDocument ObjXmlDocument = new XmlDocument();
ObjXmlDocument.Load(XMLFilePath); //Load the XML
XmlAttributeCollection SignatureElement = ObjXmlDocument.DocumentElement.Attributes; //Get the all XML attribute
string SignatureValue = SignatureElement.GetNamedItem("s").InnerXml; // Get Signature value
SignatureElement.RemoveNamedItem("s");//Remove the signature "s" attribute from XML and get the new XML to validate
/*----------------Read and parse the public key as string-----------------------*/
X509Certificate2 ObjX509Certificate2 = new X509Certificate2(KeyFilePath, "public"); //Initialize the public ket certificate file
Org.BouncyCastle.X509.X509Certificate objX509Certificate;
Org.BouncyCastle.X509.X509CertificateParser objX509CertificateParser = new Org.BouncyCastle.X509.X509CertificateParser();
objX509Certificate = objX509CertificateParser.ReadCertificate(ObjX509Certificate2.GetRawCertData());
/*----------------End-----------------------*/
/* Init alg */
Org.BouncyCastle.Crypto.ISigner signer = Org.BouncyCastle.Security.SignerUtilities.GetSigner("SHA256withRSA");
/* Populate key */
signer.Init(false, objX509Certificate.GetPublicKey());
/* Get the signature into bytes */
var expectedSig = Convert.FromBase64String(SignatureValue);
/* Get the bytes to be signed from the string */
var msgBytes = System.Text.Encoding.UTF8.GetBytes(ObjXmlDocument.InnerXml);
/* Calculate the signature and see if it matches */
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
bool Flag = signer.VerifySignature(expectedSig);
if (Flag)
{
Console.WriteLine("XML Validate Successfully");
}
else
{
Console.WriteLine("XML Validation Failed");
}
}
}
}
I am trying to implement in Python and getting the XML validation failed. I am not sure if the certificate file is wrong or there is some bug on my code.
Here is my Python Code :
import xml
import xml.etree.cElementTree as etree
from xml.etree import ElementTree
import OpenSSL
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from Crypto.PublicKey import RSA
from base64 import b64encode, b64decode
from M2Crypto import BIO, RSA, EVP
xmlDoc = open('adhar.xml', 'r').read()
Tr = etree.XML(xmlDoc)
Tr.keys()
# ['s', 'r', 'a', 'g', 'm', 'e', 'd', 'i', 'n', 'v']
sign = Tr.get('s')
len(sign)
# 344
del Tr.attrib['s']
from M2Crypto import X509
x509 =X509.load_cert('ekyc_public_key.cer')
#x509 =X509.load_cert(cert4)
rsa = x509.get_pubkey().get_rsa()
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
xmlstr = etree.tostring(Tr, encoding='utf8', method='xml')
#rstr=str(xmlstr)[45:][:-1]
#rstr = rstr.encode(encoding='utf-8')
# if you need a different digest than the default 'sha1':
pubkey.reset_context(md='sha256')
pubkey.verify_init()
# hashlib.sha256(message_without_sign).digest()
pubkey.verify_update(xmlstr)
if(pubkey.verify_final(b64decode(sign)) != 1):
print('Digital Signeture not validated')
else:
print('Digital Signeture validated')
The description in the question is not enough to completely specify signature generation / verification. Clarification of the protocol is certainly required; it's probably best to request a formalized description. It's not for nothing that XML digsig has been specified; you need a standardized canonicalization, character set etc. In the end, the signature is calculated over bytes, not over XML / text.
"SHA256withRSA" is not a signature algorithm; it's the (rather bad) Java name for the PKCS#1 v1.5 signature scheme.
These are not good signs; you should ask if the protocol has been verified by an expert.

" Message: Security error." While Requesting a Https Uri using WebClient OR HttpWebRequest using SilverLight Client

My Silverlight Client and REST Web Server(Implented using ASP.NET Handlers) both are on same domain.
Both HTTP and HTTPS protocol bindings are configured in IIS 7.0
When Request a URI using HTTPS , i Get Error " Message: "Security error."
But Same URI works just fine on HTTP request without any error
private void btnLoginWebRequest_Click(object sender, RoutedEventArgs e)
{
bool httpResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
bool httpsResult = WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
this.Dispatcher.BeginInvoke(()=>
{
WebClient webClient = new WebClient();
webClient.Headers["CustomHeader"] = String.Format("myHeaders={0}", "Value");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri(#"https://xxx.xx.xxx.xxx/MyRESTApi/UserGroups"));
});
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
}
}
I Get a Error and e.Error contains the following Error information
{System.Security.SecurityException: Security error.
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.OpenReadAsyncCallback(IAsyncResult result)}
[System.Security.SecurityException]: {System.Security.SecurityException: Security error.
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)
at System.Net.WebClient.OpenReadAsyncCallback(IAsyncResult result)}
Data: {System.Collections.ListDictionaryInternal}
InnerException: null
Message: "Security error."
StackTrace: " at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)\r\n at System.Net.WebClient.OpenReadAsyncCallback(IAsyncResult result)"
crossdomain.xml is as follows :-
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" secure="true"/>
<allow-http-request-headers-from domain="*" headers="*" secure="true"/>
</cross-domain-policy>
clientaccesspolicy.xml is as follows :-
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="https://"/>
<domain uri="http://"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
I Have seen many threads related to similar error on stack overflow but not able to resolve this issue by any of the solutions provided in those threads. Am i missing something?

What is the correct format for SAML 2.0 Assertions?

We have a customer trying to use ADFS to SSO on to our web application. We are using the ComponentSpace SAML 2.0 library. The assertion being sent to us looks like:
<Assertion ID="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889" IssueInstant="2012-05-24T13:30:33.917Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<Issuer>http://example.com/adfs/services/trust</Issuer>
<Subject>
<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">mail#example.com</NameID>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<SubjectConfirmationData NotOnOrAfter="2012-05-24T13:35:33.920Z" Recipient="https://example.com/default.aspx" />
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="2012-05-24T13:30:33.907Z" NotOnOrAfter="2012-05-24T14:30:33.907Z">
<AudienceRestriction>
<Audience>https://example.com</Audience>
</AudienceRestriction>
</Conditions>
<AttributeStatement>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
<AttributeValue>mail#example.com</AttributeValue>
</Attribute>
</AttributeStatement>
<AuthnStatement AuthnInstant="2012-05-24T13:30:33.756Z" SessionIndex="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889">
<AuthnContext>
<AuthnContextClassRef>urn:federation:authentication:windows</AuthnContextClassRef>
</AuthnContext>
</AuthnStatement>
</Assertion>
The ComponentSpace library is pulling the full SamlResponse from the HTTP post but it reports no Assertions (ie samlResponse.GetAssertions().Count == 0). If I use the ComponentSpace examples it works but I notice all of the elements I build with the ComponentSpace library are prefixed with "saml:" (as I believe it should be).
Should the ComponentSpace library be able to find the Assertion without the saml: prefix or is there a way to configure ADFS to send it correctly?
A correct SAML response should contain namespace-qualified elements
<saml2p:Response Destination="https://www.google.com/a/squaresquare.biz/acs" IssueInstant="2010-08-04T17:47:20.956Z" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Version="2.0" ID="_bd24b4a3514fd93800d2a43cafc98edb">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/idp/shibboleth</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#_bd24b4a3514fd93800d2a43cafc98edb">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="dssaml2saml2p"></ec:InclusiveNamespaces>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>m/lUCS3nvfGuSJFKAtIz+ZrfxTU=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>PLdYgU9u5KirVrMHNSwYvk6fQ401dMbpuiDXpapKf0eOKC6pN3g7tnTEzvfOaXhkDNXVmGN+lXQ6iUDppWpdO2MbvPVZabOBPU1aAO+CWI53ciC0rYsxpFzQLLMC/7x9Wk7VFFmYEecxAJV+lTWvp8ZKXvwqZbhiTO/23EC0xconGhnwSvKjJWQuLnMMaFWSjDFYyzgsp34cR7aX/eqhhJyA/rr2uFdmgEdagAl+/17ppgHgthgK+PJtX16AALtsoXonv6uybRCX/YiDRvM1VsdwusVq5tXh9V+bTMZcgi/3Eh+Em/OZp0En8pqOngvL19U4LfqG0yJZjoDGkpHuhA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDgjCCAmqgAwIBAgIVAKgIqbzZl7+0p2qjxJFVJs3DE/jxMA0GCSqGSIb3DQEBBQUAMDAxLjAsBgNVBAMTJWh0dHA6Ly93cGgtdWJpcTI3LmhvdC5jb3JwLmdvb2dsZS5jb20wHhcNMTAwNzIxMTcxNTA5WhcNMzAwNzIxMTcxNTA5WjAwMS4wLAYDVQQDEyVodHRwOi8vd3BoLXViaXEyNy5ob3QuY29ycC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAioQsJycRmjPjB2xlH0iSGn14lNbO/jIVgiGIlzZwlPkH1s2TTdwoTKKQBSe2s8AnJ4LliXlne/qWun3peYht0+RhejtB20L+Bw/I+iKQBGpHzgIKdkPGZnemWl9KqWQ/ZYKnY2x6qMEBmhUfYZcawzs26em5a+iaYlrTJNVEZ+QwWvg2/EOJvJNyBkSfXyxia5eAHV38Uy7xn0G5Zc9ge4ckCYj6b8a/UxpPJM61KztzY5coDwReQsDBq+DciGALJPbFk4783TW...etc.etc</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></saml2p:StatusCode>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2010-08-04T17:47:20.956Z" ID="_73fe28bcbb68e93df954d8e2f25097b1">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/idp/shibboleth</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">my_username</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2010-08-04T17:52:20.956Z" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Recipient="https://www.google.com/a/squaresquare.biz/acs" Address="172.24.6.38"></saml2:SubjectConfirmationData>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotOnOrAfter="2010-08-04T17:52:20.956Z" NotBefore="2010-08-04T17:47:20.956Z">
<saml2:AudienceRestriction>
<saml2:Audience>google.com</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement SessionIndex="f306dd2bff4e9b3ba9218bd70fbaa87404d38a4c79547ac1edc9436a9f222213" AuthnInstant="2010-08-04T17:47:20.953Z">
<saml2:SubjectLocality Address="172.24.6.38"></saml2:SubjectLocality>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>
Namespace qualifications are optional.
It turns out that the above XML is valid (ADFS adds the namespace to the overall XML but not each element). The problem was that the ComponentSpace library has different methods for getting Signed or Encrypted Assertions and I was just calling the generic GetAssertions. ADFS was generating signed assertions and I needed to call the other function.
Here is the code we ended up with:
IList<EncryptedAssertion> encryptedAssertions = samlResponse.GetEncryptedAssertions();
if (encryptedAssertions.Count > 0 && x509Certificate != null) {
// Decrypt the assertion
EncryptedAssertion encryptedAssertion = encryptedAssertions[0];
XmlElement decryptedElement = encryptedAssertion.DecryptToXml(x509Certificate, null);
LogMessage("Decrypted assertion: " + decryptedElement.OuterXml);
// Then verify the signature.
VerifySignature(x509Certificate, decryptedElement);
samlAssertion = new SAMLAssertion(decryptedElement);
} else {
if (samlResponse.GetSignedAssertions().Count > 0) {
// Get the signed assertion and verify the signature.
XmlElement signedAssertionElement = samlResponse.GetSignedAssertions()[0];
LogMessage("Signed assertion: " + signedAssertionElement.OuterXml);
VerifySignature(x509Certificate, signedAssertionElement);
samlAssertion = new SAMLAssertion(signedAssertionElement);
} else {
// Assertion is not encrypted or signed.
if (samlResponse.GetAssertions().Count > 0) {
samlAssertion = samlResponse.GetAssertions()[0];
LogMessage("Assertion: " + samlAssertion.ToXml().OuterXml);
} else {
LogFatalError("No assertions in response");
}
}
}