Como analisar uma solicitação de declaração SAML em .Net
-
09-09-2020 - |
Pergunta
Estou tentando implementar uma solução SAML SSO em .Net, mas estou tendo problemas ao analisar a afirmação.
Eu tenho um exemplo de afirmação (parece byte[]
dados como texto) e correspondente .p7b
arquivo.
Quero carregar as chaves do .p7b
e descriptografar a afirmação em um documento XML.
Até agora acho que estou lendo as chaves corretamente:
// get the key data
byte[] certificateData = System.IO.File.ReadAllBytes("myKeys.p7b");
// decode the keys
var cms = new SignedCms(SubjectIdentifierType.IssuerAndSerialNumber);
cms.Decode(certificateData);
var samlCertificates = cms.Certificates;
Então tento analisar a afirmação e tenho um problema:
// we have a keychain of X509Certificate2s, we need a collection of tokens
var certificatesAsTokens =
from X509Certificate2 cert in samlCertificates
select new X509SecurityToken(cert) as SecurityToken;
// get a token resolver
var tokens = new ReadOnlyCollection<SecurityToken>(
certificatesAsTokens.ToList());
var resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(
tokens, true);
// get the SAML data in an XML reader
var reader = XmlReader.Create(assertionPostStream);
// use the WS Security stuff to parse the reader
var securityToken = WSSecurityTokenSerializer.
DefaultInstance.ReadToken(reader, resolver) as SamlSecurityToken;
Essa última instrução lança uma exceção, informando que não é possível analisar o conteúdo XML.
Acho que isso significa que estou perdendo uma etapa ao descriptografar a afirmação - obter o byte[]
como texto convertido em um documento XML no formato SAML.
Alguém sabe como adicionar esta etapa?Estou sentindo falta de mais alguma coisa?
Solução
Eu descobri isso - estava faltando parte da especificação SAML.
A afirmação é enviada (de forma bastante estranha, já que não é criptografada) como dados base64 e estava sendo codificada em URL duas vezes ao ser enviada.
Portanto, adicionar esta etapa nos dá uma afirmação válida:
// spec says "SAMLResponse="
string rawSamlData = Request["SAMLResponse"];
// the sample data sent us may be already encoded,
// which results in double encoding
if (rawSamlData.Contains('%'))
{
rawSamlData = HttpUtility.UrlDecode(rawSamlData);
}
// read the base64 encoded bytes
byte[] samlData = Convert.FromBase64String(rawSamlData);
// read back into a UTF string
string samlAssertion = Encoding.UTF8.GetString(samlData);
O a autenticação ainda não está funcionando, mas agora tenho XML válido, então é um problema diferente.