public void CanParseCreatedArtifact() { // Arrange var sourceIdUrl = "https://kleopatra.safewhere.local/Saml2ExtWeb/artifact.ashx"; var sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceIdUrl); var messageHandle = ArtifactUtil.GenerateMessageHandle(); short typeCode = 4; short endpointIndex = 1; // Act var artifact = ArtifactUtil.CreateArtifact(typeCode, endpointIndex, sourceIdHash, messageHandle); short parsedTypeCode = -1; short parsedEndpointIndex = -1; var parsedSourceIdHash = new byte[20]; var parsedMessageHandle = new byte[20]; var result = ArtifactUtil.TryParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle); // Assert Assert.True(result, "Unable to parse artifact"); Assert.True(typeCode == parsedTypeCode, "Original and parsed typeCode did not match"); Assert.True(endpointIndex == parsedEndpointIndex, "Original and parsed endpointIndex did not match"); Assert.Equal(sourceIdHash, parsedSourceIdHash); //Assert.Fail("Original and parsed sourceIdHash are not identical"); Assert.Equal(messageHandle, parsedMessageHandle); //Assert.Fail("Original and parsed messageHandle are not identical"); }
/// <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> /// Handles all artifact creations and redirects. /// </summary> /// <param name="destination">The destination.</param> /// <param name="localEndpointIndex">Index of the local endpoint.</param> /// <param name="signedSamlMessage">The signed saml message.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> private void ArtifactRedirect(IDPEndPointElement destination, Int16 localEndpointIndex, XmlDocument signedSamlMessage, string relayState) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); string sourceId = config.ServiceProvider.ID; byte[] sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId); byte[] messageHandle = ArtifactUtil.GenerateMessageHandle(); string artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); _context.Cache.Insert(artifact, signedSamlMessage, null, DateTime.Now.AddMinutes(1), SamlCache.NoSlidingExpiration); string destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + HttpUtility.UrlEncode(artifact); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; } if (Trace.ShouldTrace(TraceEventType.Information)) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.CreatedArtifact, artifact, signedSamlMessage.OuterXml)); } _context.Response.Redirect(destinationUrl); }
public void CreateError2() { Int16 typeCode = 4; Int16 endpointIndex = 1; byte[] sourceIdHash = new byte[20]; byte[] messageHandle = new byte[19]; ArtifactUtil.CreateArtifact(typeCode, endpointIndex, sourceIdHash, messageHandle); }
public void ThrowsExceptionWhenSourceIdHashLengthMismatch() { // Arrange short typeCode = 4; short endpointIndex = 1; var sourceIdHash = new byte[19]; var messageHandle = new byte[20]; // Act Assert.Throws <ArgumentException>(() => ArtifactUtil.CreateArtifact(typeCode, endpointIndex, sourceIdHash, messageHandle)); }
public void ParseError1() { Int16 parsedTypeCode = -1; Int16 parsedEndpointIndex = -1; byte[] parsedSourceIdHash = new byte[19]; byte[] parsedMessageHandle = new byte[20]; string artifact = string.Empty; ArtifactUtil.ParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle); }
public void ThrowsExceptionWhenArtifactLengthMismatch() { // Arrange short parsedTypeCode = -1; short parsedEndpointIndex = -1; var parsedSourceIdHash = new byte[20]; var parsedMessageHandle = new byte[20]; var artifact = string.Empty; // Act Assert.Throws <ArgumentException>(() => ArtifactUtil.ParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle)); }
public void TryParseError3() { Int16 parsedTypeCode = -1; Int16 parsedEndpointIndex = -1; byte[] parsedSourceIdHash = new byte[20]; byte[] parsedMessageHandle = new byte[20]; string artifact = string.Empty; bool result = ArtifactUtil.TryParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle); Assert.That(!result, "TryParseArtifact did not fail as expected"); }
public void ReturnsFalseOnMessageHandleLengthMismatch() { // Arrange short parsedTypeCode = -1; short parsedEndpointIndex = -1; var parsedSourceIdHash = new byte[20]; var parsedMessageHandle = new byte[19]; var artifact = string.Empty; // Act var result = ArtifactUtil.TryParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle); // Assert Assert.That(!result, "TryParseArtifact did not fail as expected"); }
public void ArtifactCreateParse() { string sourceIdUrl = "https://kleopatra.safewhere.local/Saml2ExtWeb/artifact.ashx"; byte[] sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceIdUrl); Assert.That(sourceIdHash.Length == 20, "Unexpected hash length"); byte[] messageHandle = ArtifactUtil.GenerateMessageHandle(); Assert.That(messageHandle.Length == 20, "Unexpected hash length"); Int16 typeCode = 4; Int16 endpointIndex = 1; string artifact = ArtifactUtil.CreateArtifact(typeCode, endpointIndex, sourceIdHash, messageHandle); Int16 parsedTypeCode = -1; Int16 parsedEndpointIndex = -1; byte[] parsedSourceIdHash = new byte[20]; byte[] parsedMessageHandle = new byte[20]; Assert.That( ArtifactUtil.TryParseArtifact(artifact, ref parsedTypeCode, ref parsedEndpointIndex, ref parsedSourceIdHash, ref parsedMessageHandle), "Unable to parse artifact"); Assert.That(typeCode == parsedTypeCode, "Original and parsed typeCode did not match"); Assert.That(endpointIndex == parsedEndpointIndex, "Original and parsed endpointIndex did not match"); for (int i = 0; i < 20; i++) { if (sourceIdHash[i] != parsedSourceIdHash[i]) { Assert.Fail("Original and parsed sourceIdHash are not identical"); } } for (int i = 0; i < 20; i++) { if (messageHandle[i] != parsedMessageHandle[i]) { Assert.Fail("Original and parsed messageHandle are not identical"); } } }
/// <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> /// Determines which IdP an artifact has been sent from. /// </summary> /// <param name="artifact">The artifact.</param> /// <returns>An IdP configuration element</returns> private IdentityProvider DetermineIdp(string artifact) { short typeCodeValue = -1; short endPointIndex = -1; var sourceIdHash = new byte[20]; var messageHandle = new byte[20]; if (ArtifactUtil.TryParseArtifact(artifact, ref typeCodeValue, ref endPointIndex, ref sourceIdHash, ref messageHandle)) { foreach (IdentityProvider ep in config.IdentityProviders) { var hash = ArtifactUtil.GenerateSourceIdHash(ep.Id); if (ByteArraysAreEqual(sourceIdHash, hash)) { return(ep); } } } return(null); }
/// <summary> /// Determines which IdP an artifact has been sent from. /// </summary> /// <param name="artifact">The artifact.</param> /// <returns>An IdP configuration element</returns> private IDPEndPoint DetermineIdp(string artifact) { SAML20FederationConfig config = SAML20FederationConfig.GetConfig(); short typeCodeValue = -1; short endPointIndex = -1; byte[] sourceIdHash = new byte[20]; byte[] messageHandle = new byte[20]; if (ArtifactUtil.TryParseArtifact(artifact, ref typeCodeValue, ref endPointIndex, ref sourceIdHash, ref messageHandle)) { foreach(IDPEndPoint ep in config.IDPEndPoints) { byte[] hash = ArtifactUtil.GenerateSourceIdHash(ep.Id); if (AreEqual(sourceIdHash, hash)) return ep; } } return null; }
/// <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 all artifact creations and redirects. /// </summary> /// <param name="destination">The destination.</param> /// <param name="localEndpointIndex">Index of the local endpoint.</param> /// <param name="signedSamlMessage">The signed SAML message.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState) { Logger.DebugFormat(TraceMessages.ArtifactRedirectReceived, signedSamlMessage.OuterXml); var sourceId = config.ServiceProvider.Id; var sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId); var messageHandle = ArtifactUtil.GenerateMessageHandle(); var artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); Context.Cache.Insert(artifact, signedSamlMessage, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration); var destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + HttpUtility.UrlEncode(artifact); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; } Logger.DebugFormat(TraceMessages.ArtifactCreated, artifact); Context.Response.Redirect(destinationUrl); }
/// <summary> /// Handles all artifact creations and redirects. /// </summary> /// <param name="destination">The destination.</param> /// <param name="localEndpointIndex">Index of the local endpoint.</param> /// <param name="signedSamlMessage">The signed SAML message.</param> /// <param name="relayState">The query string relay state value to add to the communication</param> private void ArtifactRedirect(IdentityProviderEndpoint destination, short localEndpointIndex, XmlDocument signedSamlMessage, string relayState, Action <string, object> cacheInsert) { _logger.LogDebug(TraceMessages.ArtifactRedirectReceived, signedSamlMessage.OuterXml); var sourceId = config.ServiceProvider.Id; var sourceIdHash = ArtifactUtil.GenerateSourceIdHash(sourceId); var messageHandle = ArtifactUtil.GenerateMessageHandle(); var artifact = ArtifactUtil.CreateArtifact(HttpArtifactBindingConstants.ArtifactTypeCode, localEndpointIndex, sourceIdHash, messageHandle); cacheInsert(artifact, signedSamlMessage); var destinationUrl = destination.Url + "?" + HttpArtifactBindingConstants.ArtifactQueryStringName + "=" + Uri.EscapeDataString(artifact); if (!string.IsNullOrEmpty(relayState)) { destinationUrl += "&relayState=" + relayState; } _logger.LogDebug(TraceMessages.ArtifactCreated, artifact); redirect(destinationUrl); }