Exemplo 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)));
        }
Exemplo n.º 2
0
        public SamlBodyRequest GetSamlRequest(Dictionary <CCAtributes, bool> CCRequestAttrs)
        {
            #region SAML initial request configs
            AuthnRequestType _request = new AuthnRequestType();

            // saml-core-2.0-os - 3.2.1
            // An identifier for the request. It is of type xs:ID and MUST follow the requirements specified in Section
            // 1.3.4 for identifier uniqueness. The values of the ID attribute in a request and the InResponseTo
            // attribute in the corresponding response MUST match
            _request.ID = "_" + Guid.NewGuid().ToString();

            // saml-core-2.0-os - 3.2.1
            // The version of this request. The identifier for the version of SAML defined in this specification is "2.0".
            // SAML versioning is discussed in Section 4.
            _request.Version = "2.0";

            // saml-core-2.0-os - 3.2.1
            // The time instant of issue of the request. The time value is encoded in UTC, as described in Section
            // 1.3.3.
            _request.IssueInstant = DateTime.UtcNow;

            // saml-core-2.0-os - 3.2.1
            // A URI reference indicating the address to which this request has been sent. This is useful to prevent
            // malicious forwarding of requests to unintended recipients, a protection that is required by some
            // protocol bindings. If it is present, the actual recipient MUST check that the URI reference identifies the
            // location at which the message was received. If it does not, the request MUST be discarded. Some
            // protocol bindings may require the use of this attribute (see [SAMLBind]).
            _request.Destination = appSettings.Get("AuthGovPT.Saml.Request.Destination.Url");

            // saml-core-2.0-os - 3.2.1
            // Indicates whether or not (and under what conditions) consent has been obtained from a principal in
            // the sending of this request. See Section 8.4 for some URI references that MAY be used as the value
            // of the Consent attribute and their associated descriptions. If no Consent value is provided, the
            // identifier urn:oasis:names:tc:SAML:2.0:consent:unspecified (see Section 8.4.1) is in
            // effect.
            _request.Consent = "urn:oasis:names:tc:SAML:2.0:consent:unspecified";

            // saml-core-2.0-os - 3.4.1
            // A URI reference that identifies a SAML protocol binding to be used when returning the <Response>
            // message. See [SAMLBind] for more information about protocol bindings and URI references defined
            // for them. This attribute is mutually exclusive with the AssertionConsumerServiceIndex attribute
            // and is typically accompanied by the AssertionConsumerServiceURL attribute.
            _request.ProtocolBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";

            // saml-core-2.0-os - 3.4.1
            // Specifies by value the location to which the <Response> message MUST be returned to the
            // requester. The responder MUST ensure by some means that the value specified is in fact associated
            // with the requester. [SAMLMeta] provides one possible mechanism; signing the enclosing
            // <AuthnRequest> message is another. This attribute is mutually exclusive with the
            // AssertionConsumerServiceIndex attribute and is typically accompanied by the
            // ProtocolBinding attribute.
            _request.AssertionConsumerServiceURL = appSettings.Get("AuthGovPT.Saml.Request.AssertionService.Url");

            // saml-core-2.0-os - 3.4.1
            // Specifies the human-readable name of the requester for use by the presenter's user agent or the
            // identity provider.
            _request.ProviderName = appSettings.Get("AuthGovPT.Saml.Request.Provider.Name");

            // saml-core-2.0-os - 2.2.5
            // The <Issuer> element, with complex type NameIDType, provides information about the issuer of a
            // SAML assertion or protocol message. The element requires the use of a string to carry the issuer's name,
            // but permits various pieces of descriptive data (see Section 2.2.2).
            _request.Issuer = new NameIDType();

            _request.Issuer.Value = appSettings.Get("AuthGovPT.Saml.Request.Issuer.Value");


            // saml-core-2.0-os - 3.2.1
            // This extension point contains optional protocol message extension elements that are agreed on
            // between the communicating parties. No extension schema is required in order to make use of this
            // extension point, and even if one is provided, the lax validation setting does not impose a requirement
            // for the extension to be valid. SAML extension elements MUST be namespace-qualified in a non-
            // SAML-defined namespace.
            _request.Extensions = new ExtensionsType();
            #endregion

            #region Load Cartão de Cidadão Attributes

            _request.Extensions.Any = CCAttributes.RegisterCCAtributes(CCRequestAttrs, EnableAuthWithCMD);

            #endregion

            #region SAML Xml convert to stream

            XmlDocument doc = null;

            // Converter objeto para XmlDocument via stream usando serialização com os tipos AuthnRequestType e XmlDocument
            // http://support.microsoft.com/kb/815813/en-us
            try
            {
                MemoryStream  stream            = new MemoryStream();
                XmlSerializer requestSerializer = new XmlSerializer(_request.GetType());
                requestSerializer.Serialize(stream, _request, xmlNamespaces);
                stream.Flush();

                StreamReader reader = new StreamReader(stream);
                stream.Seek(0, SeekOrigin.Begin);
                XmlTextReader xmlReader = new XmlTextReader(new StringReader(reader.ReadToEnd()));

                XmlSerializer xmlDocumentSerializer = new XmlSerializer(typeof(XmlDocument));
                doc = (XmlDocument)xmlDocumentSerializer.Deserialize(xmlReader);
                doc.PreserveWhitespace = true;
            }
            catch (Exception ex)
            {
                //log
                SamlBodyRequest.Success      = false;
                SamlBodyRequest.ErrorMessage = $"Error on XmlDocument object convertion. EX: {ex.ToString()} ";
            }

            #endregion

            #region SAML Xml Signning

            try
            {
                XmlElement element   = doc.DocumentElement;
                SignedXml  signedXml = new SignedXml(element)
                {
                    SigningKey = FaX509Certificate.PrivateKey
                };

                // Tipo de dados "ID" é restrito às strings em NCName:
                //<xs:simpleType name="ID" id="ID">
                //  <xs:annotation>
                //    <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ID"/>
                //  </xs:annotation>
                //  <xs:restriction base="xs:NCName"/>
                //</xs:simpleType>
                // NCName está definido em http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName como:
                // NCName	 ::=	(Letter | '_') (NCNameChar)*
                Reference reference = new Reference("#" + element.Attributes["ID"].Value);

                // Vide 5.4.3 "Canonicalization Method" e 5.4.4 "Transforms" em
                // http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf

                reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
                reference.AddTransform(new XmlDsigExcC14NTransform());

                signedXml.AddReference(reference);
                signedXml.KeyInfo.AddClause(new KeyInfoX509Data(FaX509Certificate));
                signedXml.ComputeSignature();
                XmlElement xmlDigitalSignature = signedXml.GetXml();

                // AuthnRequestType define a ordem dos elementos filhos na schema saml-schema-protocol-2.0.xsd:
                //<complexType name="RequestAbstractType" abstract="true">
                //    <sequence>
                //        <element ref="saml:Issuer" minOccurs="0"/>
                //        <element ref="ds:Signature" minOccurs="0"/>
                //        <element ref="ds:Signature" minOccurs="0"/>
                //        <element ref="samlp:Extensions" minOccurs="0"/>
                //    </sequence>
                //    ...
                //</complexType>
                XmlNode refNode = doc.GetElementsByTagName("Issuer", "urn:oasis:names:tc:SAML:2.0:assertion").Item(0);
                element.InsertAfter(xmlDigitalSignature, refNode);
            }
            catch (Exception ex)
            {
                //TODO:: log exception ex
                SamlBodyRequest.Success      = false;
                SamlBodyRequest.ErrorMessage = $"Error on Xml signing process. EX: {ex.ToString()}";
            }

            #endregion

            #region Return SAML Request into Auth.gov FA

            SamlBodyRequest.RelayState     = RelayStateToBepersistedAcross;
            SamlBodyRequest.SAMLRequest    = Convert.ToBase64String(Encoding.UTF8.GetBytes(doc.OuterXml));
            SamlBodyRequest.PostRequestUrl = appSettings.Get("AuthGovPT.Saml.Request.Post.Url");

            SamlBodyRequest.Success = true;
            return(SamlBodyRequest);

            // Vide 3.5.3 "RelayState" em
            // http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
            // "...The value MUST NOT exceed 80 bytes in length and SHOULD be integrity protected by the entity
            // creating the message independent of any other protections that may or may not exist during message
            // transmission..."
            // Vide 3.5 "HTTP POST Binding" em
            // http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf

            #endregion
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets the authentication request.
        /// </summary>
        /// <returns></returns>
        public string GetAuthRequest()
        {
            string   result         = "";
            DateTime requestDatTime = DateTime.UtcNow;
            //New AuthnRequestType
            AuthnRequestType request = new AuthnRequestType();

            request.Version = Options.Version;

            //Unique UUID
            request.ID = "_" + this.Options.UUID;

            //Request DateTime
            request.IssueInstant = requestDatTime;

            //Request Force Authn
            if ((int)Options.SPIDLevel > 1)
            {
                request.ForceAuthn          = true;
                request.ForceAuthnSpecified = true;
            }
            else
            {
                request.ForceAuthn          = false;
                request.ForceAuthnSpecified = true;
            }


            //SSO Destination URI
            request.Destination = this.Options.Destination;

            //Service Provider Assertion Consumer Service Index
            request.AssertionConsumerServiceIndex          = this.Options.AssertionConsumerServiceIndex;
            request.AssertionConsumerServiceIndexSpecified = true;

            //Service Provider Attribute Consumer Service Index
            request.AttributeConsumingServiceIndex          = this.Options.AttributeConsumingServiceIndex;
            request.AttributeConsumingServiceIndexSpecified = true;


            //Service Provider Attribute Consumer Service Index
            request.AttributeConsumingServiceIndex          = this.Options.AttributeConsumingServiceIndex;
            request.AttributeConsumingServiceIndexSpecified = true;

            //Issuer Data
            request.Issuer = new NameIDType()
            {
                Format        = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
                Value         = Options.SPUID,
                NameQualifier = Options.SPUID
            };

            request.NameIDPolicy = new NameIDPolicyType()
            {
                Format      = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
                AllowCreate = true
            };

            //NotRequired
            request.Conditions = new ConditionsType()
            {
                NotBefore             = requestDatTime.Add(this.Options.NotBefore),
                NotBeforeSpecified    = true,
                NotOnOrAfter          = requestDatTime.Add(this.Options.NotOnOrAfter),
                NotOnOrAfterSpecified = true
            };

            RequestedAuthnContextType requestedAuthn = new RequestedAuthnContextType
            {
                Comparison          = AuthnContextComparisonType.minimum,
                ComparisonSpecified = true,
                ItemsElementName    = new ItemsChoiceType7[] { ItemsChoiceType7.AuthnContextClassRef },
                Items = new string[] { "https://www.spid.gov.it/SpidL" + ((int)Options.SPIDLevel).ToString() }
            };

            request.RequestedAuthnContext = requestedAuthn;


            string samlString = "";

            XmlSerializer serializer = new XmlSerializer(request.GetType());

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

                using (XmlWriter writer = XmlWriter.Create(stringWriter, settings))
                {
                    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                    namespaces.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol");

                    serializer.Serialize(writer, request, namespaces);

                    samlString = stringWriter.ToString();
                }
            }
            result = samlString;


            return(result);
        }
Exemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="UUID"></param>
        /// <param name="Destination"></param>
        /// <param name="ConsumerServiceURL"></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="signatureType"></param>
        /// <returns></returns>
        public static string BuildPostSamlRequest(string UUID, string Destination, string ConsumerServiceURL, int SecurityLevel,
                                                  string certFile, string certPassword,
                                                  StoreLocation storeLocation, StoreName storeName,
                                                  X509FindType findType, object findValue, SigningHelper.SignatureType signatureType, string IdentityProvider, int Enviroment)
        {
            AuthnRequestType MyRequest = new AuthnRequestType
            {
                ID      = UUID,
                Version = "2.0"
            };
            DateTime now         = DateTime.UtcNow;
            DateTime after       = now.AddMinutes(10);
            string   nowString   = String.Empty;
            string   afterString = String.Empty;

            if (IdentityProvider.Contains("sielte"))
            {
                // SIELTE
                nowString   = now.AddMinutes(-2).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'");
                afterString = after.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'");
            }
            else
            {
                // POSTE - TIM - INFOCERT
                nowString   = now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
                afterString = after.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
            }
            MyRequest.IssueInstant = nowString;
            if (SecurityLevel > 1)
            {
                MyRequest.ForceAuthn          = true;
                MyRequest.ForceAuthnSpecified = true;
            }
            MyRequest.Destination = Destination;
            MyRequest.AssertionConsumerServiceIndex           = (ushort)Enviroment;
            MyRequest.AssertionConsumerServiceIndexSpecified  = true;
            MyRequest.AttributeConsumingServiceIndex          = 1;
            MyRequest.AttributeConsumingServiceIndexSpecified = true;

            NameIDType IssuerForRequest = new NameIDType
            {
                Value         = ConsumerServiceURL.Trim(),
                Format        = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
                NameQualifier = ConsumerServiceURL
            };

            MyRequest.Issuer = IssuerForRequest;

            NameIDPolicyType NameIdPolicyForRequest = new NameIDPolicyType
            {
                Format               = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
                AllowCreate          = true,
                AllowCreateSpecified = true
            };

            MyRequest.NameIDPolicy = NameIdPolicyForRequest;

            ConditionsType Conditional = new ConditionsType();

            if (IdentityProvider.Contains("sielte"))
            {
                // SIELTE
                Conditional.NotBefore = nowString;
            }
            else
            {
                // POSTE - TIM - INFOCERT
                Conditional.NotBefore = now.AddMinutes(-2).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
            }

            Conditional.NotBeforeSpecified    = true;
            Conditional.NotOnOrAfter          = afterString;
            Conditional.NotOnOrAfterSpecified = true;
            MyRequest.Conditions = Conditional;

            RequestedAuthnContextType RequestedAuthn = new RequestedAuthnContextType
            {
                Comparison          = AuthnContextComparisonType.minimum,
                ComparisonSpecified = true,
                ItemsElementName    = new ItemsChoiceType7[] { ItemsChoiceType7.AuthnContextClassRef },
                Items = new string[] { "https://www.spid.gov.it/SpidL" + SecurityLevel.ToString() }
            };

            MyRequest.RequestedAuthnContext = RequestedAuthn;

            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");

            XmlSerializer responseSerializer = new XmlSerializer(MyRequest.GetType());

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

            XmlWriter responseWriter = XmlTextWriter.Create(stringWriter, settings);

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

            string samlString = string.Empty;

            samlString = stringWriter.ToString();

            stringWriter.Close();

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(samlString);
            X509Certificate2 cert = null;

            if (System.IO.File.Exists(certFile))
            {
                cert = new X509Certificate2(certFile, certPassword);
            }
            else
            {
                X509Store store = new X509Store(storeName, storeLocation);
                store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
                X509Certificate2Collection CertCol = store.Certificates;

                X509Certificate2Collection coll = store.Certificates.Find(findType, findValue.ToString(), false);

                if (coll.Count < 1)
                {
                    throw new ArgumentException("Unable to locate certificate");
                }
                cert = coll[0];
                store.Close();
            }

            XmlElement signature = SigningHelper.SignDoc(doc, cert, UUID);

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

            string responseStr = doc.OuterXml;

            //byte[] base64EncodedBytes =
            //    Encoding.UTF8.GetBytes(responseStr);

            //string returnValue = System.Convert.ToBase64String(
            //    base64EncodedBytes);

            return("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + responseStr);
        }