/// <summary> /// Handles responses to an artifact resolve message. /// </summary> /// <param name="idpEndPoint">The IdP endpoint</param> /// <param name="artifactResolve">The artifact resolve message.</param> public void RespondToArtifactResolve(IDPEndPoint idpEndPoint, 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); } var signingCertificate = FederationConfig.GetConfig().GetFirstValidCertificate(); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndPoint.ShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(responseDoc, response.ID, signingCertificate); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.RespondToArtifactResolve, artifactResolve.Artifact, responseDoc.OuterXml)); } SendResponseMessage(responseDoc.OuterXml); }
/// <summary> /// Return a string containing the metadata XML based on the settings added to this instance. /// The resulting XML will be signed, if the AsymmetricAlgoritm property has been set. /// </summary> public string ToXml(Encoding enc) { XmlDocument doc = new XmlDocument(); doc.XmlResolver = null; doc.PreserveWhitespace = true; doc.LoadXml(Serialization.SerializeToXmlString(_entity)); // Add the correct encoding to the head element. if (doc.FirstChild is XmlDeclaration) { ((XmlDeclaration)doc.FirstChild).Encoding = enc.WebName; } else { doc.PrependChild(doc.CreateXmlDeclaration("1.0", enc.WebName, null)); } if (Sign) { var metaDataShaHashingAlgorithm = FederationConfig.GetConfig().MetaDataShaHashingAlgorithm; var validatedMetaDataShaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(metaDataShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(validatedMetaDataShaHashingAlgorithm); var cert = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); signatureProvider.SignMetaData(doc, doc.DocumentElement.GetAttribute("ID"), cert); } return(doc.OuterXml); }
/// <summary> /// Creates an artifact for the LogoutRequest and redirects the user to the IdP. /// </summary> /// <param name="idpEndPoint">The IdP endpoint</param> /// <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(IDPEndPoint idpEndPoint, IDPEndPointElement destination, Saml20LogoutRequest request, string relayState) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); Int16 index = (Int16)config.ServiceProvider.LogoutEndpoint.endPointIndex; XmlDocument doc = request.GetXml(); var signingCertificate = FederationConfig.GetConfig().GetFirstValidCertificate(); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndPoint.ShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(doc, request.Request.ID, signingCertificate); ArtifactRedirect(destination, index, doc, relayState); }
/// <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); } var signingCertificate = FederationConfig.GetConfig().GetFirstValidCertificate(); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndPoint.ShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(doc, resolve.ID, signingCertificate); 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> /// 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)); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(endPoint.ShaHashingAlgorithm); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(query, ID, signingCertificate); 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); assertion.Validate(DateTime.UtcNow); if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.AttrQueryAssertion, xmlAssertion == null ? string.Empty : xmlAssertion.OuterXml)); } IEnumerable <string> validationFailures; if (!assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endPoint.metadata.Keys, endPoint, out validationFailures))) { Trace.TraceData(TraceEventType.Error, Resources.SignatureInvalid); throw new Saml20Exception(Resources.SignatureInvalid); } foreach (SamlAttribute attr in assertion.Attributes) { Saml20Identity.Current.AddAttributeFromQuery(attr.Name, attr); } }
private void TransferClient(IDPEndPoint idpEndpoint, Saml20AuthnRequest request, HttpContext context) { AuditLogging.AssertionId = request.ID; AuditLogging.IdpId = idpEndpoint.Id; // Determine which endpoint to use from the configuration file or the endpoint metadata. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SSOEndpoint, idpEndpoint.metadata.SSOEndpoints()); request.Destination = destination.Url; bool isPassive; string isPassiveAsString = context.Request.Params[IDPIsPassive]; if (bool.TryParse(isPassiveAsString, out isPassive)) { request.IsPassive = isPassive; } if (idpEndpoint.IsPassive) { request.IsPassive = true; } bool forceAuthn; string forceAuthnAsString = context.Request.Params[IDPForceAuthn]; if (bool.TryParse(forceAuthnAsString, out forceAuthn)) { request.ForceAuthn = forceAuthn; } if (idpEndpoint.ForceAuthn) { request.ForceAuthn = true; } if (idpEndpoint.SSOEndpoint != null) { if (!string.IsNullOrEmpty(idpEndpoint.SSOEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = idpEndpoint.SSOEndpoint.ForceProtocolBinding; } } //Save request message id to session SessionStore.CurrentSession[SessionConstants.ExpectedInResponseTo] = request.ID; var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndpoint.ShaHashingAlgorithm); if (destination.Binding == SAMLBinding.REDIRECT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Redirect, idpEndpoint.Id)); HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.signingKey = _certificate.PrivateKey; builder.Request = request.GetXml().OuterXml; builder.ShaHashingAlgorithm = shaHashingAlgorithm; string s = request.Destination + "?" + builder.ToQuery(); AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirecting user to IdP for authentication", builder.Request); context.Response.Redirect(s, true); return; } if (destination.Binding == SAMLBinding.POST) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Post, idpEndpoint.Id)); HttpPostBindingBuilder builder = 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.HTTP_Post; } XmlDocument req = request.GetXml(); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(req, request.ID, signingCertificate); builder.Request = req.OuterXml; AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_POST); builder.GetPage().ProcessRequest(context); return; } if (destination.Binding == SAMLBinding.ARTIFACT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Artifact, idpEndpoint.Id)); HttpArtifactBindingBuilder builder = 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.HTTP_Artifact; } AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT_ARTIFACT); builder.RedirectFromLogin(idpEndpoint, destination, request); } HandleError(context, Resources.BindingError); }
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, 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 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; request.SubjectToLogOut.Format = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Format; var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(endpoint.ShaHashingAlgorithm); if (destination.Binding == SAMLBinding.POST) { HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination); request.Destination = destination.Url; request.Reason = Saml20Constants.Reasons.User; request.SubjectToLogOut.Value = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value; request.SessionIndex = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex; XmlDocument requestDocument = request.GetXml(); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(requestDocument, request.ID, signingCertificate); 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 = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value; request.SessionIndex = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex; builder.Request = request.GetXml().OuterXml; builder.ShaHashingAlgorithm = shaHashingAlgorithm; 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 = Saml20PrincipalCache.GetSaml20AssertionLite().Subject.Value; request.SessionIndex = Saml20PrincipalCache.GetSaml20AssertionLite().SessionIndex; HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context); AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Method: Artifact"); builder.RedirectFromLogout(endpoint, 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); var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idp.ShaHashingAlgorithm); AuditLogging.IdpId = idp.Id; if (parser.IsArtifactResolve()) { Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResolveIn); if (!parser.CheckSamlMessageSignature(idp.metadata.Keys)) { HandleError(context, "Invalid Saml message signature"); AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, "Signature could not be verified", parser.SamlMessage); } AuditLogging.AssertionId = parser.ArtifactResolve.ID; AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, "", parser.SamlMessage); builder.RespondToArtifactResolve(idp, parser.ArtifactResolve); } else if (parser.IsArtifactResponse()) { Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResponseIn); Status status = parser.ArtifactResponse.Status; if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unexpected status code for artifact response: {0}, expected 'Success', msg: {1}", status.StatusCode.Value, parser.SamlMessage)); HandleError(context, status); return; } if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ELEMENT_NAME) { if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.ArtifactResponse.Any.OuterXml)); } //Send logoutresponse via artifact Saml20LogoutResponse response = new Saml20LogoutResponse(); response.Issuer = config.ServiceProvider.ID; LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.ArtifactResponse.Any.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = req.ID; IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idp.SLOEndpoint, idp.metadata.SLOEndpoints()); builder.RedirectFromLogout(idp, destination, response); } else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ELEMENT_NAME) { DoLogout(context); } else { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported payload message in ArtifactResponse: {0}, msg: {1}", parser.ArtifactResponse.Any.LocalName, parser.SamlMessage)); HandleError(context, string.Format("Unsupported payload message in ArtifactResponse: {0}", parser.ArtifactResponse.Any.LocalName)); } } else if (parser.IsLogoutReqest()) { if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.SamlMessage.OuterXml)); } Saml20LogoutResponse response = new Saml20LogoutResponse(); if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present in SOAP logout request, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } if (idp.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + parser.Issuer); // Not able to process the request as we do not know the IdP. response.StatusCode = Saml20Constants.StatusCodes.NoAvailableIDP; } else { Saml20MetadataDocument metadata = idp.metadata; if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing))) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature SOAP logout, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.RequestDenied; } } if (parser.GetNameID() != null && !string.IsNullOrEmpty(parser.GetNameID().Value)) { DoSoapLogout(context, parser.GetNameID().Value); } else { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. No user ID was supplied in SOAP logout request, msg: " + parser.SamlMessage.OuterXml); response.StatusCode = Saml20Constants.StatusCodes.NoAuthnContext; } LogoutRequest req = parser.LogoutRequest; //Build the response object response.Issuer = config.ServiceProvider.ID; response.StatusCode = Saml20Constants.StatusCodes.Success; response.InResponseTo = req.ID; XmlDocument doc = response.GetXml(); var signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(doc, response.ID, signingCertificate); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } builder.SendResponseMessage(doc.OuterXml); } else { Status s = parser.GetStatus(); if (s != null) { HandleError(context, s); } else { AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported SamlMessage element: {0}, msg: {1}", parser.SamlMessageName, parser.SamlMessage)); HandleError(context, string.Format("Unsupported SamlMessage element: {0}", parser.SamlMessageName)); } } }
private void TransferClient(IDPEndPoint idpEndpoint, Saml20AuthnRequest request, HttpContext context) { AuditLogging.AssertionId = request.ID; AuditLogging.IdpId = idpEndpoint.Id; // Determine which endpoint to use from the configuration file or the endpoint metadata. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SSOEndpoint, idpEndpoint.metadata.SSOEndpoints()); request.Destination = destination.Url; bool isPassive; string isPassiveAsString = context.Request.Params[IDPIsPassive]; if (bool.TryParse(isPassiveAsString, out isPassive)) { request.IsPassive = isPassive; } var requestContextItems = new List <(string value, ItemsChoiceType7 type)>(); if (!string.IsNullOrEmpty(context.Request.Params[NsisLoa])) { string demandedLevelOfAssurance = context.Request.Params[NsisLoa].ToString(); if (!new[] { "Low", "Substantial", "High" }.Contains(demandedLevelOfAssurance)) { HandleError(context, string.Format(Resources.DemandingLevelOfAssuranceError, demandedLevelOfAssurance)); return; } requestContextItems.Add((DKSaml20NsisLoaAttribute.NAME + "/" + demandedLevelOfAssurance, ItemsChoiceType7.AuthnContextClassRef)); // Persist demanded LoA in session to be able to verify assertion SessionStore.CurrentSession[SessionConstants.ExpectedNsisLoa] = demandedLevelOfAssurance; Trace.TraceData(TraceEventType.Information, string.Format(Tracing.DemandingLevelOfAssurance, demandedLevelOfAssurance)); } if (!string.IsNullOrEmpty(context.Request.Params[Profile])) { string demandedProfile = context.Request.Params[Profile].ToString(); if (!new[] { "Professional", "Person" }.Contains(demandedProfile)) { HandleError(context, string.Format(Resources.DemandingProfileError, demandedProfile)); return; } requestContextItems.Add(("https://data.gov.dk/eid/" + demandedProfile, ItemsChoiceType7.AuthnContextClassRef)); Trace.TraceData(TraceEventType.Information, string.Format(Tracing.DemandingProfile, demandedProfile)); } if (requestContextItems.Count > 0) { request.Request.RequestedAuthnContext = new RequestedAuthnContext(); request.Request.RequestedAuthnContext.Comparison = AuthnContextComparisonType.minimum; request.Request.RequestedAuthnContext.ItemsElementName = requestContextItems.Select(x => x.type).ToArray(); request.Request.RequestedAuthnContext.Items = requestContextItems.Select(x => x.value).ToArray(); } if (idpEndpoint.IsPassive) { request.IsPassive = true; } bool forceAuthn; string forceAuthnAsString = context.Request.Params[IDPForceAuthn]; if (bool.TryParse(forceAuthnAsString, out forceAuthn)) { request.ForceAuthn = forceAuthn; } if (idpEndpoint.ForceAuthn) { request.ForceAuthn = true; } if (idpEndpoint.SSOEndpoint != null) { if (!string.IsNullOrEmpty(idpEndpoint.SSOEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = idpEndpoint.SSOEndpoint.ForceProtocolBinding; } } //Save request message id to session SessionStore.CurrentSession[SessionConstants.ExpectedInResponseTo] = request.ID; var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idpEndpoint.ShaHashingAlgorithm); if (destination.Binding == SAMLBinding.REDIRECT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Redirect, idpEndpoint.Id)); HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.signingKey = _certificate.PrivateKey; builder.Request = request.GetXml().OuterXml; builder.ShaHashingAlgorithm = shaHashingAlgorithm; string s = request.Destination + "?" + builder.ToQuery(); AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirecting user to IdP for authentication", builder.Request); context.Response.Redirect(s, true); return; } if (destination.Binding == SAMLBinding.POST) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Post, idpEndpoint.Id)); HttpPostBindingBuilder builder = 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.HTTP_Post; } XmlDocument req = request.GetXml(); var signingCertificate = FederationConfig.GetConfig().GetFirstValidCertificate(); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm); signatureProvider.SignAssertion(req, request.ID, signingCertificate); builder.Request = req.OuterXml; AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_POST); builder.GetPage().ProcessRequest(context); return; } if (destination.Binding == SAMLBinding.ARTIFACT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Artifact, idpEndpoint.Id)); HttpArtifactBindingBuilder builder = 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.HTTP_Artifact; } AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT_ARTIFACT); builder.RedirectFromLogin(idpEndpoint, destination, request); } HandleError(context, Resources.BindingError); }