/// <summary> /// Checks the signature of the given ArtifactResponse and embedded /// AuthnResponse used for the Artifact profile. /// </summary> /// <param name="artifactResponse">ArtifactResponse object.</param> /// <seealso cref="ServiceProviderUtility.ValidateForArtifact"/> private void CheckSignature(ArtifactResponse artifactResponse) { AuthnResponse authnResponse = artifactResponse.AuthnResponse; IdentityProvider identityProvider = (IdentityProvider)this.IdentityProviders[authnResponse.Issuer]; if (identityProvider == null) { throw new Saml2Exception(Resources.InvalidIssuer); } XmlElement artifactResponseSignature = (XmlElement)artifactResponse.XmlSignature; XmlElement responseSignature = (XmlElement)authnResponse.XmlResponseSignature; XmlElement assertionSignature = (XmlElement)authnResponse.XmlAssertionSignature; XmlElement validationSignature = null; string validationSignatureCert = null; string validationReferenceId = null; if (this.ServiceProvider.WantArtifactResponseSigned && artifactResponseSignature == null) { throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureMissingOnArtifactResponse); } else if (this.ServiceProvider.WantPostResponseSigned && responseSignature == null && artifactResponseSignature == null) { throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureMissingOnResponse); } else if (this.ServiceProvider.WantAssertionsSigned && assertionSignature == null && responseSignature == null && artifactResponseSignature == null) { throw new Saml2Exception(Resources.AuthnResponseInvalidSignatureMissing); } // pick the ArtifactResponse, Response or the Assertion for further validation... if (artifactResponseSignature != null) { validationSignature = artifactResponseSignature; validationSignatureCert = artifactResponse.SignatureCertificate; validationReferenceId = artifactResponse.Id; } else 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 (optional for artifact) if (validationSignature != null) { Saml2Utils.ValidateSignedXml( identityProvider.SigningCertificate, (XmlDocument)artifactResponse.XmlDom, validationSignature, validationReferenceId); } }
/// <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> /// Validates the given ArtifactResponse object. /// </summary> /// <param name="artifactResponse">ArtifactResponse object.</param> /// <param name="authnRequests"> /// Collection of previously sent authnRequests used to compare with /// the InResponseTo attribute (if present) of the embedded /// AuthnResponse within the ArtifactResponse. /// </param> /// <see cref="ServiceProviderUtility.Validate(AuthnResponse, ICollection)"/> public void ValidateForArtifact(ArtifactResponse artifactResponse, ICollection authnRequests) { if (artifactResponse.XmlSignature == null && artifactResponse.AuthnResponse.isAssertionEncrypted()) { artifactResponse.Decrypt(ServiceProvider); artifactResponse.AuthnResponse.Decrypt(ServiceProvider); } this.CheckSignature(artifactResponse); if (artifactResponse.AuthnResponse.isAssertionEncrypted()) { artifactResponse.AuthnResponse.Decrypt(ServiceProvider); } this.Validate(artifactResponse.AuthnResponse, authnRequests); }
/// <summary> /// Validates the given ArtifactResponse object. /// </summary> /// <param name="artifactResponse">ArtifactResponse object.</param> /// <param name="authnRequests"> /// Collection of previously sent authnRequests used to compare with /// the InResponseTo attribute (if present) of the embedded /// AuthnResponse within the ArtifactResponse. /// </param> /// <see cref="ServiceProviderUtility.Validate(AuthnResponse, ICollection)"/> public void ValidateForArtifact(ArtifactResponse artifactResponse, ICollection authnRequests) { this.CheckSignature(artifactResponse); this.Validate(artifactResponse.AuthnResponse, authnRequests); }
/// <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; }