/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action<string, object> cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> public void RedirectFromLogout(IDPEndPointElement destination, Saml20LogoutResponse response) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); Int16 index = (Int16)config.ServiceProvider.LogoutEndpoint.endPointIndex; XmlDocument doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID); ArtifactRedirect(destination, index, doc); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> public void RedirectFromLogout(IdentityProviderEndpointElement destination, Saml20LogoutResponse response) { var config = Saml2Config.GetConfig(); var index = (short)config.ServiceProvider.Endpoints.LogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action <string, object> cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID, config); ArtifactRedirect(destination, index, doc, relayState, cacheInsert); }
/// <summary> /// Handles the SOAP message. /// </summary> /// <param name="context">The context.</param> /// <param name="inputStream">The input stream.</param> private async Task HandleSoap(IOwinContext context, Stream inputStream, NameValueCollection requestParams) { var config = options.Configuration; var parser = new HttpArtifactBindingParser(inputStream); Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml); var builder = GetBuilder(context); var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config); if (parser.IsLogoutReqest) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml); if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) { Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid); throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid); } var req = parser.LogoutRequest; var logoutRequestReceivedNotification = new LogoutRequestReceivedNotification <LogoutRequest, SamlAuthenticationOptions>(context, options) { ProtocolMessage = req }; await options.Notifications.LogoutRequestReceived(logoutRequestReceivedNotification); DoLogout(context, true); // Build the response object var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, StatusCode = Saml20Constants.StatusCodes.Success, InResponseTo = req.Id }; // response.Destination = destination.Url; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Id, config.ServiceProvider.SigningCertificate); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } SendResponseMessage(doc.OuterXml, context); } else { Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage); throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage); } }
/// <summary> /// Build a LogoutResponse and send it to the federation partner with the given entity ID. /// </summary> /// <param name="entityID"></param> private static void CreateLogoutResponse(string entityID) { Saml20MetadataDocument metadata = GetMetadata(entityID); //IDPEndPointElement endpoint = metadata.SLOEndpoint(SAMLBinding.REDIRECT); IDPEndPointElement endpoint = metadata.SLOEndpoint(SAMLBinding.POST); Saml20LogoutResponse response = new Saml20LogoutResponse(); response.Issuer = IDPConfig.ServerBaseUrl; response.Destination = endpoint.Url; response.StatusCode = Saml20Constants.StatusCodes.Success; HTTPRedirect(SAMLAction.SAMLResponse, endpoint, response.GetXml()); }
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; } }
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; } }
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; } }
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); 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(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; IDPEndPoint endpoint = RetrieveIDPConfiguration(context.Session[IDPLoginSessionKey].ToString()); IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints()); builder.RedirectFromLogout(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)); LogoutRequest req = parser.LogoutRequest; //Build the response object Saml20LogoutResponse response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; //response.Destination = destination.Url; response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = req.ID; XmlDocument doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.ID); 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)); } } }
/// <summary> /// Handles the SOAP message. /// </summary> /// <param name="context">The context.</param> /// <param name="inputStream">The input stream.</param> private void HandleSoap(HttpContext context, Stream inputStream) { var parser = new HttpArtifactBindingParser(inputStream); Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml); var builder = new HttpArtifactBindingBuilder(context); var config = Saml2Config.GetConfig(); var idp = RetrieveIDPConfiguration(parser.Issuer); if (parser.IsArtifactResolve) { Logger.DebugFormat(TraceMessages.ArtifactResolveReceived, parser.SamlMessage); if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) { Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid); throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid); } builder.RespondToArtifactResolve(parser.ArtifactResolve); } else if (parser.IsArtifactResponse) { Logger.DebugFormat(TraceMessages.ArtifactResponseReceived, parser.SamlMessage); if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) { Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid); throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid); } var status = parser.ArtifactResponse.Status; if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value); throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value)); } if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ElementName) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.ArtifactResponse.Any.OuterXml); var req = Serialization.DeserializeFromXmlString<LogoutRequest>(parser.ArtifactResponse.Any.OuterXml); // Send logoutresponse via artifact var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, StatusCode = Saml20Constants.StatusCodes.Success, InResponseTo = req.Id }; var endpoint = RetrieveIDPConfiguration(StateService.Get<string>(IdpLoginSessionKey)); var destination = DetermineEndpointConfiguration(BindingType.Redirect, endpoint.Endpoints.LogoutEndpoint, endpoint.Metadata.IDPSLOEndpoints); builder.RedirectFromLogout(destination, response); } else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ElementName) { DoLogout(context); } else { Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse); throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse); } } else if (parser.IsLogoutReqest) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml); var req = parser.LogoutRequest; // Build the response object var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, StatusCode = Saml20Constants.StatusCodes.Success, InResponseTo = req.Id }; // response.Destination = destination.Url; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Id); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } builder.SendResponseMessage(doc.OuterXml); } else { Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage); throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage); } }
/// <summary> /// Handles the request. /// </summary> /// <param name="context">The context.</param> private void HandleRequest(HttpContext context) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived); // Fetch the endpoint configuration var idp = RetrieveIDPConfiguration(StateService.Get<string>(IdpLoginSessionKey)); var destination = DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.LogoutEndpoint, idp.Metadata.IDPSLOEndpoints); // Fetch config object var config = Saml2Config.GetConfig(); // Build the response object var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, Destination = destination.Url, StatusCode = Saml20Constants.StatusCodes.Success }; string message; if (context.Request.RequestType == "GET") { // HTTP Redirect binding var parser = new HttpRedirectBindingParser(context.Request.Url); Logger.DebugFormat(TraceMessages.LogoutRequestRedirectBindingParse, parser.Message, parser.SignatureAlgorithm, parser.Signature); var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id); if (endpoint == null || endpoint.Metadata == null) { Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id); throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id)); } var metadata = endpoint.Metadata; if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.Signing))) { Logger.Error(ErrorMessages.RequestSignatureInvalid); throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid); } message = parser.Message; } else if (context.Request.RequestType == "POST") { // HTTP Post binding var parser = new HttpPostBindingParser(context); Logger.DebugFormat(TraceMessages.LogoutRequestPostBindingParse, parser.Message); if (!parser.IsSigned) { Logger.Error(ErrorMessages.RequestSignatureMissing); throw new Saml20Exception(ErrorMessages.RequestSignatureMissing); } var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id); if (endpoint == null || endpoint.Metadata == null) { Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id); throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id)); } var metadata = endpoint.Metadata; // Check signature if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.Signing))) { Logger.Error(ErrorMessages.RequestSignatureInvalid); throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid); } message = parser.Message; } else { // Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS Logger.ErrorFormat(ErrorMessages.UnsupportedRequestType, context.Request.RequestType); throw new Saml20Exception(string.Format(ErrorMessages.UnsupportedRequestType, context.Request.RequestType)); } Logger.DebugFormat(TraceMessages.LogoutRequestParsed, message); // Log the user out locally DoLogout(context, true); var req = Serialization.DeserializeFromXmlString<LogoutRequest>(message); response.InResponseTo = req.Id; // Respond using redirect binding if (destination.Binding == BindingType.Redirect) { var builder = new HttpRedirectBindingBuilder { RelayState = context.Request.Params["RelayState"], Response = response.GetXml().OuterXml, SigningKey = Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate().PrivateKey }; Logger.DebugFormat(TraceMessages.LogoutResponseSent, builder.Response); context.Response.Redirect(destination.Url + "?" + builder.ToQuery(), true); return; } // Respond using post binding if (destination.Binding == BindingType.Post) { var builder = new HttpPostBindingBuilder(destination) { Action = SamlActionType.SAMLResponse }; var responseDocument = response.GetXml(); Logger.DebugFormat(TraceMessages.LogoutResponseSent, responseDocument.OuterXml); XmlSignatureUtils.SignDocument(responseDocument, response.Id); builder.Response = responseDocument.OuterXml; builder.RelayState = context.Request.Params["RelayState"]; builder.GetPage().ProcessRequest(context); } }
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)); } } }
/// <summary> /// Creates an artifact for the LogoutResponse and redirects the user to the IdP. /// </summary> /// <param name="idpEndPoint">The IdP endpoint</param> /// <param name="destination">The destination of the response.</param> /// <param name="response">The logout response.</param> public void RedirectFromLogout(IDPEndPoint idpEndPoint, IDPEndPointElement destination, Saml20LogoutResponse response) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); Int16 index = (Int16)config.ServiceProvider.LogoutEndpoint.endPointIndex; XmlDocument doc = response.GetXml(); var signingCertificate = FederationConfig.GetConfig().GetFirstValidCertificate(); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndPoint.ShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(doc, response.Response.ID, signingCertificate); ArtifactRedirect(destination, index, doc); }
/// <summary> /// Handles the request. /// </summary> /// <param name="context">The context.</param> private void HandleRequest(HttpContext context) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived); // Fetch the endpoint configuration var idp = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], ConfigurationFactory.Instance.Configuration); var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints); // Fetch config object var config = ConfigurationFactory.Instance.Configuration; // Build the response object var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, Destination = destination.Url, StatusCode = Saml20Constants.StatusCodes.Success }; string message; if (context.Request.RequestType == "GET") { // HTTP Redirect binding var parser = new HttpRedirectBindingParser(context.Request.Url); Logger.DebugFormat(TraceMessages.LogoutRequestRedirectBindingParse, parser.Message, parser.SignatureAlgorithm, parser.Signature); var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id); if (endpoint == null || endpoint.Metadata == null) { Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id); throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id)); } var metadata = endpoint.Metadata; if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.Signing))) { Logger.Error(ErrorMessages.RequestSignatureInvalid); throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid); } message = parser.Message; } else if (context.Request.RequestType == "POST") { // HTTP Post binding var parser = new HttpPostBindingParser(context.Request.Params); Logger.DebugFormat(TraceMessages.LogoutRequestPostBindingParse, parser.Message); if (!parser.IsSigned) { Logger.Error(ErrorMessages.RequestSignatureMissing); throw new Saml20Exception(ErrorMessages.RequestSignatureMissing); } var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id); if (endpoint == null || endpoint.Metadata == null) { Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id); throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id)); } var metadata = endpoint.Metadata; // Check signature if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.Signing))) { Logger.Error(ErrorMessages.RequestSignatureInvalid); throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid); } message = parser.Message; } else { // Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS Logger.ErrorFormat(ErrorMessages.UnsupportedRequestType, context.Request.RequestType); throw new Saml20Exception(string.Format(ErrorMessages.UnsupportedRequestType, context.Request.RequestType)); } Logger.DebugFormat(TraceMessages.LogoutRequestParsed, message); // Log the user out locally DoLogout(context, true); var req = Serialization.DeserializeFromXmlString <LogoutRequest>(message); response.InResponseTo = req.Id; // Respond using redirect binding if (destination.Binding == BindingType.Redirect) { var builder = new HttpRedirectBindingBuilder { RelayState = context.Request.Params["RelayState"], Response = response.GetXml().OuterXml, SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey }; Logger.DebugFormat(TraceMessages.LogoutResponseSent, builder.Response); context.Response.Redirect(destination.Url + "?" + builder.ToQuery(), true); return; } // Respond using post binding if (destination.Binding == BindingType.Post) { var builder = new HttpPostBindingBuilder(destination) { Action = SamlActionType.SAMLResponse }; var responseDocument = response.GetXml(); Logger.DebugFormat(TraceMessages.LogoutResponseSent, responseDocument.OuterXml); XmlSignatureUtils.SignDocument(responseDocument, response.Id, config); builder.Response = responseDocument.OuterXml; builder.RelayState = context.Request.Params["RelayState"]; context.Response.Write(builder.GetPage()); } }
/// <summary> /// Handles the SOAP message. /// </summary> /// <param name="context">The context.</param> /// <param name="inputStream">The input stream.</param> private void HandleSoap(HttpContext context, Stream inputStream, Saml2Configuration config) { var parser = new HttpArtifactBindingParser(inputStream); Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml); var builder = GetBuilder(context); var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config); if (parser.IsArtifactResolve) { Logger.DebugFormat(TraceMessages.ArtifactResolveReceived, parser.SamlMessage); if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) { Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid); throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid); } builder.RespondToArtifactResolve(parser.ArtifactResolve, parser.SamlMessage); } else if (parser.IsArtifactResponse) { Logger.DebugFormat(TraceMessages.ArtifactResponseReceived, parser.SamlMessage); if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) { Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid); throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid); } var status = parser.ArtifactResponse.Status; if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value); throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value)); } if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ElementName) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.ArtifactResponse.Any.OuterXml); var req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.ArtifactResponse.Any.OuterXml); // Send logoutresponse via artifact var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, StatusCode = Saml20Constants.StatusCodes.Success, InResponseTo = req.Id }; var endpoint = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], config); var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, endpoint.Endpoints.DefaultLogoutEndpoint, endpoint.Metadata.IDPSLOEndpoints); builder.RedirectFromLogout(destination, response, context.Request.Params["relayState"], (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration)); } else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ElementName) { DoLogout(context, false, config); } else { Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse); throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse); } } else if (parser.IsLogoutReqest) { Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml); var req = parser.LogoutRequest; // Build the response object var response = new Saml20LogoutResponse { Issuer = config.ServiceProvider.Id, StatusCode = Saml20Constants.StatusCodes.Success, InResponseTo = req.Id }; // response.Destination = destination.Url; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Id, config); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } SendResponseMessage(doc.OuterXml, context); } else { Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage); throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage); } }
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; } }