Esempio n. 1
0
        /// <summary>
        /// Build a signed SAML authentication request.
        /// </summary>
        /// <param name="uuid"></param>
        /// <param name="destination"></param>
        /// <param name="consumerServiceURL"></param>
        /// <param name="securityLevel"></param>
        /// <param name="certFile"></param>
        /// <param name="certPassword"></param>
        /// <param name="storeLocation"></param>
        /// <param name="storeName"></param>
        /// <param name="findType"></param>
        /// <param name="findValue"></param>
        /// <param name="identityProvider"></param>
        /// <param name="enviroment"></param>
        /// <returns>Returns a Base64 Encoded String of the SAML request</returns>
        public static string BuildAuthnPostRequest(string uuid, string destination, string consumerServiceURL, int securityLevel,
                                                   X509Certificate2 certificate, IdentityProvider identityProvider, int enviroment)
        {
            if (string.IsNullOrWhiteSpace(uuid))
            {
                throw new ArgumentNullException("The uuid parameter can't be null or empty.");
            }

            if (string.IsNullOrWhiteSpace(destination))
            {
                throw new ArgumentNullException("The destination parameter can't be null or empty.");
            }

            if (string.IsNullOrWhiteSpace(consumerServiceURL))
            {
                throw new ArgumentNullException("The consumerServiceURL parameter can't be null or empty.");
            }

            if (certificate == null)
            {
                throw new ArgumentNullException("The certificate parameter can't be null.");
            }

            if (identityProvider == null)
            {
                throw new ArgumentNullException("The identityProvider parameter can't be null.");
            }

            if (enviroment < 0)
            {
                throw new ArgumentNullException("The enviroment parameter can't be less than zero.");
            }

            DateTime now = DateTime.UtcNow;

            AuthnRequestType authnRequest = new AuthnRequestType
            {
                ID           = "_" + uuid,
                Version      = "2.0",
                IssueInstant = identityProvider.Now(now),
                Destination  = destination,
                AssertionConsumerServiceIndex           = (ushort)enviroment,
                AssertionConsumerServiceIndexSpecified  = true,
                AttributeConsumingServiceIndex          = 1,
                AttributeConsumingServiceIndexSpecified = true,
                ForceAuthn          = (securityLevel > 1),
                ForceAuthnSpecified = (securityLevel > 1),
                Issuer = new NameIDType
                {
                    Value         = consumerServiceURL.Trim(),
                    Format        = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
                    NameQualifier = consumerServiceURL
                },
                NameIDPolicy = new NameIDPolicyType
                {
                    Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
                },
                Conditions = new ConditionsType
                {
                    NotBefore             = identityProvider.NotBefore(now),
                    NotBeforeSpecified    = true,
                    NotOnOrAfter          = identityProvider.After(now.AddMinutes(10)),
                    NotOnOrAfterSpecified = true
                },
                RequestedAuthnContext = new RequestedAuthnContextType
                {
                    Comparison          = AuthnContextComparisonType.minimum,
                    ComparisonSpecified = true,
                    ItemsElementName    = new ItemsChoiceType7[] { ItemsChoiceType7.AuthnContextClassRef },
                    Items = new string[] { "https://www.spid.gov.it/SpidL" + securityLevel.ToString() }
                }
            };

            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

            ns.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol");
            ns.Add("saml2", "urn:oasis:names:tc:SAML:2.0:assertion");

            StringWriter      stringWriter = new StringWriter();
            XmlWriterSettings settings     = new XmlWriterSettings
            {
                OmitXmlDeclaration = true,
                Indent             = true,
                Encoding           = Encoding.UTF8
            };

            XmlWriter     responseWriter     = XmlTextWriter.Create(stringWriter, settings);
            XmlSerializer responseSerializer = new XmlSerializer(authnRequest.GetType());

            responseSerializer.Serialize(responseWriter, authnRequest, ns);
            responseWriter.Close();

            string samlString = stringWriter.ToString();

            stringWriter.Close();

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(samlString);

            XmlElement signature = XmlSigningHelper.SignXMLDoc(doc, certificate, "_" + uuid);

            doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]);

            return(Convert.ToBase64String(Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + doc.OuterXml)));
        }
Esempio n. 2
0
        /// <summary>
        /// Build a signed SAML logout request.
        /// </summary>
        /// <param name="uuid"></param>
        /// <param name="destination"></param>
        /// <param name="consumerServiceURL"></param>
        /// <param name="certificate"></param>
        /// <param name="identityProvider"></param>
        /// <param name="subjectNameId"></param>
        /// <param name="authnStatementSessionIndex"></param>
        /// <returns></returns>
        public static string BuildLogoutPostRequest(string uuid, string consumerServiceURL, X509Certificate2 certificate,
                                                    IdentityProvider identityProvider, string subjectNameId, string authnStatementSessionIndex)
        {
            if (string.IsNullOrWhiteSpace(uuid))
            {
                throw new ArgumentNullException("The uuid parameter can't be null or empty.");
            }

            if (string.IsNullOrWhiteSpace(consumerServiceURL))
            {
                throw new ArgumentNullException("The consumerServiceURL parameter can't be null or empty.");
            }

            if (certificate == null)
            {
                throw new ArgumentNullException("The certificate parameter can't be null.");
            }

            if (identityProvider == null)
            {
                throw new ArgumentNullException("The identityProvider parameter can't be null.");
            }

            if (string.IsNullOrWhiteSpace(subjectNameId))
            {
                throw new ArgumentNullException("The subjectNameId parameter can't be null or empty.");
            }

            if (string.IsNullOrWhiteSpace(identityProvider.SingleLogoutServiceUrl))
            {
                throw new ArgumentNullException("The LogoutServiceUrl of the identity provider is null or empty.");
            }

            DateTime now = DateTime.UtcNow;

            LogoutRequestType logoutRequest = new LogoutRequestType
            {
                ID           = "_" + uuid,
                Version      = "2.0",
                IssueInstant = identityProvider.Now(now),
                Destination  = identityProvider.EntityID,
                Issuer       = new NameIDType
                {
                    Value         = consumerServiceURL.Trim(),
                    Format        = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
                    NameQualifier = consumerServiceURL
                },
                Item = new NameIDType
                {
                    NameQualifier = consumerServiceURL,
                    Format        = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
                    Value         = identityProvider.SubjectNameIdFormatter(subjectNameId)
                },
                NotOnOrAfterSpecified = true,
                NotOnOrAfter          = now.AddMinutes(10),
                Reason       = "urn:oasis:names:tc:SAML:2.0:logout:user",
                SessionIndex = new string[] { authnStatementSessionIndex }
            };

            try
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol");
                ns.Add("saml2", "urn:oasis:names:tc:SAML:2.0:assertion");

                StringWriter      stringWriter = new StringWriter();
                XmlWriterSettings settings     = new XmlWriterSettings
                {
                    OmitXmlDeclaration = true,
                    Indent             = true,
                    Encoding           = Encoding.UTF8
                };

                XmlWriter     responseWriter     = XmlTextWriter.Create(stringWriter, settings);
                XmlSerializer responseSerializer = new XmlSerializer(logoutRequest.GetType());
                responseSerializer.Serialize(responseWriter, logoutRequest, ns);
                responseWriter.Close();

                string samlString = stringWriter.ToString();
                stringWriter.Close();

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(samlString);

                XmlElement signature = XmlSigningHelper.SignXMLDoc(doc, certificate, "_" + uuid);
                doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]);

                return(Convert.ToBase64String(Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + doc.OuterXml)));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
Esempio n. 3
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);
            }
        }
Esempio n. 4
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);
            }
        }