in wwauth/Google.Solutions.WWAuth/Data/Saml2/AuthenticationResponse.cs [63:169]
public static AuthenticationResponse Parse(string encodedResponse)
{
try
{
var xml = Encoding.UTF8.GetString(
Convert.FromBase64String(encodedResponse));
var deserializer = new XmlSerializer(typeof(Saml2Schema.Response));
var response = (Saml2Schema.Response)deserializer.Deserialize(
new StringReader(xml));
if (response.Version != "2.0")
{
throw new InvalidSamlResponseException(
"Unsupported SAML version");
}
else if (string.IsNullOrEmpty(response.ID))
{
throw new InvalidSamlResponseException(
"Malformed SAML response: Missing required attribute: ID");
}
else if (string.IsNullOrEmpty(response.Issuer))
{
throw new InvalidSamlResponseException(
"Malformed SAML response: Missing required attribute: Issuer");
}
else if (response.IssueInstant == DateTime.MinValue)
{
throw new InvalidSamlResponseException(
"Malformed SAML response: Missing required attribute: IssueInstant");
}
else if (string.IsNullOrEmpty(response.Destination))
{
throw new InvalidSamlResponseException(
"Malformed SAML response: Missing required attribute: Destination");
}
else if (response.Status?.StatusCode?.Value == "urn:oasis:names:tc:SAML:2.0:status:Responder" &&
string.IsNullOrEmpty(response.Status?.StatusMessage) &&
string.IsNullOrEmpty(response.Status.StatusCode?.StatusCode?.Value))
{
throw new InvalidSamlResponseException(
$"Server rejected request, possible because of mismatched signing settings");
}
else if (response.Status?.StatusCode?.Value !=
"urn:oasis:names:tc:SAML:2.0:status:Success")
{
throw new InvalidSamlResponseException(
$"Request failed with status code {response.Status?.StatusCode?.Value}\n\n" +
$"Details: {response.Status?.StatusMessage ?? "-"}\n" +
$"Detail status code {response.Status.StatusCode?.StatusCode?.Value ?? "-"}");
}
//
// There should be either an <Assertion/> or <EncryptedAssertion/> element,
// but we don't know which.
//
var assertionElement = response.Assertion
.EnsureNotNull()
.FirstOrDefault(n => n.NamespaceURI == "urn:oasis:names:tc:SAML:2.0:assertion");
switch (assertionElement.Name)
{
case "Assertion":
//
// Response contains non-encrypted assertion. We can parse
// this to extract attributes, etc.
//
using (var assertionReader = new XmlNodeReader(assertionElement))
{
var tokenHandler = new Saml2SecurityTokenHandler()
{
Configuration = new SecurityTokenHandlerConfiguration()
};
tokenHandler.Configuration.CertificateValidationMode =
System.ServiceModel.Security.X509CertificateValidationMode.None;
var assertion = new Assertion(
(Saml2SecurityToken)tokenHandler.ReadToken(assertionReader),
null);
return new Saml2ResponseWithPlaintextAssertion(
encodedResponse,
assertion);
}
case "EncryptedAssertion":
//
// Response contains an encrypted assertion. We can't do
// much with that.
//
return new Saml2ResponseWithEncryptedAssertion(
response.Issuer,
encodedResponse);
default:
throw new InvalidSamlResponseException(
$"SAML Response does not contain an assertion: {assertionElement}");
}
}
catch (InvalidOperationException e)
{
throw new InvalidSamlResponseException("Failed to parse SAML respose", e);
}
}