Пример #1
0
        /// <summary>
        /// Get the IdP Logout Response and extract metadata to the returned DTO class
        /// </summary>
        /// <param name="base64Response"></param>
        /// <returns></returns>
        public static IdpLogoutResponse GetLogoutResponse(string base64Response)
        {
            const string VALUE_NOT_AVAILABLE = "N/A";
            string       idpResponse;

            if (String.IsNullOrEmpty(base64Response))
            {
                throw new ArgumentNullException("The base64Response parameter can't be null or empty.");
            }

            try
            {
                idpResponse = Encoding.UTF8.GetString(Convert.FromBase64String(base64Response));
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Unable to converto base64 response to ascii string.", ex);
            }

            try
            {
                // Verify signature
                XmlDocument xml = new XmlDocument {
                    PreserveWhitespace = true
                };
                xml.LoadXml(idpResponse);
                if (!XmlSigningHelper.VerifySignature(xml))
                {
                    throw new Exception("Unable to verify the signature of the IdP response.");
                }

                // Parse XML document
                XDocument xdoc = new XDocument();
                xdoc = XDocument.Parse(idpResponse);

                string         destination          = VALUE_NOT_AVAILABLE;
                string         id                   = VALUE_NOT_AVAILABLE;
                string         inResponseTo         = VALUE_NOT_AVAILABLE;
                DateTimeOffset issueInstant         = DateTimeOffset.MinValue;
                string         version              = VALUE_NOT_AVAILABLE;
                string         statusCodeValue      = VALUE_NOT_AVAILABLE;
                string         statusCodeInnerValue = VALUE_NOT_AVAILABLE;
                string         statusMessage        = VALUE_NOT_AVAILABLE;
                string         statusDetail         = VALUE_NOT_AVAILABLE;

                // Extract response metadata
                XElement responseElement = xdoc.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}LogoutResponse").Single();
                destination  = responseElement.Attribute("Destination").Value;
                id           = responseElement.Attribute("ID").Value;
                inResponseTo = responseElement.Attribute("InResponseTo").Value;
                issueInstant = DateTimeOffset.Parse(responseElement.Attribute("IssueInstant").Value);
                version      = responseElement.Attribute("Version").Value;

                // Extract Issuer metadata
                string issuer = responseElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Issuer").Single().Value.Trim();

                // Extract Status metadata
                XElement StatusElement = responseElement.Descendants("{urn:oasis:names:tc:SAML:2.0:protocol}Status").Single();
                IEnumerable <XElement> statusCodeElements = StatusElement.Descendants("{urn:oasis:names:tc:SAML:2.0:protocol}StatusCode");
                statusCodeValue      = statusCodeElements.First().Attribute("Value").Value.Replace("urn:oasis:names:tc:SAML:2.0:status:", "");
                statusCodeInnerValue = statusCodeElements.Count() > 1 ? statusCodeElements.Last().Attribute("Value").Value.Replace("urn:oasis:names:tc:SAML:2.0:status:", "") : VALUE_NOT_AVAILABLE;
                statusMessage        = StatusElement.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}StatusMessage").SingleOrDefault()?.Value ?? VALUE_NOT_AVAILABLE;
                statusDetail         = StatusElement.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}StatusDetail").SingleOrDefault()?.Value ?? VALUE_NOT_AVAILABLE;

                return(new IdpLogoutResponse(destination, id, inResponseTo, issueInstant, version, issuer,
                                             statusCodeValue, statusCodeInnerValue, statusMessage, statusDetail));
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Unable to read AttributeStatement attributes from SAML2 document.", ex);
            }
        }
Пример #2
0
        /// <summary>
        /// Get the IdP Authn Response and extract metadata to the returned DTO class
        /// </summary>
        /// <param name="base64Response"></param>
        /// <returns>IdpSaml2Response</returns>
        public static IdpAuthnResponse GetAuthnResponse(string base64Response)
        {
            const string VALUE_NOT_AVAILABLE = "N/A";
            string       idpResponse;

            if (String.IsNullOrEmpty(base64Response))
            {
                throw new ArgumentNullException("The base64Response parameter can't be null or empty.");
            }

            try
            {
                idpResponse = Encoding.UTF8.GetString(Convert.FromBase64String(base64Response));
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Unable to converto base64 response to ascii string.", ex);
            }

            try
            {
                // Verify signature
                XmlDocument xml = new XmlDocument {
                    PreserveWhitespace = true
                };
                xml.LoadXml(idpResponse);
                if (!XmlSigningHelper.VerifySignature(xml))
                {
                    throw new Exception("Unable to verify the signature of the IdP response.");
                }

                // Parse XML document
                XDocument xdoc = new XDocument();
                xdoc = XDocument.Parse(idpResponse);

                string         destination                         = VALUE_NOT_AVAILABLE;
                string         id                                  = VALUE_NOT_AVAILABLE;
                string         inResponseTo                        = VALUE_NOT_AVAILABLE;
                DateTimeOffset issueInstant                        = DateTimeOffset.MinValue;
                string         version                             = VALUE_NOT_AVAILABLE;
                string         statusCodeValue                     = VALUE_NOT_AVAILABLE;
                string         statusCodeInnerValue                = VALUE_NOT_AVAILABLE;
                string         statusMessage                       = VALUE_NOT_AVAILABLE;
                string         statusDetail                        = VALUE_NOT_AVAILABLE;
                string         assertionId                         = VALUE_NOT_AVAILABLE;
                DateTimeOffset assertionIssueInstant               = DateTimeOffset.MinValue;
                string         assertionVersion                    = VALUE_NOT_AVAILABLE;
                string         assertionIssuer                     = VALUE_NOT_AVAILABLE;
                string         subjectNameId                       = VALUE_NOT_AVAILABLE;
                string         subjectConfirmationMethod           = VALUE_NOT_AVAILABLE;
                string         subjectConfirmationDataInResponseTo = VALUE_NOT_AVAILABLE;
                DateTimeOffset subjectConfirmationDataNotOnOrAfter = DateTimeOffset.MinValue;
                string         subjectConfirmationDataRecipient    = VALUE_NOT_AVAILABLE;
                DateTimeOffset conditionsNotBefore                 = DateTimeOffset.MinValue;
                DateTimeOffset conditionsNotOnOrAfter              = DateTimeOffset.MinValue;
                string         audience                            = VALUE_NOT_AVAILABLE;
                DateTimeOffset authnStatementAuthnInstant          = DateTimeOffset.MinValue;
                string         authnStatementSessionIndex          = VALUE_NOT_AVAILABLE;
                Dictionary <string, string> spidUserInfo           = new Dictionary <string, string>();

                // Extract response metadata
                XElement responseElement = xdoc.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}Response").Single();
                destination  = responseElement.Attribute("Destination").Value;
                id           = responseElement.Attribute("ID").Value;
                inResponseTo = responseElement.Attribute("InResponseTo").Value;
                issueInstant = DateTimeOffset.Parse(responseElement.Attribute("IssueInstant").Value);
                version      = responseElement.Attribute("Version").Value;

                // Extract Issuer metadata
                string issuer = responseElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Issuer").Single().Value.Trim();

                // Extract Status metadata
                XElement StatusElement = responseElement.Descendants("{urn:oasis:names:tc:SAML:2.0:protocol}Status").Single();
                IEnumerable <XElement> statusCodeElements = StatusElement.Descendants("{urn:oasis:names:tc:SAML:2.0:protocol}StatusCode");
                statusCodeValue      = statusCodeElements.First().Attribute("Value").Value.Replace("urn:oasis:names:tc:SAML:2.0:status:", "");
                statusCodeInnerValue = statusCodeElements.Count() > 1 ? statusCodeElements.Last().Attribute("Value").Value.Replace("urn:oasis:names:tc:SAML:2.0:status:", "") : VALUE_NOT_AVAILABLE;
                statusMessage        = StatusElement.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}StatusMessage").SingleOrDefault()?.Value ?? VALUE_NOT_AVAILABLE;
                statusDetail         = StatusElement.Elements("{urn:oasis:names:tc:SAML:2.0:protocol}StatusDetail").SingleOrDefault()?.Value ?? VALUE_NOT_AVAILABLE;

                if (statusCodeValue == "Success")
                {
                    // Extract Assertion metadata
                    XElement assertionElement = responseElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Assertion").Single();
                    assertionId           = assertionElement.Attribute("ID").Value;
                    assertionIssueInstant = DateTimeOffset.Parse(assertionElement.Attribute("IssueInstant").Value);
                    assertionVersion      = assertionElement.Attribute("Version").Value;
                    assertionIssuer       = assertionElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Issuer").Single().Value.Trim();

                    // Extract Subject metadata
                    XElement subjectElement = assertionElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Subject").Single();
                    subjectNameId             = subjectElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}NameID").Single().Value.Trim();
                    subjectConfirmationMethod = subjectElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}SubjectConfirmation").Single().Attribute("Method").Value;
                    XElement confirmationDataElement = subjectElement.Descendants("{urn:oasis:names:tc:SAML:2.0:assertion}SubjectConfirmationData").Single();
                    subjectConfirmationDataInResponseTo = confirmationDataElement.Attribute("InResponseTo").Value;
                    subjectConfirmationDataNotOnOrAfter = DateTimeOffset.Parse(confirmationDataElement.Attribute("NotOnOrAfter").Value);
                    subjectConfirmationDataRecipient    = confirmationDataElement.Attribute("Recipient").Value;

                    // Extract Conditions metadata
                    XElement conditionsElement = assertionElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}Conditions").Single();
                    conditionsNotBefore    = DateTimeOffset.Parse(conditionsElement.Attribute("NotBefore").Value);
                    conditionsNotOnOrAfter = DateTimeOffset.Parse(conditionsElement.Attribute("NotOnOrAfter").Value);
                    audience = conditionsElement.Descendants("{urn:oasis:names:tc:SAML:2.0:assertion}Audience").Single().Value.Trim();

                    // Extract AuthnStatement metadata
                    XElement authnStatementElement = assertionElement.Elements("{urn:oasis:names:tc:SAML:2.0:assertion}AuthnStatement").Single();
                    authnStatementAuthnInstant = DateTimeOffset.Parse(authnStatementElement.Attribute("AuthnInstant").Value);
                    authnStatementSessionIndex = authnStatementElement.Attribute("SessionIndex").Value;

                    // Extract SPID user info
                    foreach (XElement attribute in xdoc.Descendants("{urn:oasis:names:tc:SAML:2.0:assertion}AttributeStatement").Elements())
                    {
                        spidUserInfo.Add(
                            attribute.Attribute("Name").Value,
                            attribute.Elements().Single(a => a.Name == "{urn:oasis:names:tc:SAML:2.0:assertion}AttributeValue").Value.Trim()
                            );
                    }
                }

                return(new IdpAuthnResponse(destination, id, inResponseTo, issueInstant, version, issuer,
                                            statusCodeValue, statusCodeInnerValue, statusMessage, statusDetail,
                                            assertionId, assertionIssueInstant, assertionVersion, assertionIssuer,
                                            subjectNameId, subjectConfirmationMethod, subjectConfirmationDataInResponseTo,
                                            subjectConfirmationDataNotOnOrAfter, subjectConfirmationDataRecipient,
                                            conditionsNotBefore, conditionsNotOnOrAfter, audience,
                                            authnStatementAuthnInstant, authnStatementSessionIndex,
                                            spidUserInfo));
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Unable to read AttributeStatement attributes from SAML2 document.", ex);
            }
        }