/// <summary> /// Resolves an artifact. /// </summary> /// <returns>A stream containing the artifact response from the IdP</returns> /// <param name="artifact">artifact from request ("SAMLart")</param> public Stream ResolveArtifact(string artifact, string relayState, Saml2Configuration config) { var idpEndPoint = DetermineIdp(artifact); if (idpEndPoint == null) { throw new InvalidOperationException(ErrorMessages.ArtifactResolveIdentityProviderUnknown); } var endpointIndex = ArtifactUtil.GetEndpointIndex(artifact); var endpointUrl = idpEndPoint.Metadata.GetIDPARSEndpoint(endpointIndex); _logger.LogDebug(TraceMessages.ArtifactResolveForKnownIdentityProvider, artifact, idpEndPoint.Id, endpointUrl); var resolve = Saml20ArtifactResolve.GetDefault(config.ServiceProvider.Id); resolve.Artifact = artifact; var doc = resolve.GetXml(); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } XmlSignatureUtils.SignDocument(doc, resolve.Id, config); var artifactResolveString = doc.OuterXml; _logger.LogDebug(TraceMessages.ArtifactResolved, artifactResolveString); return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution, relayState)); }
/// <summary> /// Resolves an artifact. /// </summary> /// <returns>A stream containing the artifact response from the IdP</returns> public Stream ResolveArtifact() { var artifact = Context.Request.Params["SAMLart"]; var idpEndPoint = DetermineIdp(artifact); if (idpEndPoint == null) { throw new InvalidOperationException(ErrorMessages.ArtifactResolveIdentityProviderUnknown); } var endpointIndex = ArtifactUtil.GetEndpointIndex(artifact); var endpointUrl = idpEndPoint.Metadata.GetIDPARSEndpoint(endpointIndex); Logger.DebugFormat(TraceMessages.ArtifactResolveForKnownIdentityProvider, artifact, idpEndPoint.Id, endpointUrl); var config = ConfigurationFactory.Instance.Configuration; var resolve = Saml20ArtifactResolve.GetDefault(config.ServiceProvider.Id); resolve.Artifact = artifact; var doc = resolve.GetXml(); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } XmlSignatureUtils.SignDocument(doc, resolve.Id, config.ServiceProvider.SigningCertificate); var artifactResolveString = doc.OuterXml; Logger.DebugFormat(TraceMessages.ArtifactResolved, artifactResolveString); return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution)); }
/// <summary> /// Resolves an artifact. /// </summary> /// <returns>A stream containing the artifact response from the IdP</returns> public Stream ResolveArtifact(string artifact, string artifactResolveEndpoint, string serviceProviderId, X509Certificate2 cert) { if (artifactResolveEndpoint == null) { throw new InvalidOperationException("Received artifact from unknown IDP."); } var resolve = new Saml2ArtifactResolve { Issuer = serviceProviderId, Artifact = artifact }; var doc = resolve.GetXml(); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } XmlSignatureUtils.SignDocument(doc, resolve.ID, cert); var artifactResolveString = doc.OuterXml; return(GetResponse(artifactResolveEndpoint, artifactResolveString)); }
private static void SignMessage(ref XDocument xDocument, X509Certificate2 clientCertificate) { // Add id's to elements that needs to be signed. var namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("a", WsaNamespace); namespaceManager.AddNamespace("s", S11Namespace); namespaceManager.AddNamespace("wsse", Wsse10Namespace); namespaceManager.AddNamespace("wsu", WsuNamespace); var actionElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:Action", namespaceManager); var msgElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:MessageID", namespaceManager); var toElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:To", namespaceManager); var timeStampElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/wsu:Timestamp", namespaceManager); var binarySecurityTokenElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/wsse:BinarySecurityToken", namespaceManager); var bodyElement = xDocument.XPathSelectElement("/s:Envelope/s:Body", namespaceManager); var idXName = XName.Get("Id", WsuNamespace); actionElement.Add(new XAttribute(idXName, ActionIdValue)); msgElement.Add(new XAttribute(idXName, MessageIdIdValue)); toElement.Add(new XAttribute(idXName, ToIdValue)); timeStampElement.Add(new XAttribute(idXName, TimeStampIdValue)); binarySecurityTokenElement.Add(new XAttribute(idXName, BinarySecurityTokenIdValue)); bodyElement.Add(new XAttribute(idXName, BodyIdValue)); var idOfElementsThatMustBeSigned = new List <string> { ActionIdValue, MessageIdIdValue, ToIdValue, TimeStampIdValue, BinarySecurityTokenIdValue, BodyIdValue }; xDocument = XmlSignatureUtils.SignDocument(xDocument, idOfElementsThatMustBeSigned, clientCertificate); }
/// <summary> /// Resolves an artifact. /// </summary> /// <param name="providerName"></param> /// <returns>A stream containing the artifact response from the IdP</returns> public Stream ResolveArtifact(string providerName) { var artifactResolveEndpoint = _configurationProvider.GetIdentityProviderConfiguration(providerName).ArtifactResolveService; if (artifactResolveEndpoint == null) { throw new InvalidOperationException("Received artifact from unknown IDP."); } var serviceProviderId = _configurationProvider.ServiceProviderConfiguration.EntityId; var artifact = GetArtifact(); var resolve = new Saml2ArtifactResolve { Issuer = serviceProviderId, Artifact = artifact }; var doc = resolve.GetXml(); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } var cert = _configurationProvider.ServiceProviderSigningCertificate(); XmlSignatureUtils.SignDocument(doc, resolve.ID, cert); var artifactResolveString = doc.OuterXml; return(GetResponse(artifactResolveEndpoint, artifactResolveString)); }
/// <summary> /// Handles responses to an artifact resolve message. /// </summary> /// <param name="artifactResolve">The artifact resolve message.</param> public void RespondToArtifactResolve(ArtifactResolve artifactResolve) { XmlDocument samlDoc = (XmlDocument)_context.Cache.Get(artifactResolve.Artifact); Saml20ArtifactResponse response = Saml20ArtifactResponse.GetDefault(); response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = artifactResolve.ID; response.SamlElement = samlDoc.DocumentElement; XmlDocument responseDoc = response.GetXml(); if (responseDoc.FirstChild is XmlDeclaration) { responseDoc.RemoveChild(responseDoc.FirstChild); } XmlSignatureUtils.SignDocument(responseDoc, response.ID); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.RespondToArtifactResolve, artifactResolve.Artifact, responseDoc.OuterXml)); } SendResponseMessage(responseDoc.OuterXml); }
/// <summary> /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The logout request.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IDPEndPointElement destination, Saml20LogoutRequest request, string relayState) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); Int16 index = (Int16)config.ServiceProvider.LogoutEndpoint.endPointIndex; XmlDocument doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.ID); ArtifactRedirect(destination, index, doc, relayState); }
/// <summary> /// Creates an artifact and redirects the user to the IdP /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The authentication request.</param> public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request) { var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The logout request.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request, string relayState) { var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate); ArtifactRedirect(destination, index, doc, relayState); }
/// <summary> /// Creates an artifact and redirects the user to the IdP /// </summary> /// <param name="destination">The destination of the request.</param> /// <param name="request">The authentication request.</param> /// <param name="relayState">Relay state from client. May be null</param> public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request, string relayState, Action <string, object> cacheInsert) { var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index; var doc = request.GetXml(); XmlSignatureUtils.SignDocument(doc, request.Request.Id, config); 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> /// <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> /// 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 config = Saml2Config.Current; var index = (short)config.ServiceProvider.LogoutEndpoint.Index; var doc = response.GetXml(); XmlSignatureUtils.SignDocument(doc, response.Response.ID); ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]); }
/// <summary> /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to <c>Saml20Identity.Current</c>. /// </summary> /// <param name="context">The http context.</param> /// <param name="endPoint">The IdP to perform the query against.</param> /// <param name="nameIdFormat">The name id format.</param> public void PerformQuery(HttpContext context, IdentityProviderElement endPoint, string nameIdFormat) { Logger.DebugFormat("{0}.{1} called", GetType(), "PerformQuery()"); var builder = new HttpSoapBindingBuilder(context); var name = new NameId { Value = Saml20Identity.Current.Name, Format = nameIdFormat }; _attrQuery.Subject.Items = new object[] { name }; _attrQuery.SamlAttribute = _attributes.ToArray(); var query = new XmlDocument(); query.LoadXml(Serialization.SerializeToXmlString(_attrQuery)); XmlSignatureUtils.SignDocument(query, Id); if (query.FirstChild is XmlDeclaration) { query.RemoveChild(query.FirstChild); } Logger.DebugFormat(TraceMessages.AttrQuerySent, endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml); Stream s; try { s = builder.GetResponse(endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml, endPoint.AttributeQuery); } catch (Exception e) { Logger.Error(e.Message, e); throw; } var parser = new HttpSoapBindingParser(s); var status = parser.GetStatus(); if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { Logger.ErrorFormat(ErrorMessages.AttrQueryStatusNotSuccessful, Serialization.SerializeToXmlString(status)); throw new Saml20Exception(status.StatusMessage); } bool isEncrypted; var xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted); if (isEncrypted) { var ass = new Saml20EncryptedAssertion((RSA)Saml2Config.GetConfig().ServiceProvider.SigningCertificat
private Saml20AuthnRequest CreateAuthNRequest(Saml2Configuration config) { var authnRequest = Saml20AuthnRequest.GetDefault(config); var requestXml = authnRequest.GetXml(); if (config.ServiceProvider.AuthNRequestsSigned) { XmlSignatureUtils.SignDocument(requestXml, authnRequest.Id, config); } return(authnRequest); }
public void SignatureTest() { // Arrange var rtsSoapMessageNotSigned = XDocument.Load(@"Resources\RST_Not_Signed.xml"); var ids = new[] { "action", "msgid", "to", "sec-ts", "sec-binsectoken", "body" }; var cert = CertificateUtil.GetCertificate("0E6DBCC6EFAAFF72E3F3D824E536381B26DEECF5"); // Act var rtsSoapMessageSigned = XmlSignatureUtils.SignDocument(rtsSoapMessageNotSigned, ids, cert); // Assert Assert.IsTrue(XmlSignatureUtils.VerifySignature(rtsSoapMessageSigned, cert)); }
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> /// Handles responses to an artifact resolve message. /// </summary> /// <param name="artifactResolve">The artifact resolve message.</param> public void RespondToArtifactResolve(ArtifactResolve artifactResolve, XmlElement samlDoc) { var response = Saml20ArtifactResponse.GetDefault(config.ServiceProvider.Id); response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = artifactResolve.Id; response.SamlElement = samlDoc; //samlDoc.DocumentElement; var responseDoc = response.GetXml(); if (responseDoc.FirstChild is XmlDeclaration) { responseDoc.RemoveChild(responseDoc.FirstChild); } XmlSignatureUtils.SignDocument(responseDoc, response.Id, config); _logger.LogDebug(TraceMessages.ArtifactResolveResponseSent, artifactResolve.Artifact, responseDoc.OuterXml); sendResponseMessage(responseDoc.OuterXml); }
/// <summary> /// Resolves an artifact. /// </summary> /// <returns>A stream containing the artifact response from the IdP</returns> public Stream ResolveArtifact() { Trace.TraceMethodCalled(GetType(), "ResolveArtifact()"); string artifact = _context.Request.Params["SAMLart"]; IDPEndPoint idpEndPoint = DetermineIdp(artifact); if (idpEndPoint == null) { throw new InvalidOperationException("Received artifact from unknown IDP."); } ushort endpointIndex = ArtifactUtil.GetEndpointIndex(artifact); string endpointUrl = idpEndPoint.metadata.GetARSEndpoint(endpointIndex); Saml20ArtifactResolve resolve = Saml20ArtifactResolve.GetDefault(); resolve.Artifact = artifact; XmlDocument doc = resolve.GetXml(); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } XmlSignatureUtils.SignDocument(doc, resolve.ID); string artifactResolveString = doc.OuterXml; if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.ResolveArtifact, artifact, idpEndPoint.Id, endpointIndex, endpointUrl, artifactResolveString)); } return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution)); }
/// <summary> /// Handles responses to an artifact resolve message. /// </summary> /// <param name="artifactResolve">The artifact resolve message.</param> public void RespondToArtifactResolve(ArtifactResolve artifactResolve) { var samlDoc = (XmlDocument)Context.Cache.Get(artifactResolve.Artifact); var response = Saml20ArtifactResponse.GetDefault(config.ServiceProvider.Id); response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = artifactResolve.Id; response.SamlElement = samlDoc.DocumentElement; var responseDoc = response.GetXml(); if (responseDoc.FirstChild is XmlDeclaration) { responseDoc.RemoveChild(responseDoc.FirstChild); } XmlSignatureUtils.SignDocument(responseDoc, response.Id, config.ServiceProvider.SigningCertificate); Logger.DebugFormat(TraceMessages.ArtifactResolveResponseSent, artifactResolve.Artifact, responseDoc.OuterXml); SendResponseMessage(responseDoc.OuterXml); }
/// <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); } }
/// <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()); } }
private void CreateSAMLResponse() { FormsIdentity id = null; if (HttpContext.Current.User != null) { if (HttpContext.Current.User.Identity.IsAuthenticated) { if (HttpContext.Current.User.Identity is FormsIdentity) { id = (FormsIdentity)HttpContext.Current.User.Identity; } } } DateTime notBefore = (id != null ? id.Ticket.IssueDate.ToUniversalTime() : DateTime.UtcNow); DateTime notOnOrAfter = (id != null ? id.Ticket.Expiration.ToUniversalTime() : DateTime.UtcNow.AddMinutes(30)); IDProvider config = IDProvider.GetConfig(); SAMLResponse.Status = new StatusType(); SAMLResponse.Status.StatusCode = new StatusCodeType(); SAMLResponse.Status.StatusCode.Value = SAMLUtility.StatusCodes.Success; AssertionType assert = new AssertionType(); assert.ID = SAMLUtility.GenerateID(); assert.IssueInstant = DateTime.UtcNow.AddMinutes(10); assert.Issuer = new NameIDType(); assert.Issuer.Value = config.id; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType(); subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer"; subjectConfirmation.SubjectConfirmationData = new SubjectConfirmationDataType(); subjectConfirmation.SubjectConfirmationData.Recipient = SAMLRequest.Issuer; subjectConfirmation.SubjectConfirmationData.InResponseTo = SAMLRequest.Request.ID; subjectConfirmation.SubjectConfirmationData.NotOnOrAfter = notOnOrAfter; NameIDType nameID = new NameIDType(); nameID.Format = SAMLUtility.NameIdentifierFormats.Transient; nameID.Value = (id != null ? id.Name : UtilBO.FormatNameFormsAuthentication(this.__SessionWEB.__UsuarioWEB.Usuario)); assert.Subject = new SubjectType(); assert.Subject.Items = new object[] { subjectConfirmation, nameID }; assert.Conditions = new ConditionsType(); assert.Conditions.NotBefore = notBefore; assert.Conditions.NotOnOrAfter = notOnOrAfter; assert.Conditions.NotBeforeSpecified = true; assert.Conditions.NotOnOrAfterSpecified = true; AudienceRestrictionType audienceRestriction = new AudienceRestrictionType(); audienceRestriction.Audience = new string[] { SAMLRequest.Issuer }; assert.Conditions.Items = new ConditionAbstractType[] { audienceRestriction }; AuthnStatementType authnStatement = new AuthnStatementType(); authnStatement.AuthnInstant = DateTime.UtcNow; authnStatement.SessionIndex = SAMLUtility.GenerateID(); authnStatement.AuthnContext = new AuthnContextType(); authnStatement.AuthnContext.Items = new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" }; authnStatement.AuthnContext.ItemsElementName = new ItemsChoiceType5[] { ItemsChoiceType5.AuthnContextClassRef }; StatementAbstractType[] statementAbstract = new StatementAbstractType[] { authnStatement }; assert.Items = statementAbstract; SAMLResponse.Items = new object[] { assert }; string xmlResponse = SAMLUtility.SerializeToXmlString(SAMLResponse); XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlResponse); XmlSignatureUtils.SignDocument(doc, assert.ID); SAMLResponse = SAMLUtility.DeserializeFromXmlString <ResponseType>(doc.InnerXml); HttpPostBinding binding = new HttpPostBinding(SAMLResponse, HttpUtility.UrlDecode(Request[HttpBindingConstants.RelayState])); binding.SendResponse(this.Context, HttpUtility.UrlDecode(SAMLRequest.AssertionConsumerServiceURL), SAMLTypeSSO.signon); }
/// <summary> /// Transfers the client. /// </summary> /// <param name="idp">The identity provider.</param> /// <param name="context">The context.</param> private void TransferClient(IdentityProvider idp, HttpContext context, Saml2Configuration config) { var request = Saml20LogoutRequest.GetDefault(config); // Determine which endpoint to use from the configuration file or the endpoint metadata. var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints); request.Destination = destination.Url; var nameIdFormat = (string)context.Session[IdpNameIdFormat]; request.SubjectToLogOut.Format = nameIdFormat; // Handle POST binding if (destination.Binding == BindingType.Post) { var builder = new HttpPostBindingBuilder(destination); request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; var requestDocument = request.GetXml(); XmlSignatureUtils.SignDocument(requestDocument, request.Id, config); builder.Request = requestDocument.OuterXml; Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "POST", builder.Request); context.Response.Write(builder.GetPage()); context.Response.End(); return; } // Handle Redirect binding if (destination.Binding == BindingType.Redirect) { request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; var builder = new HttpRedirectBindingBuilder { Request = request.GetXml().OuterXml, SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey }; var redirectUrl = destination.Url + "?" + builder.ToQuery(); Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "REDIRECT", redirectUrl); context.Response.Redirect(redirectUrl, true); return; } // Handle Artifact binding if (destination.Binding == BindingType.Artifact) { request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = (string)context.Session[IdpNameId]; request.SessionIndex = (string)context.Session[IdpSessionIdKey]; Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "ARTIFACT", request.GetXml().OuterXml); var builder = GetBuilder(context); builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"), (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration)); } Logger.Error(ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid); }
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 TransferClient(IDPEndPoint endpoint, HttpContext context) { Trace.TraceMethodCalled(GetType(), "TransferClient()"); Saml20LogoutRequest request = Saml20LogoutRequest.GetDefault(); AuditLogging.AssertionId = request.ID; AuditLogging.IdpId = endpoint.Id; // Determine which endpoint to use from the configuration file or the endpoint metadata. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints()); request.Destination = destination.Url; string nameIdFormat = context.Session[IDPNameIdFormat].ToString(); request.SubjectToLogOut.Format = nameIdFormat; if (destination.Binding == SAMLBinding.POST) { HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination); request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString(); request.SessionIndex = context.Session[IDPSessionIdKey].ToString(); XmlDocument requestDocument = request.GetXml(); XmlSignatureUtils.SignDocument(requestDocument, request.ID); builder.Request = requestDocument.OuterXml; if(Trace.ShouldTrace(TraceEventType.Information)) Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "POST", endpoint.Id, requestDocument.OuterXml)); AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: POST"); builder.GetPage().ProcessRequest(context); context.Response.End(); return; } if(destination.Binding == SAMLBinding.REDIRECT) { HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey; request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString(); request.SessionIndex = context.Session[IDPSessionIdKey].ToString(); builder.Request = request.GetXml().OuterXml; string redirectUrl = destination.Url + "?" + builder.ToQuery(); if (Trace.ShouldTrace(TraceEventType.Information)) Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "REDIRECT", endpoint.Id, redirectUrl)); AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: Redirect"); context.Response.Redirect(redirectUrl, true); return; } if(destination.Binding == SAMLBinding.ARTIFACT) { if (Trace.ShouldTrace(TraceEventType.Information)) Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "ARTIFACT", endpoint.Id, string.Empty)); request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString(); request.SessionIndex = context.Session[IDPSessionIdKey].ToString(); HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context); AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Method: Artifact"); builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N")); } HandleError(context, Resources.BindingError); }
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> /// Transfers the client. /// </summary> /// <param name="identityProvider">The identity provider.</param> /// <param name="request">The request.</param> /// <param name="context">The context.</param> private void TransferClient(IdentityProvider identityProvider, Saml20AuthnRequest request, HttpContext context) { // Set the last IDP we attempted to login at. StateService.Set(IdpTempSessionKey, identityProvider.Id); // Determine which endpoint to use from the configuration file or the endpoint metadata. var destination = DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.SignOnEndpoint, identityProvider.Metadata.SSOEndpoints); request.Destination = destination.Url; if (identityProvider.ForceAuth) { request.ForceAuthn = true; } // Check isPassive status var isPassiveFlag = StateService.Get <bool?>(IdpIsPassive); if (isPassiveFlag != null && (bool)isPassiveFlag) { request.IsPassive = true; StateService.Set(IdpIsPassive, null); } if (identityProvider.IsPassive) { request.IsPassive = true; } // Check if request should forceAuthn var forceAuthnFlag = StateService.Get <bool?>(IdpForceAuthn); if (forceAuthnFlag != null && (bool)forceAuthnFlag) { request.ForceAuthn = true; StateService.Set(IdpForceAuthn, null); } // Check if protocol binding should be forced if (identityProvider.SignOnEndpoint != null) { if (!string.IsNullOrEmpty(identityProvider.SignOnEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = identityProvider.SignOnEndpoint.ForceProtocolBinding; } } // Save request message id to session StateService.Set(ExpectedInResponseToSessionKey, request.Id); switch (destination.Binding) { case BindingType.Redirect: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect); var redirectBuilder = new HttpRedirectBindingBuilder { SigningKey = _certificate.PrivateKey, Request = request.GetXml().OuterXml }; Logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request); var redirectLocation = request.Destination + (request.Destination.Contains("?") ? "&" : "?") + redirectBuilder.ToQuery(); context.Response.Redirect(redirectLocation, true); break; case BindingType.Post: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost); var postBuilder = new HttpPostBindingBuilder(destination); // Honor the ForceProtocolBinding and only set this if it's not already set if (string.IsNullOrEmpty(request.ProtocolBinding)) { request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost; } var requestXml = request.GetXml(); XmlSignatureUtils.SignDocument(requestXml, request.Id); postBuilder.Request = requestXml.OuterXml; Logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request); postBuilder.GetPage().ProcessRequest(context); break; case BindingType.Artifact: Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact); var artifactBuilder = new HttpArtifactBindingBuilder(context); // Honor the ForceProtocolBinding and only set this if it's not already set if (string.IsNullOrEmpty(request.ProtocolBinding)) { request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact; } Logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml); artifactBuilder.RedirectFromLogin(destination, request); break; default: Logger.Error(ErrorMessages.EndpointBindingInvalid); throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid); } }
private void SendAuthNRequest(Saml2Configuration config) { _logger.LogDebug("Begin Transfer User to IDP"); if (!config.IdentityProviders.Any()) { _logger.LogError("No IdentityProviders configured"); } // order signon endpoints by index and then check for default. var idp = (GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Post && x.Type == EndpointType.SignOn) ?? GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Redirect && x.Type == EndpointType.SignOn)); if (idp == null) { _logger.LogError("IdentityProvider configured does not have POST or Redirect binding", config.IdentityProviders.FirstOrDefault()); } _logger.LogDebug($"IdentityProvider found: {idp.Binding.ToString()}"); var authnRequest = CreateAuthNRequest(config); if (idp.Binding == BindingType.Post) { var post = new SAMLSilly.Bindings.HttpPostBindingBuilder(idp); if (string.IsNullOrEmpty(authnRequest.ProtocolBinding)) { authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost; } var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Post, idp, config.IdentityProviders[0].Metadata.SSOEndpoints); authnRequest.Destination = destination.Url; var requestXml = authnRequest.GetXml(); if (config.ServiceProvider.AuthNRequestsSigned) { _logger.LogDebug("Sign AuthNRequest"); XmlSignatureUtils.SignDocument(requestXml, authnRequest.Id, config); } post.Request = requestXml.OuterXml; _httpContextAccessor.HttpContext.Response.WriteAsync(post.GetPage()); return; } else { var redirectBuilder = new SAMLSilly.AspNetCore.BindingBuilders.HttpRedirectBindingBuilder(config); // if (string.IsNullOrEmpty(authnRequest.ProtocolBinding)) // { authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost; // } var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp, config.IdentityProviders[0].Metadata.SSOEndpoints); authnRequest.Destination = destination.Url; redirectBuilder.Request = authnRequest.GetXml().OuterXml; redirectBuilder.SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey; var query = redirectBuilder.ToQuery(); var url = $"{idp.Url}?{query}"; _httpContextAccessor.HttpContext.Response.Redirect(url, false); return; } throw new NotImplementedException(); }
/// <summary> /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to Saml20Identity.Current. /// </summary> /// <param name="context">The http context.</param> /// <param name="endPoint">The IdP to perform the query against.</param> /// <param name="nameIdFormat">The nameid format.</param> public void PerformQuery(HttpContext context, IDPEndPoint endPoint, string nameIdFormat) { Trace.TraceMethodCalled(GetType(), "PerformQuery()"); HttpSOAPBindingBuilder builder = new HttpSOAPBindingBuilder(context); NameID name = new NameID(); name.Value = Saml20Identity.Current.Name; name.Format = nameIdFormat; _attrQuery.Subject.Items = new object[] { name }; _attrQuery.SamlAttribute = _attributes.ToArray(); XmlDocument query = new XmlDocument(); query.XmlResolver = null; query.LoadXml(Serialization.SerializeToXmlString(_attrQuery)); XmlSignatureUtils.SignDocument(query, ID); if (query.FirstChild is XmlDeclaration) { query.RemoveChild(query.FirstChild); } Stream s; if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAttrQuery, endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml)); } try { s = builder.GetResponse(endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml, endPoint.AttributeQuery); } catch (Exception e) { Trace.TraceData(TraceEventType.Error, e.ToString()); throw; } HttpSOAPBindingParser parser = new HttpSOAPBindingParser(s); Status status = parser.GetStatus(); if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { Trace.TraceData(TraceEventType.Error, string.Format(Tracing.AttrQueryStatusError, Serialization.SerializeToXmlString(status))); throw new Saml20Exception(status.StatusMessage); } bool isEncrypted; XmlElement xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted); if (isEncrypted) { Saml20EncryptedAssertion ass = new Saml20EncryptedAssertion( (RSA)FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey); ass.LoadXml(xmlAssertion); ass.Decrypt(); xmlAssertion = ass.Assertion.DocumentElement; } Saml20Assertion assertion = new Saml20Assertion(xmlAssertion, null, AssertionProfile.Core, endPoint.QuirksMode); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.AttrQueryAssertion, xmlAssertion == null ? string.Empty : xmlAssertion.OuterXml)); } if (!assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endPoint.metadata.Keys, endPoint))) { Trace.TraceData(TraceEventType.Error, Resources.SignatureInvalid); throw new Saml20Exception(Resources.SignatureInvalid); } foreach (SamlAttribute attr in assertion.Attributes) { Saml20Identity.Current.AddAttributeFromQuery(attr.Name, attr); } }