diff --git a/src/SAML2.Core/Config/IdentityProvider.cs b/src/SAML2.Core/Config/IdentityProvider.cs index f1b7e05..477bbe6 100644 --- a/src/SAML2.Core/Config/IdentityProvider.cs +++ b/src/SAML2.Core/Config/IdentityProvider.cs @@ -73,7 +73,6 @@ public class IdentityProvider /// The response encoding. public string ResponseEncoding { get; set; } - /// /// Gets or sets the artifact resolution. /// diff --git a/src/SAML2.Core/Config/Saml2Configuration.cs b/src/SAML2.Core/Config/Saml2Configuration.cs index 36b359e..35d362d 100644 --- a/src/SAML2.Core/Config/Saml2Configuration.cs +++ b/src/SAML2.Core/Config/Saml2Configuration.cs @@ -53,6 +53,15 @@ public class Saml2Configuration /// The service provider. public ServiceProvider ServiceProvider { get; set; } + /// + /// Gets or sets a value weather the response SAML message from IdP should be decompressed after it's BAse64 endoded. + /// Compression is used by some IdP providers for example PingFederate. + /// This perform these decode steps: https://www.samltool.com/decode.php (see Base64 Decode + Inflate page) + /// Default: false + /// + /// The response encoding. + public bool InflateResponseMessage { get; set; } + public Saml2Configuration() { IdentityProviders = new IdentityProviders(); diff --git a/src/SAML2.Core/Protocol/Utility.cs b/src/SAML2.Core/Protocol/Utility.cs index f863c46..ff1b7ac 100644 --- a/src/SAML2.Core/Protocol/Utility.cs +++ b/src/SAML2.Core/Protocol/Utility.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -153,14 +154,34 @@ public static void PreHandleAssertion(XmlElement elem, IdentityProvider endpoint /// /// This is base64 encoded SAML Response (usually SAMLResponse on query string) /// The encoding. + /// Wheater the response message should be inflated (decompressed). /// The decoded SAML response XML. - public static XmlDocument GetDecodedSamlResponse(string samlResponse, Encoding encoding) + public static XmlDocument GetDecodedSamlResponse(string samlResponse, Encoding encoding, bool infateResponse) { logger.Debug(TraceMessages.SamlResponseDecoding); + var samlResponseBytes = Convert.FromBase64String(samlResponse); + if (infateResponse) + { + logger.Debug(TraceMessages.SamlResponseDecodingDeflating); + + // The response message is compressed using the Deflate algorith. Need to decompress it first. + using (var decompressedStream = new MemoryStream()) + { + using (var compressedStream = new MemoryStream(samlResponseBytes)) + using (var decompressor = new DeflateStream(compressedStream, CompressionMode.Decompress)) + { + decompressor.CopyTo(decompressedStream); + } + samlResponseBytes = decompressedStream.ToArray(); + } + + logger.Debug(TraceMessages.SamlResponseDecodingDeflated); + } + + samlResponse = encoding.GetString(samlResponseBytes); var doc = new XmlDocument { PreserveWhitespace = true }; - samlResponse = encoding.GetString(Convert.FromBase64String(samlResponse)); doc.LoadXml(samlResponse); logger.DebugFormat(TraceMessages.SamlResponseDecoded, samlResponse); @@ -381,7 +402,7 @@ public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputSt public static Saml20Assertion HandleResponse(Saml2Configuration config, string samlResponse, IDictionary session, Func getFromCache, Action setInCache) { var defaultEncoding = Encoding.UTF8; - var doc = Utility.GetDecodedSamlResponse(samlResponse, defaultEncoding); + var doc = Utility.GetDecodedSamlResponse(samlResponse, defaultEncoding, config.InflateResponseMessage); logger.DebugFormat(TraceMessages.SamlResponseReceived, doc.OuterXml); // Determine whether the assertion should be decrypted before being validated. @@ -419,7 +440,7 @@ public static Saml20Assertion HandleResponse(Saml2Configuration config, string s } if (encodingOverride.CodePage != defaultEncoding.CodePage) { - var doc1 = GetDecodedSamlResponse(samlResponse, encodingOverride); + var doc1 = GetDecodedSamlResponse(samlResponse, encodingOverride, config.InflateResponseMessage); assertion = GetAssertion(doc1.DocumentElement, out isEncrypted); } } diff --git a/src/SAML2.Core/Resources.Designer.cs b/src/SAML2.Core/Resources.Designer.cs index 0ad53b4..19ec3d2 100644 --- a/src/SAML2.Core/Resources.Designer.cs +++ b/src/SAML2.Core/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.0 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/src/SAML2.Core/TraceMessages.resx b/src/SAML2.Core/TraceMessages.resx index 1f40883..bb1794b 100644 --- a/src/SAML2.Core/TraceMessages.resx +++ b/src/SAML2.Core/TraceMessages.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Artifact created: {0} @@ -273,4 +273,10 @@ SignOn handler called + + Deflating the response SAML message + + + The response SAML message was deflated + \ No newline at end of file diff --git a/src/SAML2.sln b/src/SAML2.sln index 72ae66d..a71bf44 100644 --- a/src/SAML2.sln +++ b/src/SAML2.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.22310.1 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAML2.Core", "SAML2.Core\SAML2.Core.csproj", "{75E5BAD2-A20C-43CC-B5C8-38004CEDBDFD}" EndProject