/// <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> /// Sign the specfiied data /// </summary> public byte[] SignData(byte[] data, string keyId = null) { var credentials = SecurityUtils.CreateSigningCredentials(keyId); using (var signatureProvider = new SignatureProviderFactory().CreateForSigning(credentials.SigningKey, credentials.SignatureAlgorithm)) return(signatureProvider.Sign(data)); }
/// <summary> /// Verify the signature /// </summary> public bool Verify(byte[] data, byte[] signature, string keyId = null) { var credentials = SecurityUtils.CreateSigningCredentials(keyId); using (var signatureProvider = new SignatureProviderFactory().CreateForVerifying(credentials.SigningKey, credentials.SignatureAlgorithm)) return(signatureProvider.Verify(data, signature)); }
private void GenerateMetadataDocument(HttpContext context) { EntityDescriptor metadata = new EntityDescriptor(); metadata.entityID = IDPConfig.ServerBaseUrl; metadata.ID = "id" + Guid.NewGuid().ToString("N"); IDPSSODescriptor descriptor = new IDPSSODescriptor(); metadata.Items = new object[] { descriptor }; descriptor.protocolSupportEnumeration = new string[] { Saml20Constants.PROTOCOL }; descriptor.KeyDescriptor = CreateKeyDescriptors(); { // Signon endpoint Endpoint endpoint = new Endpoint(); endpoint.Location = IDPConfig.ServerBaseUrl + "Signon.ashx"; endpoint.Binding = Saml20Constants.ProtocolBindings.HTTP_Redirect; descriptor.SingleSignOnService = new Endpoint[] { endpoint }; } { // Logout endpoint Endpoint endpoint = new Endpoint(); endpoint.Location = IDPConfig.ServerBaseUrl + "Logout.ashx"; endpoint.Binding = Saml20Constants.ProtocolBindings.HTTP_Redirect; descriptor.SingleLogoutService = new Endpoint[] { endpoint }; } // Create the list of attributes offered. List <SamlAttribute> atts = new List <SamlAttribute>(IDPConfig.attributes.Length); foreach (string name in IDPConfig.attributes) { SamlAttribute att = new SamlAttribute(); att.NameFormat = SamlAttribute.NAMEFORMAT_BASIC; att.Name = name; atts.Add(att); } descriptor.Attributes = atts.ToArray(); XmlDocument doc = new XmlDocument(); doc.XmlResolver = null; doc.PreserveWhitespace = true; doc.LoadXml(Serialization.SerializeToXmlString(metadata)); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm.SHA256); X509Certificate2 cert = IDPConfig.IDPCertificate; var id = doc.DocumentElement.GetAttribute("ID"); signatureProvider.SignMetaData(doc, id, cert); context.Response.Write(doc.OuterXml); }
/// <summary> /// Sign the specfiied data /// </summary> public byte[] SignData(byte[] data, string keyId = null) { var credentials = SecurityUtils.CreateSigningCredentials(keyId); if (credentials == null) { throw new InvalidOperationException($"Couldn't create signature for key {keyId}"); } using (var signatureProvider = new SignatureProviderFactory().CreateForSigning(credentials.SigningKey, credentials.SignatureAlgorithm)) return(signatureProvider.Sign(data)); }
/// <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); }
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. var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm.SHA256); signatureProvider.SignAssertion(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> /// Validates the signature using the public part of the asymmetric key given as parameter. /// </summary> /// <param name="key"></param> /// <returns><code>true</code> if the signature is present and can be verified using the given key. /// <code>false</code> if the signature is present, but can't be verified using the given key.</returns> /// <exception cref="InvalidOperationException">If the query is not signed, and therefore cannot have its signature verified. Use /// the <code>IsSigned</code> property to check for this situation before calling this method.</exception> public bool CheckSignature(AsymmetricAlgorithm key) { if (key == null) { throw new ArgumentNullException("key"); } if (!IsSigned) { throw new InvalidOperationException("Query is not signed, so there is no signature to verify."); } var signatureProvider = SignatureProviderFactory.CreateFromHashingAlgorithmSignatureUri(_signatureAlgorithm); return(signatureProvider.VerifySignature(key, Encoding.UTF8.GetBytes(_signedquery), DecodeSignature())); }
/// <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> /// If an asymmetric key has been specified, sign the request. /// </summary> private void AddSignature(StringBuilder result) { if (_signingKey == null) { return; } result.Append(string.Format("&{0}=", HttpRedirectBindingConstants.SigAlg)); var signingProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm); result.Append(UpperCaseUrlEncode(HttpUtility.UrlEncode(signingProvider.SignatureUri))); // Calculate the signature of the URL as described in [SAMLBind] section 3.4.4.1. byte[] signature = signingProvider.SignData(_signingKey, Encoding.UTF8.GetBytes(result.ToString())); //byte[] signature = SignData(Encoding.UTF8.GetBytes(result.ToString())); result.AppendFormat("&{0}=", HttpRedirectBindingConstants.Signature); result.Append(HttpUtility.UrlEncode(Convert.ToBase64String(signature))); }
private void RunCreationTests(SecurityTokenDescriptor tokenDescriptor, int iterations, bool display = true) { // Create jwts using wif // Create Saml2 tokens // Create Saml tokens DateTime started; string written = "Created, signed and xmlWrite: '{0}', '{1}' Tokens. Time: '{2}'"; string created = "Created, signed: '{0}', '{1}' Tokens. Time: '{2}'"; SignatureProviderFactory factory = new SignatureProviderFactory(); SignatureProvider signatureProvider = factory.CreateForSigning(tokenDescriptor.SigningCredentials.SigningKey, tokenDescriptor.SigningCredentials.SignatureAlgorithm); started = DateTime.UtcNow; for (int i = 0; i < iterations; i++) { CreateJwts(tokenDescriptor, signatureProvider); } if (display) { Console.WriteLine(string.Format(created, "JwtHandler - signatureProvider != null", iterations, DateTime.UtcNow - started)); } started = DateTime.UtcNow; for (int i = 0; i < iterations; i++) { CreateJwts(tokenDescriptor, null); } if (display) { Console.WriteLine(string.Format(created, "JwtHandler - signatureProvider == null", iterations, DateTime.UtcNow - started)); } started = DateTime.UtcNow; for (int i = 0; i < iterations; i++) { CreateSaml2Tokens(tokenDescriptor); } if (display) { Console.WriteLine(string.Format(written, "Saml2", iterations, DateTime.UtcNow - started)); } started = DateTime.UtcNow; for (int i = 0; i < iterations; i++) { CreateSamlTokens(tokenDescriptor); } if (display) { Console.WriteLine(string.Format(written, "Saml1", iterations, DateTime.UtcNow - started)); } started = DateTime.UtcNow; for (int i = 0; i < iterations; i++) { WriteJwts(tokenDescriptor, signatureProvider); } if (display) { Console.WriteLine(string.Format(written, "JwtHandler", iterations, DateTime.UtcNow - started)); } }
private void FactoryCreateFor(string testcase, SecurityKey key, string algorithm, SignatureProviderFactory factory, ExpectedException exceptionExpected) { Console.WriteLine(string.Format("Testcase: '{0}'", testcase)); try { if (testcase.StartsWith("Siging")) { factory.CreateForSigning(key, algorithm); } else { factory.CreateForVerifying(key, algorithm); } Assert.IsFalse(exceptionExpected.Thrown != null, string.Format("Expected exception: '{0}'", exceptionExpected.Thrown)); } catch (Exception ex) { ExpectedException.ProcessException(exceptionExpected, ex); } }
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); }
public void SignatureProviderFactory_Tests() { SignatureProviderFactory factory = new SignatureProviderFactory(); // Asymmetric / Symmetric both need signature alg specified FactoryCreateFor("Siging: - algorithm string.Empty", KeyingMaterial.AsymmetricKey_1024, string.Empty, factory, ExpectedException.ArgumentException()); FactoryCreateFor("Verifying: - algorithm string.Empty", KeyingMaterial.AsymmetricKey_1024, string.Empty, factory, ExpectedException.ArgumentException()); // Keytype not supported FactoryCreateFor("Siging: - SecurityKey type not Asymmetric or Symmetric", NotAsymmetricOrSymmetricSecurityKey.New, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgumentException("IDX10600:")); FactoryCreateFor("Verifying: - SecurityKey type not Asymmetric or Symmetric", NotAsymmetricOrSymmetricSecurityKey.New, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgumentException("IDX10600:")); // Private keys missing FactoryCreateFor("Siging: - SecurityKey without private key", KeyingMaterial.DefaultAsymmetricKey_Public_2048, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.InvalidOperationException(substringExpected: "IDX10614:", inner: typeof(NotSupportedException))); FactoryCreateFor("Verifying: - SecurityKey without private key", KeyingMaterial.DefaultAsymmetricKey_Public_2048, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.NoExceptionExpected); // Key size checks FactoryCreateFor("Siging: - AsymmetricKeySize Key to small", KeyingMaterial.AsymmetricKey_1024, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgumentOutOfRangeException("IDX10630:")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = 2048; FactoryCreateFor("Verifying: - AsymmetricKeySize Key to small", KeyingMaterial.AsymmetricKey_1024, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgumentOutOfRangeException("IDX10631:")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying; SignatureProviderFactory.MinimumSymmetricKeySizeInBits = 512; FactoryCreateFor("Siging: - SymmetricKeySize Key to small", KeyingMaterial.DefaultSymmetricSecurityKey_256, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgumentOutOfRangeException("IDX10603:")); FactoryCreateFor("Verifying: - SymmetricKeySize Key to small", KeyingMaterial.DefaultSymmetricSecurityKey_256, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgumentOutOfRangeException("IDX10603")); SignatureProviderFactory.MinimumSymmetricKeySizeInBits = SignatureProviderFactory.AbsoluteMinimumSymmetricKeySizeInBits; ExpectedException expectedException = ExpectedException.ArgumentOutOfRangeException("IDX10613:"); // setting keys too small try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning < AbsoluteMinimumAsymmetricKeySizeInBitsForSigning")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForSigning - 10; expectedException.ProcessNoException(); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForSigning; } catch (Exception ex) { expectedException.ProcessException(ex); } expectedException = ExpectedException.ArgumentOutOfRangeException("IDX10627:"); try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying < AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying - 10; expectedException.ProcessNoException(); } catch (Exception ex) { expectedException.ProcessException(ex); } expectedException = ExpectedException.ArgumentOutOfRangeException("IDX10628:"); try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumSymmetricKeySizeInBits < AbsoluteMinimumSymmetricKeySizeInBits")); SignatureProviderFactory.MinimumSymmetricKeySizeInBits = SignatureProviderFactory.AbsoluteMinimumSymmetricKeySizeInBits - 10; expectedException.ProcessNoException(); } catch (Exception ex) { expectedException.ProcessException(ex); } }
public void SignatureProviderFactoryTests() { SignatureProviderFactory factory = new SignatureProviderFactory(); // Asymmetric / Symmetric both need signature alg specified FactoryCreateFor("Siging: - algorithm string.Empty", KeyingMaterial.AsymmetricKey_1024, string.Empty, factory, ExpectedException.ArgEx()); FactoryCreateFor("Verifying: - algorithm string.Empty", KeyingMaterial.AsymmetricKey_1024, string.Empty, factory, ExpectedException.ArgEx()); // Keytype not supported FactoryCreateFor("Siging: - SecurityKey type not Asymmetric or Symmetric", NotAsymmetricOrSymmetricSecurityKey.New, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgEx("Jwt10500")); FactoryCreateFor("Verifying: - SecurityKey type not Asymmetric or Symmetric", NotAsymmetricOrSymmetricSecurityKey.New, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgEx("Jwt10500")); // Private keys missing FactoryCreateFor("Siging: - SecurityKey without private key", KeyingMaterial.AsymmetricKey_Public_2048, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.InvalidOp()); FactoryCreateFor("Verifying: - SecurityKey without private key", KeyingMaterial.AsymmetricKey_Public_2048, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.Null); // Key size checks FactoryCreateFor("Siging: - AsymmetricKeySize Key to small", KeyingMaterial.AsymmetricKey_1024, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgRange("Jwt10530")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = 2048; FactoryCreateFor("Verifying: - AsymmetricKeySize Key to small", KeyingMaterial.AsymmetricKey_1024, SecurityAlgorithms.RsaSha256Signature, factory, ExpectedException.ArgRange("Jwt10531")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying; SignatureProviderFactory.MinimumSymmetricKeySizeInBits = 512; FactoryCreateFor("Siging: - SymmetricKeySize Key to small", KeyingMaterial.SymmetricSecurityKey_256, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgRange("Jwt10503")); FactoryCreateFor("Verifying: - SymmetricKeySize Key to small", KeyingMaterial.SymmetricSecurityKey_256, SecurityAlgorithms.HmacSha256Signature, factory, ExpectedException.ArgRange("Jwt10503")); SignatureProviderFactory.MinimumSymmetricKeySizeInBits = SignatureProviderFactory.AbsoluteMinimumSymmetricKeySizeInBits; // setting keys too small try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning < AbsoluteMinimumAsymmetricKeySizeInBitsForSigning")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForSigning - 10; Assert.Fail(string.Format("Expected exception: '{0}'", typeof(ArgumentOutOfRangeException))); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForSigning = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForSigning; } catch (Exception ex) { ExpectedException.ProcessException(ExpectedException.ArgRange("Jwt10513"), ex); } try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying < AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying")); SignatureProviderFactory.MinimumAsymmetricKeySizeInBitsForVerifying = SignatureProviderFactory.AbsoluteMinimumAsymmetricKeySizeInBitsForVerifying - 10; Assert.Fail(string.Format("Expected exception: '{0}'", typeof(ArgumentOutOfRangeException))); } catch (Exception ex) { ExpectedException.ProcessException(ExpectedException.ArgRange("Jwt10527"), ex); } try { Console.WriteLine(string.Format("Testcase: '{0}'", "SignatureProviderFactory.MinimumSymmetricKeySizeInBits < AbsoluteMinimumSymmetricKeySizeInBits")); SignatureProviderFactory.MinimumSymmetricKeySizeInBits = SignatureProviderFactory.AbsoluteMinimumSymmetricKeySizeInBits - 10; Assert.Fail(string.Format("Expected exception: '{0}'", typeof(ArgumentOutOfRangeException))); } catch (Exception ex) { ExpectedException.ProcessException(ExpectedException.ArgRange("Jwt10528"), ex); } }
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); }
/// <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 CreateAssertionResponse(User user) { string entityId = request.Issuer.Value; Saml20MetadataDocument metadataDocument = IDPConfig.GetServiceProviderMetadata(entityId); IDPEndPointElement endpoint = metadataDocument.AssertionConsumerServiceEndpoints().Find(delegate(IDPEndPointElement e) { return(e.Binding == SAMLBinding.POST); }); if (endpoint == null) { Context.Response.Write(string.Format("'{0}' does not have a SSO endpoint that supports the POST binding.", entityId)); Context.Response.End(); return; } UserSessionsHandler.AddLoggedInSession(entityId); Response response = new Response(); response.Destination = endpoint.Url; response.InResponseTo = request.ID; response.Status = new Status(); response.Status.StatusCode = new StatusCode(); response.Status.StatusCode.Value = Saml20Constants.StatusCodes.Success; var nameIdFormat = metadataDocument.Entity.Items.OfType <SPSSODescriptor>().SingleOrDefault()?.NameIDFormat.SingleOrDefault() ?? Saml20Constants.NameIdentifierFormats.Persistent; Assertion assertion = CreateAssertion(user, entityId, nameIdFormat); var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm.SHA256); EncryptedAssertion encryptedAssertion = null; var keyDescriptors = metadataDocument.Keys.Where(x => x.use == KeyTypes.encryption); if (keyDescriptors.Any()) { foreach (KeyDescriptor keyDescriptor in keyDescriptors) { KeyInfo ki = (KeyInfo)keyDescriptor.KeyInfo; foreach (KeyInfoClause clause in ki) { if (clause is KeyInfoX509Data) { X509Certificate2 cert = XmlSignatureUtils.GetCertificateFromKeyInfo((KeyInfoX509Data)clause); var spec = new DefaultCertificateSpecification(); string error; if (spec.IsSatisfiedBy(cert, out error)) { AsymmetricAlgorithm key = XmlSignatureUtils.ExtractKey(clause); AssertionEncryptionUtility.AssertionEncryptionUtility encryptedAssertionUtil = new AssertionEncryptionUtility.AssertionEncryptionUtility((RSA)key, assertion); // Sign the assertion inside the response message. signatureProvider.SignAssertion(encryptedAssertionUtil.Assertion, assertion.ID, IDPConfig.IDPCertificate); encryptedAssertionUtil.Encrypt(); encryptedAssertion = Serialization.DeserializeFromXmlString <EncryptedAssertion>(encryptedAssertionUtil.EncryptedAssertion.OuterXml); break; } } } if (encryptedAssertion != null) { break; } } if (encryptedAssertion == null) { throw new Exception("Could not encrypt. No valid certificates found."); } } if (encryptedAssertion != null) { response.Items = new object[] { encryptedAssertion }; } else { response.Items = new object[] { assertion }; } // Serialize the response. XmlDocument responseDoc = new XmlDocument(); responseDoc.XmlResolver = null; responseDoc.PreserveWhitespace = true; responseDoc.LoadXml(Serialization.SerializeToXmlString(response)); if (encryptedAssertion == null) { // Sign the assertion inside the response message. signatureProvider.SignAssertion(responseDoc, assertion.ID, IDPConfig.IDPCertificate); } HttpPostBindingBuilder builder = new HttpPostBindingBuilder(endpoint); builder.Action = SAMLAction.SAMLResponse; builder.Response = responseDoc.OuterXml; builder.GetPage().ProcessRequest(Context); Context.Response.End(); }
private void 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 FactoryCreateFor(string testcase, SecurityKey key, string algorithm, SignatureProviderFactory factory, ExpectedException expectedException) { Console.WriteLine(string.Format("Testcase: '{0}'", testcase)); try { if (testcase.StartsWith("Siging")) { factory.CreateForSigning(key, algorithm); } else { factory.CreateForVerifying(key, algorithm); } expectedException.ProcessNoException(); } catch (Exception ex) { expectedException.ProcessException(ex); } }