Exemple #1
0
        /// <summary>
        /// Initializes a new instance of the ArtifactResolve class.
        /// </summary>
        /// <param name="serviceProvider">Service Provider to issue this request</param>
        /// <param name="artifact">SAMLv2 Artifact</param>
        public ArtifactResolve(IServiceProvider serviceProvider, Artifact artifact, Saml2Utils saml2Utils)
        {
            xml = new XmlDocument();
            xml.PreserveWhitespace = true;

            nsMgr = new XmlNamespaceManager(xml.NameTable);
            nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");
            nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");

            Id = saml2Utils.GenerateId();
            IssueInstant = saml2Utils.GenerateIssueInstant();
            Issuer = serviceProvider.EntityId;
            Artifact = artifact;

            var rawXml = new StringBuilder();
            rawXml.Append("<samlp:ArtifactResolve");
            rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"");
            rawXml.Append(" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"");
            rawXml.Append(" ID=\"" + Id + "\"");
            rawXml.Append(" Version=\"2.0\"");
            rawXml.Append(" IssueInstant=\"" + IssueInstant + "\"");
            rawXml.Append(">");
            rawXml.Append(" <saml:Issuer>" + Issuer + "</saml:Issuer>");
            rawXml.Append(" <samlp:Artifact>" + Artifact + "</samlp:Artifact>");
            rawXml.Append("</samlp:ArtifactResolve>");

            xml.LoadXml(rawXml.ToString());
        }
        /// <summary>
        /// Retrieve the AuthnResponse object found within the HttpRequest
        /// in the context of the HttpContext, performing validation of
        /// the AuthnResponse prior to returning to the user.
        /// </summary>
        /// <param name="context">
        /// HttpContext containing session, request, and response objects.
        /// </param>
        /// <returns>AuthnResponse object</returns>
        public AuthnResponse GetAuthnResponse(HttpContext context)
        {
            ArtifactResponse artifactResponse = null;
            AuthnResponse authnResponse = null;
            ICollection authnRequests = AuthnRequestCache.GetSentAuthnRequests(context);
            HttpRequest request = context.Request;

            // Check if a saml response was received...
            if (string.IsNullOrEmpty(request[Saml2Constants.ResponseParameter])
                && string.IsNullOrEmpty(request[Saml2Constants.ArtifactParameter]))
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityNoSamlResponseReceived);
            }

            // Obtain AuthnResponse object from either HTTP-POST or HTTP-Artifact
            if (request[Saml2Constants.ResponseParameter] != null)
            {
                string samlResponse = Saml2Utils.ConvertFromBase64(request[Saml2Constants.ResponseParameter]);
                authnResponse = new AuthnResponse(samlResponse);

                XmlDocument xmlDoc = (XmlDocument)authnResponse.XmlDom;
                StringBuilder logMessage = new StringBuilder();
                logMessage.Append("AuthnResponse:\r\n").Append(xmlDoc.OuterXml);
                FedletLogger.Info(logMessage.ToString());
            }
            else if (request[Saml2Constants.ArtifactParameter] != null)
            {
                Artifact artifact = new Artifact(request[Saml2Constants.ArtifactParameter]);
                artifactResponse = this.GetArtifactResponse(artifact);
                authnResponse = artifactResponse.AuthnResponse;

                XmlDocument xmlDoc = (XmlDocument)artifactResponse.XmlDom;
                StringBuilder logMessage = new StringBuilder();
                logMessage.Append("ArtifactResponse:\r\n").Append(xmlDoc.OuterXml);
                FedletLogger.Info(logMessage.ToString());
            }

            string prevAuthnRequestId = authnResponse.InResponseTo;
            try
            {
                if (artifactResponse != null)
                {
                    this.ValidateForArtifact(artifactResponse, authnRequests);
                }
                else
                {
                    this.ValidateForPost(authnResponse, authnRequests);
                }
            }
            catch (Saml2Exception se)
            {
                // log and throw again...
                XmlDocument authnResponseXml = (XmlDocument)authnResponse.XmlDom;
                StringBuilder logMessage = new StringBuilder();
                logMessage.Append(se.Message).Append("\r\n").Append(authnResponseXml.InnerXml);
                FedletLogger.Warning(logMessage.ToString());
                throw;
            }
            finally
            {
                AuthnRequestCache.RemoveSentAuthnRequest(context, prevAuthnRequestId);
            }

            return authnResponse;
        }
        /// <summary>
        /// Gets the Identity Provider associated with the specified artifact.
        /// The currently maintained list of IDPs each have their entity ID
        /// hashed and compared with the given artifact's source ID to make
        /// the correct determination.
        /// </summary>
        /// <param name="artifact">SAML artifact.</param>
        /// <returns>
        /// Identity Provider who's entity ID matches the source ID
        /// within the artifact, null if not found.
        /// </returns>
        private IdentityProvider GetIdpFromArtifact(Artifact artifact)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            IdentityProvider idp = null;
            string idpEntityIdHashed = null;

            foreach (string idpEntityId in this.IdentityProviders.Keys)
            {
                idpEntityIdHashed = BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(idpEntityId)));
                idpEntityIdHashed = idpEntityIdHashed.Replace("-", string.Empty);

                if (idpEntityIdHashed == artifact.SourceId)
                {
                    idp = (IdentityProvider)this.IdentityProviders[idpEntityId];
                    break;
                }
            }

            return idp;
        }
        /// <summary>
        /// Retrieve the ArtifactResponse object with the given SAMLv2 
        /// artifact.
        /// </summary>
        /// <param name="artifact">SAMLv2 artifact</param>
        /// <returns>ArtifactResponse object</returns>
        public ArtifactResponse GetArtifactResponse(Artifact artifact)
        {
            ArtifactResolve artifactResolve = new ArtifactResolve(this.ServiceProvider, artifact);
            ArtifactResponse artifactResponse = null;

            IdentityProvider idp = this.GetIdpFromArtifact(artifact);
            if (idp == null)
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityIdpNotDeterminedFromArtifact);
            }

            string artifactResolutionSvcLoc = idp.GetArtifactResolutionServiceLocation(Saml2Constants.HttpSoapProtocolBinding);
            if (artifactResolutionSvcLoc == null)
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityIdpArtifactResSvcLocNotDefined);
            }

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            try
            {
                Uri artifactResolutionSvcUri = new Uri(artifactResolutionSvcLoc);
                request = (HttpWebRequest)WebRequest.Create(artifactResolutionSvcUri);
                XmlDocument artifactResolveXml = (XmlDocument)artifactResolve.XmlDom;

                if (idp.WantArtifactResolveSigned)
                {
                    if (string.IsNullOrEmpty(this.ServiceProvider.SigningCertificateAlias))
                    {
                        throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilitySignFailedNoCertAlias);
                    }
                    else
                    {
                        Saml2Utils.SignXml(
                            this.ServiceProvider.SigningCertificateAlias,
                            artifactResolveXml,
                            artifactResolve.Id,
                            true);
                    }
                }

                string soapMessage = Saml2Utils.CreateSoapMessage(artifactResolveXml.InnerXml);

                byte[] byteArray = Encoding.UTF8.GetBytes(soapMessage);
                request.ContentType = "text/xml";
                request.ContentLength = byteArray.Length;
                request.AllowAutoRedirect = false;
                request.Method = "POST";

                Stream requestStream = request.GetRequestStream();
                requestStream.Write(byteArray, 0, byteArray.Length);
                requestStream.Close();

                StringBuilder logMessage = new StringBuilder();
                logMessage.Append("ArtifactResolve:\r\n").Append(artifactResolveXml.OuterXml);
                FedletLogger.Info(logMessage.ToString());

                response = (HttpWebResponse)request.GetResponse();
                StreamReader streamReader = new StreamReader(response.GetResponseStream());
                string responseContent = streamReader.ReadToEnd();
                streamReader.Close();

                XmlDocument soapResponse = new XmlDocument();
                soapResponse.PreserveWhitespace = true;
                soapResponse.LoadXml(responseContent);

                XmlNamespaceManager soapNsMgr = new XmlNamespaceManager(soapResponse.NameTable);
                soapNsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
                soapNsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");
                soapNsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
                soapNsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");

                XmlElement root = soapResponse.DocumentElement;
                XmlNode responseXml = root.SelectSingleNode("/soap:Envelope/soap:Body/samlp:ArtifactResponse", soapNsMgr);
                string artifactResponseXml = responseXml.OuterXml;

                artifactResponse = new ArtifactResponse(artifactResponseXml);

                if (artifactResolve.Id != artifactResponse.InResponseTo)
                {
                    throw new Saml2Exception(Resources.ArtifactResolutionInvalidInResponseTo);
                }
            }
            catch (WebException we)
            {
                throw new ServiceProviderUtilityException(Resources.ArtifactResolutionWebException, we);
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }

            return artifactResponse;
        }
        /// <summary>
        /// Retrieve the ArtifactResponse object with the given SAMLv2 
        /// artifact.
        /// </summary>
        /// <param name="artifact">SAMLv2 artifact</param>
        /// <returns>ArtifactResponse object</returns>
        public ArtifactResponse GetArtifactResponse(Artifact artifact)
        {
            ArtifactResolve artifactResolve = new ArtifactResolve(this.ServiceProvider, artifact);
            ArtifactResponse artifactResponse = null;

            IdentityProvider idp = this.GetIdpFromArtifact(artifact);
            if (idp == null)
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityIdpNotDeterminedFromArtifact);
            }

            string artifactResolutionSvcLoc = idp.GetArtifactResolutionServiceLocation(Saml2Constants.HttpSoapProtocolBinding);
            if (artifactResolutionSvcLoc == null)
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityIdpArtifactResSvcLocNotDefined);
            }

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            try
            {
                Uri artifactResolutionSvcUri = new Uri(artifactResolutionSvcLoc);
                if (artifactResolutionSvcUri.Scheme == "https")
                {
                    System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                    delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                    System.Security.Cryptography.X509Certificates.X509Chain chain,
                    System.Net.Security.SslPolicyErrors sslPolicyErrors)
                    {
                        if (ServiceProvider.TrustAllCerts
                            || sslPolicyErrors.HasFlag(System.Net.Security.SslPolicyErrors.None))
                            {
                                return true;
                            }

                        StringBuilder logErrorMessage = new StringBuilder();
                        logErrorMessage.Append("SSLPolicyError: ").Append(sslPolicyErrors);
                        FedletLogger.Error(logErrorMessage.ToString());
                        return false;
                    };
                }

                request = (HttpWebRequest)WebRequest.Create(artifactResolutionSvcUri);

                string authCertAlias = ConfigurationManager.AppSettings[Saml2Constants.MutualAuthCertAlias];
                if (artifactResolutionSvcUri.Scheme == "https" && !string.IsNullOrWhiteSpace(authCertAlias))
                {
                    X509Certificate2 cert = FedletCertificateFactory.GetCertificateByFriendlyName(authCertAlias);
                    if (cert != null)
                    {
                        request.ClientCertificates.Add(cert);
                    }
                }

                XmlDocument artifactResolveXml = (XmlDocument)artifactResolve.XmlDom;

                if (idp.WantArtifactResolveSigned)
                {
                    if (string.IsNullOrEmpty(this.ServiceProvider.SigningCertificateAlias))
                    {
                        throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilitySignFailedNoCertAlias);
                    }
                    else
                    {
                        Saml2Utils.SignXml(
                            this.ServiceProvider.SigningCertificateAlias,
                            artifactResolveXml,
                            artifactResolve.Id,
                            true,
                            this.ServiceProvider);
                    }
                }

                string soapMessage = Saml2Utils.CreateSoapMessage(artifactResolveXml.InnerXml);

                byte[] byteArray = Encoding.UTF8.GetBytes(soapMessage);
                request.ContentType = "text/xml";
                request.ContentLength = byteArray.Length;
                request.AllowAutoRedirect = false;
                request.Method = "POST";

                Stream requestStream = request.GetRequestStream();
                requestStream.Write(byteArray, 0, byteArray.Length);
                requestStream.Close();

                StringBuilder logMessage = new StringBuilder();
                logMessage.Append("ArtifactResolve:\r\n").Append(artifactResolveXml.OuterXml);
                FedletLogger.Info(logMessage.ToString());

                response = (HttpWebResponse)request.GetResponse();
                StreamReader streamReader = new StreamReader(response.GetResponseStream());
                string responseContent = streamReader.ReadToEnd();
                streamReader.Close();

                XmlDocument soapResponse = new XmlDocument();
                soapResponse.PreserveWhitespace = true;
                soapResponse.LoadXml(responseContent);

                XmlNamespaceManager soapNsMgr = new XmlNamespaceManager(soapResponse.NameTable);
                soapNsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
                soapNsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");
                soapNsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
                soapNsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");

                XmlElement root = soapResponse.DocumentElement;
                XmlNode responseXml = root.SelectSingleNode("/soap:Envelope/soap:Body/samlp:ArtifactResponse", soapNsMgr);
                string artifactResponseXml = responseXml.OuterXml;

                artifactResponse = new ArtifactResponse(artifactResponseXml);

                if (artifactResolve.Id != artifactResponse.InResponseTo)
                {
                    throw new Saml2Exception(Resources.ArtifactResolutionInvalidInResponseTo);
                }
            }
            catch (WebException we)
            {
                throw new ServiceProviderUtilityException(Resources.ArtifactResolutionWebException, we);
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }

            return artifactResponse;
        }
        /// <summary>
        /// Retrieve the AuthnResponse object found within the HttpRequest
        /// in the context of the HttpContext, performing validation of
        /// the AuthnResponse prior to returning to the user.
        /// </summary>
        /// <param name="context">
        /// HttpContext containing session, request, and response objects.
        /// </param>
        /// <returns>AuthnResponse object</returns>
        public AuthnResponse GetAuthnResponse(HttpContextBase context)
        {
            ArtifactResponse artifactResponse = null;
            AuthnResponse authnResponse;
            ICollection authnRequests = AuthnRequestCache.GetSentAuthnRequests(context);
            HttpRequestBase request = context.Request;

            // Obtain AuthnResponse object from either HTTP-POST or HTTP-Artifact
            if (!string.IsNullOrWhiteSpace(request[Saml2Constants.ResponseParameter]))
            {
                string samlResponse = _saml2Utils.ConvertFromBase64(request[Saml2Constants.ResponseParameter]);
                authnResponse = new AuthnResponse(samlResponse);

                var xmlDoc = (XmlDocument) authnResponse.XmlDom;
                _logger.Info("AuthnResponse:\r\n{0}", xmlDoc.OuterXml);
            }
            else if (!string.IsNullOrWhiteSpace(request[Saml2Constants.ArtifactParameter]))
            {
                var artifact = new Artifact(request[Saml2Constants.ArtifactParameter]);
                artifactResponse = GetArtifactResponse(artifact);
                authnResponse = artifactResponse.AuthnResponse;

                var xmlDoc = (XmlDocument) artifactResponse.XmlDom;
                _logger.Info("ArtifactResponse:\r\n{0}", xmlDoc.OuterXml);
            }
            else
            {
                throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityNoSamlResponseReceived);
            }

            string prevAuthnRequestId = authnResponse.InResponseTo;
            try
            {
                if (artifactResponse != null)
                {
                    ValidateForArtifact(artifactResponse, authnRequests);
                }
                else
                {
                    ValidateForPost(authnResponse, authnRequests);
                }
            }
            catch (Saml2Exception se)
            {
                // add some context
                var authnResponseXml = (XmlDocument) authnResponse.XmlDom;
                se.Data["xml"] = authnResponseXml.InnerXml;
                throw;
            }
            finally
            {
                AuthnRequestCache.RemoveSentAuthnRequest(context, prevAuthnRequestId);
            }

            return authnResponse;
        }