예제 #1
0
        /// <summary>
        /// Initializes a new instance of the ArtifactResponse class.
        /// </summary>
        /// <param name="artifactResponse">
        /// String representation of the ArtifactResponse xml.
        /// </param>
        public ArtifactResponse(string artifactResponse)
        {
            try
            {
                xml = new XmlDocument();
                xml.PreserveWhitespace = true;
                xml.LoadXml(artifactResponse);
                nsMgr = new XmlNamespaceManager(xml.NameTable);
                nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
                nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
                nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");

                string  xpath    = "/samlp:ArtifactResponse/samlp:Response";
                XmlNode response = xml.DocumentElement.SelectSingleNode(xpath, nsMgr);
                if (response == null)
                {
                    throw new Saml2Exception(Resources.ArtifactResponseMissingResponse);
                }

                authnResponse = new AuthnResponse(response.OuterXml);
            }
            catch (ArgumentNullException ane)
            {
                throw new Saml2Exception(Resources.ArtifactResponseNullArgument, ane);
            }
            catch (XmlException xe)
            {
                throw new Saml2Exception(Resources.ArtifactResponseXmlException, xe);
            }
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the ArtifactResponse class.
        /// </summary>
        /// <param name="artifactResponse">
        /// String representation of the ArtifactResponse xml.
        /// </param>
        public ArtifactResponse(string artifactResponse)
        {
            try
            {
                m_xml = new XmlDocument {
                    PreserveWhitespace = true
                };
                m_xml.LoadXml(artifactResponse);
                m_nsMgr = new XmlNamespaceManager(m_xml.NameTable);
                m_nsMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
                m_nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
                m_nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");

                const string xpath    = "/samlp:ArtifactResponse/samlp:Response";
                var          response = m_xml.DocumentElement?.SelectSingleNode(xpath, m_nsMgr);
                if (response == null)
                {
                    throw new Saml2Exception(Resources.ArtifactResponseMissingResponse);
                }

                AuthnResponse = new AuthnResponse(response.OuterXml);
            }
            catch (ArgumentNullException ane)
            {
                throw new Saml2Exception(Resources.ArtifactResponseNullArgument, ane);
            }
            catch (XmlException xe)
            {
                throw new Saml2Exception(Resources.ArtifactResponseXmlException, xe);
            }
        }
예제 #3
0
        /// <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;
        }
예제 #4
0
        /// <summary>
        /// Validates the given AuthnResponse object except for xml signature.
        /// XML signature checking is expected to be done prior to calling
        /// this method based on the appropriate profile.
        /// </summary>
        /// <param name="authnResponse">AuthnResponse object.</param>
        /// <param name="authnRequests">
        /// Collection of previously sent authnRequests used to compare with
        /// the InResponseTo attribute of the AuthnResponse (if present).
        /// </param>
        /// <see cref="ServiceProviderUtility.ValidateForArtifact"/>
        /// <see cref="ServiceProviderUtility.ValidateForPost(AuthnResponse, ICollection)"/>
        private void Validate(AuthnResponse authnResponse, ICollection authnRequests)
        {
            if (authnResponse.InResponseTo != null)
            {
                ServiceProviderUtility.CheckInResponseTo(authnResponse, authnRequests);
            }

            this.CheckIssuer(authnResponse.Issuer);
            ServiceProviderUtility.CheckStatusCode(authnResponse.StatusCode);
            ServiceProviderUtility.CheckConditionWithTime(authnResponse);
            this.CheckConditionWithAudience(authnResponse);
            this.CheckCircleOfTrust(authnResponse.Issuer);
        }
예제 #5
0
        /// <summary>
        /// Checks the signature of the given AuthnResponse used for the POST
        /// profile.
        /// </summary>
        /// <param name="authnResponse">AuthnResponse object.</param>
        /// <seealso cref="ServiceProviderUtility.ValidateForPost(AuthnResponse, ICollection)"/>
        private void CheckSignature(AuthnResponse authnResponse)
        {
            IdentityProvider identityProvider = (IdentityProvider)this.IdentityProviders[authnResponse.Issuer];
            if (identityProvider == null)
            {
                throw new Saml2Exception(Resources.InvalidIssuer);
            }

            XmlElement responseSignature = (XmlElement)authnResponse.XmlResponseSignature;
            XmlElement assertionSignature = (XmlElement)authnResponse.XmlAssertionSignature;
            XmlElement validationSignature = null;
            string validationSignatureCert = null;
            string validationReferenceId = null;

            if (responseSignature == null && assertionSignature == null)
            {
                throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureMissing);
            }
            else if (this.ServiceProvider.WantPostResponseSigned && responseSignature == null)
            {
                throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureMissingOnResponse);
            }

            // pick the Response or the Assertion for further validation...
            if (responseSignature != null)
            {
                validationSignature = responseSignature;
                validationSignatureCert = authnResponse.ResponseSignatureCertificate;
                validationReferenceId = authnResponse.Id;
            }
            else
            {
                validationSignature = assertionSignature;
                validationSignatureCert = authnResponse.AssertionSignatureCertificate;
                validationReferenceId = authnResponse.AssertionId;
            }

            if (validationSignatureCert != null)
            {
                string idpCert = Regex.Replace(identityProvider.EncodedSigningCertificate, @"\s", string.Empty);
                validationSignatureCert = Regex.Replace(validationSignatureCert, @"\s", string.Empty);
                if (idpCert != validationSignatureCert)
                {
                    throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureCertsDontMatch);
                }
            }

            // check the signature of the xml document (always for post)
            Saml2Utils.ValidateSignedXml(
                                         identityProvider.SigningCertificate,
                                         (XmlDocument)authnResponse.XmlDom,
                                         validationSignature,
                                         validationReferenceId);
        }
예제 #6
0
 /// <summary>
 /// Checks the audience condition of the given AuthnResponse.
 /// </summary>
 /// <param name="authnResponse">SAMLv2 AuthnResponse.</param>
 private void CheckConditionWithAudience(AuthnResponse authnResponse)
 {
     if (!authnResponse.ConditionAudiences.Contains(this.ServiceProvider.EntityId))
     {
         throw new Saml2Exception(Resources.AuthnResponseInvalidConditionAudience);
     }
 }
예제 #7
0
        /// <summary>
        /// Checks the InResponseTo field of the given AuthnResponse to
        /// see if it is one of the managed authn requests.
        /// </summary>
        /// <param name="authnResponse">SAMLv2 AuthnResponse.</param>
        /// <param name="authnRequests">
        /// Collection of previously sent AuthnRequests.
        /// </param>
        private static void CheckInResponseTo(AuthnResponse authnResponse, ICollection authnRequests)
        {
            if (authnRequests != null && authnResponse.InResponseTo != null)
            {
                IEnumerator i = authnRequests.GetEnumerator();
                while (i.MoveNext())
                {
                    AuthnRequest authnRequest = (AuthnRequest)i.Current;
                    if (authnRequest.Id == authnResponse.InResponseTo)
                    {
                        // Found one, return quietly.
                        return;
                    }
                }
            }

            // Didn't find one, complain loudly.
            throw new Saml2Exception(Resources.AuthnResponseInvalidInResponseTo);
        }
예제 #8
0
        /// <summary>
        /// Checks the time condition of the given AuthnResponse.
        /// </summary>
        /// <param name="authnResponse">SAMLv2 AuthnResponse.</param>
        private static void CheckConditionWithTime(AuthnResponse authnResponse)
        {
            DateTime utcNow = DateTime.UtcNow;
            DateTime utcBefore = TimeZoneInfo.ConvertTimeToUtc(authnResponse.ConditionNotBefore);
            DateTime utcOnOrAfter = TimeZoneInfo.ConvertTimeToUtc(authnResponse.ConditionNotOnOrAfter);

            if (utcNow < utcBefore || utcNow >= utcOnOrAfter)
            {
                throw new Saml2Exception(Resources.AuthnResponseInvalidConditionTime);
            }
        }
예제 #9
0
 /// <summary>
 /// Validates the given AuthnResponse object.
 /// </summary>
 /// <param name="authnResponse">AuthnResponse object.</param>
 /// <param name="authnRequests">
 /// Collection of previously sent authnRequests used to compare with
 /// the InResponseTo attribute (if present) of the AuthnResponse.
 /// </param>
 /// <see cref="ServiceProviderUtility.Validate(AuthnResponse, ICollection)"/>
 public void ValidateForPost(AuthnResponse authnResponse, ICollection authnRequests)
 {
     this.CheckSignature(authnResponse);
     this.Validate(authnResponse, authnRequests);
 }
예제 #10
0
        /// <summary>
        /// Initializes a new instance of the ArtifactResponse class.
        /// </summary>
        /// <param name="artifactResponse">
        /// String representation of the ArtifactResponse xml.
        /// </param>
        public ArtifactResponse(string artifactResponse)
        {
            try
            {
                this.xml = new XmlDocument();
                this.xml.PreserveWhitespace = true;
                this.xml.LoadXml(artifactResponse);
                this.nsMgr = new XmlNamespaceManager(this.xml.NameTable);
                this.nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
                this.nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion");
                this.nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol");

                string xpath = "/samlp:ArtifactResponse/samlp:Response";
                XmlNode response = this.xml.DocumentElement.SelectSingleNode(xpath, this.nsMgr);
                if (response == null)
                {
                    throw new Saml2Exception(Resources.ArtifactResponseMissingResponse);
                }

                this.authnResponse = new AuthnResponse(response.OuterXml);
            }
            catch (ArgumentNullException ane)
            {
                throw new Saml2Exception(Resources.ArtifactResponseNullArgument, ane);
            }
            catch (XmlException xe)
            {
                throw new Saml2Exception(Resources.ArtifactResponseXmlException, xe);
            }
        }
예제 #11
0
 /// <summary>
 /// Validates the given AuthnResponse object.
 /// </summary>
 /// <param name="authnResponse">AuthnResponse object.</param>
 /// <param name="authnRequests">
 /// Collection of previously sent authnRequests used to compare with
 /// the InResponseTo attribute (if present) of the AuthnResponse.
 /// </param>
 /// <see cref="ServiceProviderUtility.Validate(AuthnResponse, ICollection)"/>
 public void ValidateForPost(AuthnResponse authnResponse, ICollection authnRequests)
 {
     if (authnResponse.XmlResponseSignature == null && authnResponse.isAssertionEncrypted())
     {
         authnResponse.Decrypt(ServiceProvider);
     }
     this.CheckSignature(authnResponse);
     if (authnResponse.isAssertionEncrypted())
     {
         authnResponse.Decrypt(ServiceProvider);
     }
     this.Validate(authnResponse, authnRequests);
 }
예제 #12
0
        /// <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;
        }
예제 #13
0
        /// <summary>
        /// Validates the given AuthnResponse object except for xml signature.
        /// XML signature checking is expected to be done prior to calling
        /// this method based on the appropriate profile.
        /// </summary>
        /// <param name="authnResponse">AuthnResponse object.</param>
        /// <param name="authnRequests">
        /// Collection of previously sent authnRequests used to compare with
        /// the InResponseTo attribute of the AuthnResponse (if present).
        /// </param>
        /// <see cref="ServiceProviderUtility.ValidateForArtifact"/>
        /// <see cref="ServiceProviderUtility.ValidateForPost(AuthnResponse, ICollection)"/>
        private void Validate(AuthnResponse authnResponse, ICollection authnRequests)
        {
            /* Commenting this section out since we had to remove the Session caching of Authnresponses due
             * to some session sharing issues
            if (authnResponse.InResponseTo != null)
            {
                CheckInResponseTo(authnResponse, authnRequests);
            }*/

            CheckIssuer(authnResponse.Issuer);
            CheckStatusCode(authnResponse.StatusCode);
            CheckConditionWithTime(authnResponse);
            CheckConditionWithAudience(authnResponse);
            CheckCircleOfTrust(authnResponse.Issuer);
        }