private void CreateMetadataDocument(HttpContext context, bool sign) { SAML20FederationConfig configuration = ConfigurationReader.GetConfig<SAML20FederationConfig>(); KeyInfo keyinfo = new KeyInfo(); KeyInfoX509Data keyClause = new KeyInfoX509Data(ConfigurationReader.GetConfig<FederationConfig>().SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly); keyinfo.AddClause(keyClause); Saml20MetadataDocument doc = new Saml20MetadataDocument(configuration, keyinfo, sign); context.Response.Write(doc.ToXml( context.Response.ContentEncoding )); }
public void CanExtractEndpoints() { // Arrange var doc = new XmlDocument { PreserveWhitespace = true }; doc.Load(@"Protocol\MetadataDocs\metadata-ADLER.xml"); // Act var metadata = new Saml20MetadataDocument(doc); // Assert Assert.AreEqual(2, metadata.IDPSLOEndpoints.Count); Assert.AreEqual(2, metadata.SSOEndpoints.Count); }
/// <summary> /// Creates the metadata document. /// </summary> /// <param name="context">The context.</param> /// <param name="sign">if set to <c>true</c> sign the document.</param> public string CreateMetadataDocument(Encoding encoding, bool sign) { logger.Debug(TraceMessages.MetadataDocumentBeingCreated); var keyinfo = new System.Security.Cryptography.Xml.KeyInfo(); var keyClause = new System.Security.Cryptography.Xml.KeyInfoX509Data(configuration.ServiceProvider.SigningCertificate, X509IncludeOption.EndCertOnly); keyinfo.AddClause(keyClause); var doc = new Saml20MetadataDocument(configuration, keyinfo, sign); logger.Debug(TraceMessages.MetadataDocumentCreated); return doc.ToXml(encoding, configuration.ServiceProvider.SigningCertificate); }
private void CreateAssertionResponse(User user) { string entityId = request.Issuer.Value; Saml20MetadataDocument metadataDocument = IDPConfig.GetServiceProviderMetadata(entityId); IDPEndPointElement endpoint = metadataDocument.AssertionConsumerServiceEndpoints().Find(delegate(IDPEndPointElement e) { return(e.Binding == SAMLBinding.POST); }); if (endpoint == null) { Context.Response.Write(string.Format("'{0}' does not have a SSO endpoint that supports the POST binding.", entityId)); Context.Response.End(); return; } UserSessionsHandler.AddLoggedInSession(entityId); Response response = new Response(); response.Destination = endpoint.Url; response.InResponseTo = request.ID; response.Status = new Status(); response.Status.StatusCode = new StatusCode(); response.Status.StatusCode.Value = Saml20Constants.StatusCodes.Success; Assertion assertion = CreateAssertion(user, entityId); response.Items = new object[] { assertion }; // Serialize the response. XmlDocument assertionDoc = new XmlDocument(); assertionDoc.XmlResolver = null; assertionDoc.PreserveWhitespace = true; assertionDoc.LoadXml(Serialization.SerializeToXmlString(response)); // Sign the assertion inside the response message. XmlSignatureUtils.SignDocument(assertionDoc, assertion.ID, IDPConfig.IDPCertificate); HttpPostBindingBuilder builder = new HttpPostBindingBuilder(endpoint); builder.Action = SAMLAction.SAMLResponse; builder.Response = assertionDoc.OuterXml; builder.GetPage().ProcessRequest(Context); Context.Response.End(); }
/// <summary> /// Verify the request and transfer the login-page. /// </summary> /// <param name="parser"></param> private static void Signin(HttpRedirectBindingParser parser) { AuthnRequest req = Serialization.DeserializeFromXmlString <AuthnRequest>(parser.Message); // Retrieve metadata of requestor. string SPID = req.Issuer.Value; Saml20MetadataDocument SPmetadata = GetMetadata(SPID); if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata)) { HandleUnableToVerifySignature(SPID); return; } HttpContext.Current.Application["authenticationrequest"] = req; HttpContext.Current.Server.Transfer("SignonForm.aspx"); }
/// <summary> /// Creates the metadata document. /// </summary> /// <param name="context">The context.</param> /// <param name="sign">if set to <c>true</c> sign the document.</param> private void CreateMetadataDocument(HttpContext context, bool sign) { Logger.Debug(TraceMessages.MetadataDocumentBeingCreated); var configuration = Saml2Config.GetConfig(); var keyinfo = new KeyInfo(); var keyClause = new KeyInfoX509Data(Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly); keyinfo.AddClause(keyClause); var doc = new Saml20MetadataDocument(configuration, keyinfo, sign); Logger.Debug(TraceMessages.MetadataDocumentCreated); context.Response.Write(doc.ToXml(context.Response.ContentEncoding)); }
public void AddByMetadataUrl(Uri url) { var request = System.Net.WebRequest.Create(url); // It may be more efficient to pass the stream directly, but // it's likely a bit safer to pull the data off the response // stream and create a new memorystream with the data using (var ms = new MemoryStream()) { using (var response = request.GetResponse().GetResponseStream()) { response.CopyTo(ms); response.Close(); } ms.Seek(0, SeekOrigin.Begin); // Rewind memorystream back to the beginning // We want to allow exceptions to bubble up in this case var metadataDoc = new Saml20MetadataDocument(ms, GetEncodings()); AdjustIdpListWithNewMetadata(metadataDoc); } }
private void CreateMetadataDocument(HttpContext context, bool sign) { SAML20FederationConfig configuration = SAML20FederationConfig.GetConfig(); var keyinfos = new List <KeyInfo>(); foreach (Certificate certificate in FederationConfig.GetConfig().SigningCertificates) { KeyInfo keyinfo = new KeyInfo(); KeyInfoX509Data keyClause = new KeyInfoX509Data(certificate.GetCertificate(), X509IncludeOption.EndCertOnly); keyinfo.AddClause(keyClause); keyinfos.Add(keyinfo); } Saml20MetadataDocument doc = new Saml20MetadataDocument(configuration, keyinfos, sign); context.Response.Write(doc.ToXml(context.Response.ContentEncoding)); }
private static void HandleLogoutResponse(HttpRedirectBindingParser parser) { LogoutResponse res = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message); // Retrieve metadata of requestor. string SPID = res.Issuer.Value; Saml20MetadataDocument SPmetadata = GetMetadata(SPID); if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata)) { HandleUnableToVerifySignature(SPID); return; } // Remove the Service Provider from the list of the user's active sessions. UserSessionsHandler.RemoveLoggedInSession(SPID); Logout(); }
public void SignsXml() { // Arrange var doc = new Saml20MetadataDocument(true); var entity = doc.CreateDefaultEntity(); entity.ValidUntil = DateTime.Now.AddDays(14); // Act var metadata = doc.ToXml(); var document = new XmlDocument { PreserveWhitespace = true }; document.LoadXml(metadata); var result = XmlSignatureUtils.CheckSignature(document); // Assert Assert.That(result); }
private static void HandleLogoutRequest(HttpRedirectBindingParser parser) { LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.Message); // Retrieve metadata of requestor. string SPID = req.Issuer.Value; Saml20MetadataDocument SPmetadata = GetMetadata(SPID); if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata)) { HandleUnableToVerifySignature(SPID); return; } // Set the entity ID of the federation partner that initiated the logout. HttpContext.Current.Session[LOGOUTINITIATORKEY] = SPID; UserSessionsHandler.RemoveLoggedInSession(SPID); Logout(); }
public void CanExtractCertificatesOnStream() { Saml20MetadataDocument metadata; // Arrange using (var ms = new MemoryStream()) { using (var reader = File.OpenText(@"Protocol\MetadataDocs\metadata-ADLER.xml")) { reader.BaseStream.CopyTo(ms); reader.Close(); } ms.Seek(0, SeekOrigin.Begin); metadata = new Saml20MetadataDocument(ms, null); } // Assert Assert.That(metadata.GetKeys(KeyTypes.Signing).Count == 1); Assert.That(metadata.GetKeys(KeyTypes.Encryption).Count == 1); Assert.That(metadata.Keys[0].Use == KeyTypes.Signing); Assert.That(metadata.Keys[1].Use == KeyTypes.Encryption); Assert.AreEqual("ADLER_SAML20_ID", metadata.EntityId); }
public void SignsXml() { // Arrange var doc = new Saml20MetadataDocument(true); var entity = doc.CreateDefaultEntity(); entity.ValidUntil = DateTime.Now.AddDays(14); var certificate = new X509Certificate2(FileEmbeddedResource("SAML2.Tests.Certificates.sts_dev_certificate.pfx"), "test1234"); // Act var metadata = doc.ToXml(null, certificate); var document = new XmlDocument { PreserveWhitespace = true }; document.LoadXml(metadata); var result = XmlSignatureUtils.CheckSignature(document); // Assert Assert.That(result); }
public void CanExtractCertificates() { // Arrange var doc = new XmlDocument { PreserveWhitespace = true }; doc.Load(@"Protocol\MetadataDocs\metadata-ADLER.xml"); // Act var metadata = new Saml20MetadataDocument(doc); var certificateCheckResult = XmlSignatureUtils.CheckSignature(doc, (KeyInfo)metadata.Keys[0].KeyInfo); // Assert Assert.That(metadata.GetKeys(KeyTypes.Signing).Count == 1); Assert.That(metadata.GetKeys(KeyTypes.Encryption).Count == 1); Assert.That(metadata.Keys[0].Use == KeyTypes.Signing); Assert.That(metadata.Keys[1].Use == KeyTypes.Encryption); // The two certs in the metadata document happen to be identical, and are also // used for signing the entire document. // Extract the certificate and verify the document. Assert.That(certificateCheckResult); Assert.AreEqual("ADLER_SAML20_ID", metadata.EntityId); }
public void LoginWithIdentityProvider() { XmlDocument xDoc = new XmlDocument(); xDoc.PreserveWhitespace = true; xDoc.Load("idp.symplified.net.metadata.xml"); Saml20MetadataDocument idpMetadata = new Saml20MetadataDocument(xDoc); Saml20Authenticator authenticator = new Saml20Authenticator( "Symplified.Auth.iOS.Sample", idpMetadata ); authenticator.Completed += (s, e) => { loginViewController.DismissViewController(true, null); if (!e.IsAuthenticated) { samlLoginStatusStringElement.Caption = "Not authorized"; samlLoginStatusStringElement.GetActiveCell().BackgroundColor = UIColor.Red; } else { SamlAccount authenticatedAccount = (SamlAccount)e.Account; samlLoginStatusStringElement.Caption = String.Format("Name: {0}", authenticatedAccount.Assertion.Subject.Value); samlLoginStatusStringElement.GetActiveCell().BackgroundColor = UIColor.Green; } loginViewController.ReloadData(); }; vc = authenticator.GetUI(); loginViewController.PresentViewController(vc, true, null); }
/// <summary> /// Build a LogoutRequest and send it to the Federation Partner with the given entity ID. /// </summary> /// <param name="entityID"></param> private static void CreateLogoutRequest(string entityID) { User user = UserSessionsHandler.CurrentUser; Saml20LogoutRequest request = new Saml20LogoutRequest(); request.Issuer = IDPConfig.ServerBaseUrl; request.SessionIndex = Guid.NewGuid().ToString("N"); request.SubjectToLogOut = new NameID(); request.SubjectToLogOut.Format = Saml20Constants.NameIdentifierFormats.Unspecified; request.SubjectToLogOut.Value = user.Username; request.NotOnOrAfter = DateTime.UtcNow.AddMinutes(5); Saml20MetadataDocument metadata = GetMetadata(entityID); // HTTPRedirect(SAMLAction.SAMLRequest, metadata.SLOEndpoint(SAMLBinding.REDIRECT), request.GetXml()); HttpPostBindingBuilder builder = new HttpPostBindingBuilder(metadata.SLOEndpoint(SAMLBinding.POST)); builder.Action = SAMLAction.SAMLRequest; //builder.Response = assertionDoc.OuterXml; string xmloutput = request.GetXml().OuterXml; TextWriter tw = new StreamWriter("C:\\temp\\idp.txt", true); tw.WriteLine(xmloutput); tw.Close(); builder.Response = xmloutput; builder.GetPage().ProcessRequest(HttpContext.Current); HttpContext.Current.Response.End(); }
private void HandleSOAP(HttpContext context, Stream inputStream) { Trace.TraceMethodCalled(GetType(), "HandleSOAP"); HttpArtifactBindingParser parser = new HttpArtifactBindingParser(inputStream); HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context); SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); IDPEndPoint idp = RetrieveIDPConfiguration(parser.Issuer); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idp.ShaHashingAlgorithm); AuditLogging.IdpId = idp.Id; if (parser.IsArtifactResolve()) { Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResolveIn); if (!parser.CheckSamlMessageSignature(idp.metadata.Keys)) { HandleError(context, "Invalid Saml message signature"); AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, "Signature could not be verified", parser.SamlMessage); } AuditLogging.AssertionId = parser.ArtifactResolve.ID; AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, "", parser.SamlMessage); builder.RespondToArtifactResolve(idp, parser.ArtifactResolve); } else if (parser.IsArtifactResponse()) { Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResponseIn); Status status = parser.ArtifactResponse.Status; if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unexpected status code for artifact response: {0}, expected 'Success', msg: {1}", status.StatusCode.Value, parser.SamlMessage)); HandleError(context, status); return; } if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ELEMENT_NAME) { if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.ArtifactResponse.Any.OuterXml)); } //Send logoutresponse via artifact Saml20LogoutResponse response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.ArtifactResponse.Any.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = req.ID; IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idp.SLOEndpoint, idp.metadata.SLOEndpoints()); builder.RedirectFromLogout(idp, destination, response); } else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ELEMENT_NAME) { DoLogout(context); } else { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported payload message in ArtifactResponse: {0}, msg: {1}", parser.ArtifactResponse.Any.LocalName, parser.SamlMessage)); HandleError(context, string.Format("Unsupported payload message in ArtifactResponse: {0}", parser.ArtifactResponse.Any.LocalName)); } } else if (parser.IsLogoutReqest()) { if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.SamlMessage.OuterXml)); } Saml20LogoutResponse response = new Saml20LogoutResponse(); if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present in SOAP logout request, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } if (idp.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + parser.Issuer); // Not able to process the request as we do not know the IdP. response.StatusCode = Saml20Constants.StatusCodes.NoAvailableIDP; } else { Saml20MetadataDocument metadata = idp.metadata; if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature SOAP logout, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } } if (parser.GetNameID() != null && !string.IsNullOrEmpty(parser.GetNameID().Value)) { DoSoapLogout(context, parser.GetNameID().Value); } else { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. No user ID was supplied in SOAP logout request, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.NoAuthnContext; } LogoutRequest req = parser.LogoutRequest; //Build the response object response.Issuer = config.ServiceProvider.ID; response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = req.ID; XmlDocument doc = response.GetXml(); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(doc, response.ID, signingCertificate); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } builder.SendResponseMessage(doc.OuterXml); } else { Status s = parser.GetStatus(); if (s != null) { HandleError(context, s); } else { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported SamlMessage element: {0}, msg: {1}", parser.SamlMessageName, parser.SamlMessage)); HandleError(context, string.Format("Unsupported SamlMessage element: {0}", parser.SamlMessageName)); } } }
private void HandleRequest(HttpContext context) { Trace.TraceMethodCalled(GetType(), "HandleRequest()"); //Fetch config object SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); LogoutRequest logoutRequest = null; IDPEndPoint endpoint = null; string message = string.Empty; //Build the response object var response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; response.StatusCode = Saml20Constants.StatusCodes.Success; // Default success. Is overwritten if something fails. if(context.Request.RequestType == "GET") // HTTP Redirect binding { HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, string.Format("Binding: redirect, Signature algorithm: {0} Signature: {1}, Message: {2}", parser.SignatureAlgorithm, parser.Signature, parser.Message)); if (!parser.IsSigned) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } logoutRequest = parser.LogoutRequest; endpoint = config.FindEndPoint(logoutRequest.Issuer.Value); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + logoutRequest.Issuer.Value); // Not able to return a response as we do not know the IdP. HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value); return; } Saml20MetadataDocument metadata = endpoint.metadata; if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature redirect-binding, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } message = parser.Message; } else if (context.Request.RequestType == "POST") // HTTP Post binding { HttpPostBindingParser parser = new HttpPostBindingParser(context); AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Binding: POST, Message: " + parser.Message); if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } logoutRequest = parser.LogoutRequest; endpoint = config.FindEndPoint(logoutRequest.Issuer.Value); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP"); // Not able to return a response as we do not know the IdP. HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value); return; } Saml20MetadataDocument metadata = endpoint.metadata; // handle a logout-request if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature post-binding, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } message = parser.Message; }else { //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS // Not able to return a response as we do not understand the request. HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType)); } AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message); // Check that idp in session and request matches. string idpRequest = logoutRequest.Issuer.Value; if (!context.Session.IsNewSession) { object idpSession = context.Session[IDPLoginSessionKey]; if (idpSession != null && idpSession.ToString() != idpRequest) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, Resources.IdPMismatchBetweenRequestAndSessionFormat(idpSession, idpRequest), message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } } else { // All other status codes than Success results in the IdP throwing an error page. Therefore we return default Success even if we do not have a session. AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Session does not exist. Continues the redirect logout procedure with status code success." + idpRequest, message); } // Only logout if request is valid and we are working on an existing Session. if (Saml20Constants.StatusCodes.Success == response.StatusCode && !context.Session.IsNewSession) { // Execute all actions that the service provider has configured DoLogout(context, true); } // Update the response object with informations that first is available when request has been parsed. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints()); response.Destination = destination.Url; response.InResponseTo = logoutRequest.ID; //Respond using redirect binding if(destination.Binding == SAMLBinding.REDIRECT) { HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.RelayState = context.Request.Params["RelayState"]; builder.Response = response.GetXml().OuterXml; builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey; string s = destination.Url + "?" + builder.ToQuery(); context.Response.Redirect(s, true); return; } //Respond using post binding if (destination.Binding == SAMLBinding.POST) { HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination); builder.Action = SAMLAction.SAMLResponse; XmlDocument responseDocument = response.GetXml(); XmlSignatureUtils.SignDocument(responseDocument, response.ID); builder.Response = responseDocument.OuterXml; builder.RelayState = context.Request.Params["RelayState"]; builder.GetPage().ProcessRequest(context); return; } }
public void Parse_metadata_from_xml_test_idp() { var metadata = new Saml20MetadataDocument().Load(FileLoadUtils.GetStream(Path.Combine("Protocol", "MetadataDocs", "inlogik-test-adfs-metadata.xml"))); var a = metadata.EntityId; }
private void CreateAssertionResponse(User user) { string entityId = request.Issuer.Value; Saml20MetadataDocument metadataDocument = IDPConfig.GetServiceProviderMetadata(entityId); IDPEndPointElement endpoint = metadataDocument.AssertionConsumerServiceEndpoints().Find(delegate(IDPEndPointElement e) { return(e.Binding == SAMLBinding.POST); }); if (endpoint == null) { Context.Response.Write(string.Format("'{0}' does not have a SSO endpoint that supports the POST binding.", entityId)); Context.Response.End(); return; } UserSessionsHandler.AddLoggedInSession(entityId); Response response = new Response(); response.Destination = endpoint.Url; response.InResponseTo = request.ID; response.Status = new Status(); response.Status.StatusCode = new StatusCode(); response.Status.StatusCode.Value = Saml20Constants.StatusCodes.Success; var nameIdFormat = metadataDocument.Entity.Items.OfType <SPSSODescriptor>().SingleOrDefault()?.NameIDFormat.SingleOrDefault() ?? Saml20Constants.NameIdentifierFormats.Persistent; Assertion assertion = CreateAssertion(user, entityId, nameIdFormat); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm.SHA256); EncryptedAssertion encryptedAssertion = null; var keyDescriptors = metadataDocument.Keys.Where(x => x.use == KeyTypes.encryption); if (keyDescriptors.Any()) { foreach (KeyDescriptor keyDescriptor in keyDescriptors) { KeyInfo ki = (KeyInfo)keyDescriptor.KeyInfo; foreach (KeyInfoClause clause in ki) { if (clause is KeyInfoX509Data) { X509Certificate2 cert = XmlSignatureUtils.GetCertificateFromKeyInfo((KeyInfoX509Data)clause); var spec = new DefaultCertificateSpecification(); string error; if (spec.IsSatisfiedBy(cert, out error)) { AsymmetricAlgorithm key = XmlSignatureUtils.ExtractKey(clause); AssertionEncryptionUtility.AssertionEncryptionUtility encryptedAssertionUtil = new AssertionEncryptionUtility.AssertionEncryptionUtility((RSA)key, assertion); // Sign the assertion inside the response message. signatureProvider.SignAssertion(encryptedAssertionUtil.Assertion, assertion.ID, IDPConfig.IDPCertificate); encryptedAssertionUtil.Encrypt(); encryptedAssertion = Serialization.DeserializeFromXmlString <EncryptedAssertion>(encryptedAssertionUtil.EncryptedAssertion.OuterXml); break; } } } if (encryptedAssertion != null) { break; } } if (encryptedAssertion == null) { throw new Exception("Could not encrypt. No valid certificates found."); } } if (encryptedAssertion != null) { response.Items = new object[] { encryptedAssertion }; } else { response.Items = new object[] { assertion }; } // Serialize the response. XmlDocument responseDoc = new XmlDocument(); responseDoc.XmlResolver = null; responseDoc.PreserveWhitespace = true; responseDoc.LoadXml(Serialization.SerializeToXmlString(response)); if (encryptedAssertion == null) { // Sign the assertion inside the response message. signatureProvider.SignAssertion(responseDoc, assertion.ID, IDPConfig.IDPCertificate); } HttpPostBindingBuilder builder = new HttpPostBindingBuilder(endpoint); builder.Action = SAMLAction.SAMLResponse; builder.Response = responseDoc.OuterXml; builder.GetPage().ProcessRequest(Context); Context.Response.End(); }
private void HandleRequest(HttpContext context) { Trace.TraceMethodCalled(GetType(), "HandleRequest()"); //Fetch config object SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); LogoutRequest logoutRequest = null; IDPEndPoint endpoint = null; string message = string.Empty; //Build the response object var response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; response.StatusCode = Saml20Constants.StatusCodes.Success; // Default success. Is overwritten if something fails. if (context.Request.RequestType == "GET") // HTTP Redirect binding { HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, string.Format("Binding: redirect, Signature algorithm: {0} Signature: {1}, Message: {2}", parser.SignatureAlgorithm, parser.Signature, parser.Message)); if (!parser.IsSigned) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } logoutRequest = parser.LogoutRequest; endpoint = config.FindEndPoint(logoutRequest.Issuer.Value); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + logoutRequest.Issuer.Value); // Not able to return a response as we do not know the IdP. HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value); return; } Saml20MetadataDocument metadata = endpoint.metadata; if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature redirect-binding, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } message = parser.Message; } else if (context.Request.RequestType == "POST") // HTTP Post binding { HttpPostBindingParser parser = new HttpPostBindingParser(context); AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Binding: POST, Message: " + parser.Message); if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } logoutRequest = parser.LogoutRequest; endpoint = config.FindEndPoint(logoutRequest.Issuer.Value); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP"); // Not able to return a response as we do not know the IdP. HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value); return; } if (logoutRequest.NotOnOrAfter.HasValue) { var allowedClockSkewTime = DateTime.UtcNow.AddMinutes(FederationConfig.GetConfig().AllowedClockSkewMinutes); if (logoutRequest.NotOnOrAfter >= allowedClockSkewTime) { var errormessage = $"Logout request NotOnOrAfter ({logoutRequest.NotOnOrAfter}) is after allowed time ({allowedClockSkewTime})"; AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, errormessage); HandleError(context, errormessage); return; } } Saml20MetadataDocument metadata = endpoint.metadata; // handle a logout-request if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature post-binding, msg: " + parser.Message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } message = parser.Message; } else { //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS // Not able to return a response as we do not understand the request. HandleError(context, string.Format(Resources.UnsupportedRequestType, context.Request.RequestType)); return; } AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message); // Check that idp in session and request matches. string idpRequest = logoutRequest.Issuer.Value; // SessionFactory.SessionContext.Current.New is never the first call to Current due to the logic in Application_AuthenticateRequest() ... Saml20Identity.IsInitialized() // Hence we need to check on Saml20Identity.IsInitialized() instead of using SessionFactory.SessionContext.Current.New. bool isOioSamlSessionActive = Saml20Identity.IsInitialized(); if (isOioSamlSessionActive) { object idpId = Saml20PrincipalCache.GetSaml20AssertionLite().Issuer; if (idpId != null && idpId.ToString() != idpRequest) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, string.Format(Resources.IdPMismatchBetweenRequestAndSession, idpId, idpRequest), message); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } } else { // All other status codes than Success results in the IdP throwing an error page. Therefore we return default Success even if we do not have a session. AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Session does not exist. Continues the redirect logout procedure with status code success." + idpRequest, message); } // Only logout if request is valid and we are working on an existing Session. if (Saml20Constants.StatusCodes.Success == response.StatusCode && isOioSamlSessionActive) { // Execute all actions that the service provider has configured DoLogout(context, true); } // Update the response object with informations that first is available when request has been parsed. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints()); response.Destination = destination.Url; response.InResponseTo = logoutRequest.ID; //Respond using redirect binding var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(endpoint.ShaHashingAlgorithm); if (destination.Binding == SAMLBinding.REDIRECT) { HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.RelayState = context.Request.Params["RelayState"]; builder.Response = response.GetXml().OuterXml; builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey; builder.ShaHashingAlgorithm = shaHashingAlgorithm; string s = destination.Url + "?" + builder.ToQuery(); context.Response.Redirect(s, true); return; } //Respond using post binding if (destination.Binding == SAMLBinding.POST) { HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination); builder.Action = SAMLAction.SAMLResponse; XmlDocument responseDocument = response.GetXml(); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(responseDocument, response.ID, signingCertificate); builder.Response = responseDocument.OuterXml; builder.RelayState = context.Request.Params["RelayState"]; builder.GetPage().ProcessRequest(context); return; } }
public void Serialize_metadata_to_xml_empty_constructor_should_throw_exception() { var metadata = new Saml20MetadataDocument(); Assert.Throws <System.InvalidOperationException>(() => metadata.ToXml()); }
/// <summary> /// Checks the signature of a message received using the redirect binding using the keys found in the /// metadata of the federation partner that sent the request. /// </summary> protected static bool CheckRedirectSignature(HttpRedirectBindingParser parser, Saml20MetadataDocument metadata) { List <KeyDescriptor> keys = metadata.GetKeys(KeyTypes.signing); // Go through the list of signing keys (usually only one) and use it to verify the REDIRECT request. foreach (KeyDescriptor key in keys) { KeyInfo keyinfo = (KeyInfo)key.KeyInfo; foreach (KeyInfoClause keyInfoClause in keyinfo) { AsymmetricAlgorithm signatureKey = XmlSignatureUtils.ExtractKey(keyInfoClause); if (signatureKey != null && parser.CheckSignature(signatureKey)) { return(true); } } } return(false); }
private void HandleRequest(HttpContext context) { Trace.TraceMethodCalled(GetType(), "HandleRequest()"); //Fetch the endpoint configuration IDPEndPoint idpEndpoint = RetrieveIDPConfiguration(context.Session[IDPLoginSessionKey].ToString()); IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SLOEndpoint, idpEndpoint.metadata.SLOEndpoints()); //Fetch config object SAML20FederationConfig config = ConfigurationReader.GetConfig <SAML20FederationConfig>(); //Build the response object Saml20LogoutResponse response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; response.Destination = destination.Url; response.StatusCode = Saml20Constants.StatusCodes.Success; string message = string.Empty; if (context.Request.RequestType == "GET") // HTTP Redirect binding { HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); IDPEndPoint endpoint = config.FindEndPoint(idpEndpoint.Id); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP"); HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id); return; } Saml20MetadataDocument metadata = endpoint.metadata; if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature redirect-binding, msg: " + parser.Message); HandleError(context, Resources.SignatureInvalid); return; } message = parser.Message; } else if (context.Request.RequestType == "POST") // HTTP Post binding { HttpPostBindingParser parser = new HttpPostBindingParser(context); if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message); HandleError(context, Resources.SignatureNotPresent); } IDPEndPoint endpoint = config.FindEndPoint(idpEndpoint.Id); if (endpoint.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP"); HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id); return; } Saml20MetadataDocument metadata = endpoint.metadata; // handle a logout-request if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature post-binding, msg: " + parser.Message); HandleError(context, Resources.SignatureInvalid); } message = parser.Message; } else { //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType)); } AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message); //Log the user out locally DoLogout(context, true); LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(message); response.InResponseTo = req.ID; //Respond using redirect binding if (destination.Binding == SAMLBinding.REDIRECT) { HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.RelayState = context.Request.Params["RelayState"]; builder.Response = response.GetXml().OuterXml; builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey; string s = destination.Url + "?" + builder.ToQuery(); context.Response.Redirect(s, true); return; } //Respond using post binding if (destination.Binding == SAMLBinding.POST) { HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination); builder.Action = SAMLAction.SAMLResponse; XmlDocument responseDocument = response.GetXml(); XmlSignatureUtils.SignDocument(responseDocument, response.ID); builder.Response = responseDocument.OuterXml; builder.RelayState = context.Request.Params["RelayState"]; builder.GetPage().ProcessRequest(context); return; } }
public void Parse_metadata_from_xml() { var metadata = new Saml20MetadataDocument().Load(FileLoadUtils.GetStream(Path.Combine("Protocol", "MetadataDocs", "metadata-HAIKU.xml"))); }
public void Serialize_metatdata_from_configuration_not_signed() { var metadata = new Saml20MetadataDocument().Load(_context.Config); Assert.NotEmpty(metadata.ToXml()); }