From 2ef9f4e5f2e8642617ba09ac2f52234a6d8d5d9e Mon Sep 17 00:00:00 2001 From: Benjamin Date: Fri, 24 Oct 2025 20:56:17 -0500 Subject: [PATCH 1/3] Minor performance improvements Made some improvements that improves performance a small amount, but cuts allocations by more than half. Also changed the accessors and added `readonly` to help enforce design guidelines. --- AspNetSaml/AspNetSaml.csproj | 1 + AspNetSaml/Saml.cs | 67 +++++++++++++++++------------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/AspNetSaml/AspNetSaml.csproj b/AspNetSaml/AspNetSaml.csproj index 7a17172..9e52ce7 100644 --- a/AspNetSaml/AspNetSaml.csproj +++ b/AspNetSaml/AspNetSaml.csproj @@ -23,6 +23,7 @@ + diff --git a/AspNetSaml/Saml.cs b/AspNetSaml/Saml.cs index 76ab5b0..8386448 100644 --- a/AspNetSaml/Saml.cs +++ b/AspNetSaml/Saml.cs @@ -14,6 +14,7 @@ Use this freely under the Apache license (see https://choosealicense.com/license using System.IO.Compression; using System.Text; using System.Runtime; +using System.Text.Encodings.Web; namespace Saml { @@ -283,14 +284,17 @@ protected override bool IsExpired() public abstract class BaseRequest { - public string _id; - protected string _issue_instant; - - protected string _issuer; - - public BaseRequest(string issuer) - { - _id = "_" + Guid.NewGuid().ToString(); + protected readonly string _id; + protected readonly string _issue_instant; + protected readonly string _issuer; + + protected static readonly XmlWriterSettings _xmlSettings = new XmlWriterSettings { + OmitXmlDeclaration = true, + Encoding = new UTF8Encoding(false) + }; + + protected BaseRequest(string issuer) { + _id = $"_{Guid.NewGuid()}"; _issue_instant = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture); _issuer = issuer; @@ -298,20 +302,17 @@ public BaseRequest(string issuer) public abstract string GetRequest(); - protected static string ConvertToBase64Deflated(string input) - { - //byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(input); - //return System.Convert.ToBase64String(toEncodeAsBytes); + protected static string ConvertToBase64Deflated(MemoryStream streamInput) { + streamInput.Seek(0, SeekOrigin.Begin); //https://stackoverflow.com/questions/25120025/acs75005-the-request-is-not-a-valid-saml2-protocol-message-is-showing-always%3C/a%3E - var memoryStream = new MemoryStream(); - using (var writer = new StreamWriter(new DeflateStream(memoryStream, CompressionMode.Compress, true), new UTF8Encoding(false))) - { - writer.Write(input); - writer.Close(); + using (var compressed = new MemoryStream()) { + using (var deflate = new DeflateStream(compressed, CompressionMode.Compress, leaveOpen: true)) { + streamInput.CopyTo(deflate); + } + + return Convert.ToBase64String(compressed.GetBuffer(), 0, (int)compressed.Length); } - string result = Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length, Base64FormattingOptions.None); - return result; } /// @@ -322,13 +323,13 @@ protected static string ConvertToBase64Deflated(string input) /// public string GetRedirectUrl(string samlEndpoint, string relayState = null) { - var queryStringSeparator = samlEndpoint.Contains("?") ? "&" : "?"; + var queryStringSeparator = samlEndpoint.Contains('?') ? '&' : '?'; - var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + Uri.EscapeDataString(GetRequest()); + var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + UrlEncoder.Default.Encode(GetRequest()); if (!string.IsNullOrEmpty(relayState)) { - url += "&RelayState=" + Uri.EscapeDataString(relayState); + url += "&RelayState=" + UrlEncoder.Default.Encode(relayState); } return url; @@ -337,7 +338,7 @@ public string GetRedirectUrl(string samlEndpoint, string relayState = null) public class AuthRequest : BaseRequest { - private string _assertionConsumerServiceUrl; + private readonly string _assertionConsumerServiceUrl; /// /// Initializes new instance of AuthRequest @@ -369,11 +370,9 @@ public enum AuthRequestFormat /// public override string GetRequest() { - using (StringWriter sw = new StringWriter()) + using (var ms = new MemoryStream()) { - XmlWriterSettings xws = new XmlWriterSettings { OmitXmlDeclaration = true }; - - using (XmlWriter xw = XmlWriter.Create(sw, xws)) + using (var xw = XmlWriter.Create(ms, _xmlSettings)) { xw.WriteStartElement("samlp", "AuthnRequest", "urn:oasis:names:tc:SAML:2.0:protocol"); xw.WriteAttributeString("ID", _id); @@ -403,7 +402,7 @@ public override string GetRequest() xw.WriteEndElement(); } - return ConvertToBase64Deflated(sw.ToString()); + return ConvertToBase64Deflated(ms); } } } @@ -413,20 +412,18 @@ public override string GetRequest() /// public class SignoutRequest : BaseRequest { - private string _nameId; + private readonly string _nameId; public SignoutRequest(string issuer, string nameId) : base(issuer) { _nameId = nameId; } - + public override string GetRequest() { - using (StringWriter sw = new StringWriter()) + using (var ms = new MemoryStream()) { - XmlWriterSettings xws = new XmlWriterSettings { OmitXmlDeclaration = true }; - - using (XmlWriter xw = XmlWriter.Create(sw, xws)) + using (var xw = XmlWriter.Create(ms, _xmlSettings)) { xw.WriteStartElement("samlp", "LogoutRequest", "urn:oasis:names:tc:SAML:2.0:protocol"); xw.WriteAttributeString("ID", _id); @@ -444,7 +441,7 @@ public override string GetRequest() xw.WriteEndElement(); } - return ConvertToBase64Deflated(sw.ToString()); + return ConvertToBase64Deflated(ms); } } } From b522fbf3825975f50dffb6a765d1924fd993d18f Mon Sep 17 00:00:00 2001 From: Benjamin Date: Fri, 24 Oct 2025 21:00:18 -0500 Subject: [PATCH 2/3] Update Saml.cs --- AspNetSaml/Saml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AspNetSaml/Saml.cs b/AspNetSaml/Saml.cs index 8386448..2fee4b6 100644 --- a/AspNetSaml/Saml.cs +++ b/AspNetSaml/Saml.cs @@ -311,7 +311,7 @@ protected static string ConvertToBase64Deflated(MemoryStream streamInput) { streamInput.CopyTo(deflate); } - return Convert.ToBase64String(compressed.GetBuffer(), 0, (int)compressed.Length); + return Convert.ToBase64String(compressed.GetBuffer(), 0, (int)compressed.Length, Base64FormattingOptions.None); } } From db57781192d45ce2b36515856d55a3ac6674f9b6 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Sat, 25 Oct 2025 08:36:20 -0500 Subject: [PATCH 3/3] Reverted URL encoding method --- AspNetSaml/AspNetSaml.csproj | 1 - AspNetSaml/Saml.cs | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/AspNetSaml/AspNetSaml.csproj b/AspNetSaml/AspNetSaml.csproj index 9e52ce7..7a17172 100644 --- a/AspNetSaml/AspNetSaml.csproj +++ b/AspNetSaml/AspNetSaml.csproj @@ -23,7 +23,6 @@ - diff --git a/AspNetSaml/Saml.cs b/AspNetSaml/Saml.cs index 2fee4b6..21fd2a1 100644 --- a/AspNetSaml/Saml.cs +++ b/AspNetSaml/Saml.cs @@ -13,8 +13,6 @@ Use this freely under the Apache license (see https://choosealicense.com/license using System.Security.Cryptography.Xml; using System.IO.Compression; using System.Text; -using System.Runtime; -using System.Text.Encodings.Web; namespace Saml { @@ -325,11 +323,11 @@ public string GetRedirectUrl(string samlEndpoint, string relayState = null) { var queryStringSeparator = samlEndpoint.Contains('?') ? '&' : '?'; - var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + UrlEncoder.Default.Encode(GetRequest()); + var url = samlEndpoint + queryStringSeparator + "SAMLRequest=" + Uri.EscapeDataString(GetRequest()); if (!string.IsNullOrEmpty(relayState)) { - url += "&RelayState=" + UrlEncoder.Default.Encode(relayState); + url += "&RelayState=" + Uri.EscapeDataString(relayState); } return url;