From 5fbc0c9e0b9f76ee5b432ae87a97b1aba8c20c7a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 16:53:47 -0400 Subject: [PATCH 1/7] Potentially fix a bug with deleting service connections --- src/Tgstation.Server.Host/Authority/UserAuthority.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Tgstation.Server.Host/Authority/UserAuthority.cs b/src/Tgstation.Server.Host/Authority/UserAuthority.cs index 0cb8310718..e9577dbcfd 100644 --- a/src/Tgstation.Server.Host/Authority/UserAuthority.cs +++ b/src/Tgstation.Server.Host/Authority/UserAuthority.cs @@ -495,7 +495,9 @@ namespace Tgstation.Server.Host.Authority if (model.OAuthConnections.Count == 0 && originalUser.PasswordHash == null && originalUser.SystemIdentifier == null) return BadRequest(ErrorCode.CannotRemoveLastAuthenticationOption); + DatabaseContext.OAuthConnections.RemoveRange(originalUser.OAuthConnections); originalUser.OAuthConnections.Clear(); + foreach (var updatedConnection in model.OAuthConnections) originalUser.OAuthConnections.Add(new Models.OAuthConnection { @@ -517,6 +519,7 @@ namespace Tgstation.Server.Host.Authority if (model.OidcConnections.Count == 0 && originalUser.PasswordHash == null && originalUser.SystemIdentifier == null) return BadRequest(ErrorCode.CannotRemoveLastAuthenticationOption); + DatabaseContext.OidcConnections.RemoveRange(originalUser.OidcConnections); originalUser.OidcConnections.Clear(); foreach (var updatedConnection in model.OidcConnections) originalUser.OidcConnections.Add(new Models.OidcConnection From 40125237ba033c339eeec5c34dc6de17ff97b472 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 16:56:00 -0400 Subject: [PATCH 2/7] Crossedfall test 1 --- build/Version.props | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 9 +- .../Core/ForwardedHeadersMiddleware.cs | 501 ++++++++++++++++++ 3 files changed, 509 insertions(+), 3 deletions(-) create mode 100644 src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs diff --git a/build/Version.props b/build/Version.props index edf4220733..6c380db619 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.1 + 6.15.100 5.6.0 10.13.0 0.6.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 93be5a1fec..0eebc4ebe2 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -619,10 +619,15 @@ namespace Tgstation.Server.Host.Core applicationBuilder.UseServerErrorHandling(); // header forwarding important for OIDC - applicationBuilder.UseForwardedHeaders(new ForwardedHeadersOptions + applicationBuilder.UseMiddleware(Options.Create(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, - }); + })); + + /*applicationBuilder.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, + });*/ // metrics capture applicationBuilder.UseHttpMetrics(); diff --git a/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs b/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs new file mode 100644 index 0000000000..e151890c3c --- /dev/null +++ b/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs @@ -0,0 +1,501 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#pragma warning disable +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; + +namespace Tgstation.Server.Host.Core; + +/// +/// A middleware for forwarding proxied headers onto the current request. +/// +public class ForwardedHeadersMiddleware +{ + private readonly ForwardedHeadersOptions _options; + private readonly RequestDelegate _next; + private readonly ILogger _logger; + private bool _allowAllHosts; + private IList? _allowedHosts; + + // RFC 3986 scheme = ALPHA * (ALPHA / DIGIT / "+" / "-" / ".") + private static readonly SearchValues SchemeChars = + SearchValues.Create("+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + + // Host Matches Http.Sys and Kestrel + // Host Matches RFC 3986 except "*" / "+" / "," / ";" / "=" and "%" HEXDIG HEXDIG which are not allowed by Http.Sys + private static readonly SearchValues HostChars = + SearchValues.Create("!$&'()-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"); + + // 0-9 / A-F / a-f / ":" / "." + private static readonly SearchValues Ipv6HostChars = + SearchValues.Create(".0123456789:ABCDEFabcdef"); + + /// + /// Create a new . + /// + /// The representing the next middleware in the pipeline. + /// The used for logging. + /// The for configuring the middleware. + public ForwardedHeadersMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions options) + { + ArgumentNullException.ThrowIfNull(next); + ArgumentNullException.ThrowIfNull(loggerFactory); + ArgumentNullException.ThrowIfNull(options); + + // Make sure required options is not null or whitespace + EnsureOptionNotNullorWhitespace(options.Value.ForwardedForHeaderName, nameof(options.Value.ForwardedForHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.ForwardedHostHeaderName, nameof(options.Value.ForwardedHostHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.ForwardedProtoHeaderName, nameof(options.Value.ForwardedProtoHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.ForwardedPrefixHeaderName, nameof(options.Value.ForwardedPrefixHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalForHeaderName, nameof(options.Value.OriginalForHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalHostHeaderName, nameof(options.Value.OriginalHostHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalProtoHeaderName, nameof(options.Value.OriginalProtoHeaderName)); + EnsureOptionNotNullorWhitespace(options.Value.OriginalPrefixHeaderName, nameof(options.Value.OriginalPrefixHeaderName)); + + _options = options.Value; + _logger = loggerFactory.CreateLogger(); + _next = next; + + PreProcessHosts(); + + static void EnsureOptionNotNullorWhitespace(string value, string propertyName) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException($"options.{propertyName} is required", nameof(options)); + } + } + } + + private void PreProcessHosts() + { + if (_options.AllowedHosts == null || _options.AllowedHosts.Count == 0) + { + _allowAllHosts = true; + return; + } + + var allowedHosts = new List(); + foreach (var entry in _options.AllowedHosts) + { + // Punycode. Http.Sys requires you to register Unicode hosts, but the headers contain punycode. + var host = new HostString(entry).ToUriComponent(); + + if (IsTopLevelWildcard(host)) + { + // Disable filtering + _allowAllHosts = true; + return; + } + + if (!allowedHosts.Contains(host, StringSegmentComparer.OrdinalIgnoreCase)) + { + allowedHosts.Add(host); + } + } + + _allowedHosts = allowedHosts; + } + + private static bool IsTopLevelWildcard(string host) + { + return (string.Equals("*", host, StringComparison.Ordinal) // HttpSys wildcard + || string.Equals("[::]", host, StringComparison.Ordinal) // Kestrel wildcard, IPv6 Any + || string.Equals("0.0.0.0", host, StringComparison.Ordinal)); // IPv4 Any + } + + /// + /// Executes the middleware. + /// + /// The for the current request. + public Task Invoke(HttpContext context) + { + ApplyForwarders(context); + return _next(context); + } + + /// + /// Forward the proxied headers to the given . + /// + /// The . + public void ApplyForwarders(HttpContext context) + { + // Gather expected headers. + string[]? forwardedFor = null, forwardedProto = null, forwardedHost = null, forwardedPrefix = null; + bool checkFor = false, checkProto = false, checkHost = false, checkPrefix = false; + int entryCount = 0; + + var request = context.Request; + var requestHeaders = context.Request.Headers; + if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedFor)) + { + checkFor = true; + forwardedFor = requestHeaders.GetCommaSeparatedValues(_options.ForwardedForHeaderName); + entryCount = Math.Max(forwardedFor.Length, entryCount); + } + + if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedProto)) + { + checkProto = true; + forwardedProto = requestHeaders.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName); + if (_options.RequireHeaderSymmetry && checkFor && forwardedFor!.Length != forwardedProto.Length) + { + _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); + return; + } + entryCount = Math.Max(forwardedProto.Length, entryCount); + } + + if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedHost)) + { + checkHost = true; + forwardedHost = requestHeaders.GetCommaSeparatedValues(_options.ForwardedHostHeaderName); + if (_options.RequireHeaderSymmetry + && ((checkFor && forwardedFor!.Length != forwardedHost.Length) + || (checkProto && forwardedProto!.Length != forwardedHost.Length))) + { + _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); + return; + } + entryCount = Math.Max(forwardedHost.Length, entryCount); + } + + if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedPrefix)) + { + checkPrefix = true; + forwardedPrefix = requestHeaders.GetCommaSeparatedValues(_options.ForwardedPrefixHeaderName); + if (_options.RequireHeaderSymmetry + && ((checkFor && forwardedFor!.Length != forwardedPrefix.Length) + || (checkProto && forwardedProto!.Length != forwardedPrefix.Length) + || (checkHost && forwardedHost!.Length != forwardedPrefix.Length))) + { + _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-Prefix and X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); + return; + } + entryCount = Math.Max(forwardedPrefix.Length, entryCount); + } + + // Apply ForwardLimit, if any + if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) + { + entryCount = _options.ForwardLimit.Value; + } + + // Group the data together. + var sets = new SetOfForwarders[entryCount]; + for (int i = 0; i < sets.Length; i++) + { + // They get processed in reverse order, right to left. + var set = new SetOfForwarders(); + if (checkFor && i < forwardedFor!.Length) + { + set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1]; + } + if (checkProto && i < forwardedProto!.Length) + { + set.Scheme = forwardedProto[forwardedProto.Length - i - 1]; + } + if (checkHost && i < forwardedHost!.Length) + { + set.Host = forwardedHost[forwardedHost.Length - i - 1]; + } + if (checkPrefix && i < forwardedPrefix!.Length) + { + set.Prefix = forwardedPrefix[forwardedPrefix.Length - i - 1]; + } + sets[i] = set; + } + + // Gather initial values + var connection = context.Connection; + var currentValues = new SetOfForwarders() + { + RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, + // Host and Scheme initial values are never inspected, no need to set them here. + }; + + var checkKnownIps = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0; + bool applyChanges = false; + int entriesConsumed = 0; + + for (; entriesConsumed < sets.Length; entriesConsumed++) + { + var set = sets[entriesConsumed]; + if (checkFor) + { + // For the first instance, allow remoteIp to be null for servers that don't support it natively. + if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address)) + { + // Stop at the first unknown remote IP, but still apply changes processed so far. + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort); + } + break; + } + + if (IPEndPoint.TryParse(set.IpAndPortText, out var parsedEndPoint)) + { + applyChanges = true; + set.RemoteIpAndPort = parsedEndPoint; + currentValues.IpAndPortText = set.IpAndPortText; + currentValues.RemoteIpAndPort = set.RemoteIpAndPort; + } + else if (!string.IsNullOrEmpty(set.IpAndPortText)) + { + // Stop at the first unparsable IP, but still apply changes processed so far. + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(1, "Unparsable IP: {IpAndPortText}", set.IpAndPortText); + } + break; + } + else if (_options.RequireHeaderSymmetry) + { + _logger.LogWarning(2, "Missing forwarded IPAddress."); + return; + } + } + + if (checkProto) + { + if (!string.IsNullOrEmpty(set.Scheme) && set.Scheme.AsSpan().IndexOfAnyExcept(SchemeChars) < 0) + { + applyChanges = true; + currentValues.Scheme = set.Scheme; + } + else if (_options.RequireHeaderSymmetry) + { + _logger.LogWarning(3, $"Forwarded scheme is not present, this is required by {nameof(_options.RequireHeaderSymmetry)}"); + return; + } + } + + if (checkHost) + { + if (!string.IsNullOrEmpty(set.Host) && TryValidateHost(set.Host) + && (_allowAllHosts || HostString.MatchesAny(set.Host, _allowedHosts!))) + { + applyChanges = true; + currentValues.Host = set.Host; + } + else if (_options.RequireHeaderSymmetry) + { + _logger.LogWarning(4, $"Incorrect number of x-forwarded-host header values, see {nameof(_options.RequireHeaderSymmetry)}."); + return; + } + } + + if (checkPrefix) + { + if (!string.IsNullOrEmpty(set.Prefix) && set.Prefix[0] == '/') + { + applyChanges = true; + currentValues.Prefix = set.Prefix; + } + else if (_options.RequireHeaderSymmetry) + { + _logger.LogWarning(5, $"Incorrect number of x-forwarded-prefix header values, see {nameof(_options.RequireHeaderSymmetry)}"); + return; + } + } + } + + if (applyChanges) + { + if (checkFor && currentValues.RemoteIpAndPort != null) + { + if (connection.RemoteIpAddress != null) + { + // Save the original + requestHeaders[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); + } + if (forwardedFor!.Length > entriesConsumed) + { + // Truncate the consumed header values + requestHeaders[_options.ForwardedForHeaderName] = + TruncateConsumedHeaderValues(forwardedFor, entriesConsumed); + } + else + { + // All values were consumed + requestHeaders.Remove(_options.ForwardedForHeaderName); + } + connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; + connection.RemotePort = currentValues.RemoteIpAndPort.Port; + } + + if (checkProto && currentValues.Scheme != null) + { + // Save the original + requestHeaders[_options.OriginalProtoHeaderName] = request.Scheme; + if (forwardedProto!.Length > entriesConsumed) + { + // Truncate the consumed header values + requestHeaders[_options.ForwardedProtoHeaderName] = + TruncateConsumedHeaderValues(forwardedProto, entriesConsumed); + } + else + { + // All values were consumed + requestHeaders.Remove(_options.ForwardedProtoHeaderName); + } + request.Scheme = currentValues.Scheme; + } + + if (checkHost && currentValues.Host != null) + { + // Save the original + requestHeaders[_options.OriginalHostHeaderName] = request.Host.ToString(); + if (forwardedHost!.Length > entriesConsumed) + { + // Truncate the consumed header values + requestHeaders[_options.ForwardedHostHeaderName] = + TruncateConsumedHeaderValues(forwardedHost, entriesConsumed); + } + else + { + // All values were consumed + requestHeaders.Remove(_options.ForwardedHostHeaderName); + } + request.Host = HostString.FromUriComponent(currentValues.Host); + } + + if (checkPrefix && currentValues.Prefix != null) + { + if (request.PathBase.HasValue) + { + // Save the original + requestHeaders[_options.OriginalPrefixHeaderName] = request.PathBase.ToString(); + } + + if (forwardedPrefix!.Length > entriesConsumed) + { + // Truncate the consumed header values + requestHeaders[_options.ForwardedPrefixHeaderName] = + TruncateConsumedHeaderValues(forwardedPrefix, entriesConsumed); + } + else + { + // All values were consumed + requestHeaders.Remove(_options.ForwardedPrefixHeaderName); + } + + request.PathBase = PathString.FromUriComponent(currentValues.Prefix); + } + } + } + + private bool CheckKnownAddress(IPAddress address) + { + if (address.IsIPv4MappedToIPv6) + { + var ipv4Address = address.MapToIPv4(); + if (CheckKnownAddress(ipv4Address)) + { + return true; + } + } + if (_options.KnownProxies.Contains(address)) + { + return true; + } + foreach (var network in _options.KnownNetworks) + { + if (network.Contains(address)) + { + return true; + } + } + return false; + } + + private struct SetOfForwarders + { + public string IpAndPortText; + public IPEndPoint? RemoteIpAndPort; + public string Host; + public string Scheme; + public string Prefix; + } + + // Empty was checked for by the caller + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryValidateHost(string host) + { + if (host[0] == '[') + { + return TryValidateIPv6Host(host); + } + + if (host[0] == ':') + { + // Only a port + return false; + } + + var firstNonHostCharIdx = host.AsSpan().IndexOfAnyExcept(HostChars); + if (firstNonHostCharIdx == -1) + { + // no port + return true; + } + else + { + return TryValidateHostPort(host, firstNonHostCharIdx); + } + } + + // The lead '[' was already checked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryValidateIPv6Host(string hostText) + { + var host = hostText.AsSpan(1); + + var hostEndIdx = host.IndexOfAnyExcept(Ipv6HostChars); + if ((uint)hostEndIdx >= (uint)host.Length || // No ']'. The uint cast is there to eliminate the + // bounds check on the 'host[hostEndIdx]' access below. + host[hostEndIdx] != ']' || // We found an invalid host character + hostEndIdx < 3) // [::1] is the shortest valid IPv6 host + { + return false; + } + + // If there's nothing left, we're good. If there's more, validate it as a port. + // +2 to skip the '[' and ']' (the '[' wasn't included in hostEndIdx because we + // cut it off in the AsSpan above). + return (hostEndIdx + 2 == hostText.Length) || TryValidateHostPort(hostText, hostEndIdx + 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryValidateHostPort(string hostText, int offset) + { + if (hostText[offset] != ':' || hostText.Length == offset + 1) + { + // Must have at least one number after the colon if present. + return false; + } + + return hostText.AsSpan(offset + 1).IndexOfAnyExceptInRange('0', '9') < 0; + } + + private static string[] TruncateConsumedHeaderValues(string[] forwarded, int entriesConsumed) + { + var newLength = forwarded.Length - entriesConsumed; + var remaining = new string[newLength]; + Array.Copy(forwarded, remaining, newLength); + return remaining; + } +} From 7bbae05668a34d85e6e7a7da755db3d4b73de067 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 19:13:36 -0400 Subject: [PATCH 3/7] Crossedfall test 2 --- build/Version.props | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 23 +++++++++++++++++++ .../Core/ForwardedHeadersMiddleware.cs | 11 +++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index 6c380db619..5e2e897532 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.100 + 6.15.101 5.6.0 10.13.0 0.6.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 0eebc4ebe2..11f9e8763a 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -577,6 +577,7 @@ namespace Tgstation.Server.Host.Core /// The containing the to use. /// The containing the to use. /// The for the . + #pragma warning disable public void Configure( IApplicationBuilder applicationBuilder, IServerControl serverControl, @@ -618,12 +619,34 @@ namespace Tgstation.Server.Host.Core // Wrap exceptions in a 500 (ErrorMessage) response applicationBuilder.UseServerErrorHandling(); + applicationBuilder.Use((context, next) => + { + logger.LogDebug("Crossedfall Pre middleware:"); + foreach (var header in context.Request.Headers) + { + logger.LogDebug("{header}: {value}", header.Key, header.Value); + } + + return next(); + }); + // header forwarding important for OIDC applicationBuilder.UseMiddleware(Options.Create(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, })); + applicationBuilder.Use((context, next) => + { + logger.LogDebug("Crossedfall Post middleware:"); + foreach (var header in context.Request.Headers) + { + logger.LogDebug("{header}: {value}", header.Key, header.Value); + } + + return next(); + }); + /*applicationBuilder.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, diff --git a/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs b/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs index e151890c3c..a128a24e8f 100644 --- a/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs +++ b/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs @@ -122,7 +122,9 @@ public class ForwardedHeadersMiddleware /// The for the current request. public Task Invoke(HttpContext context) { + _logger.LogDebug("Pre apply"); ApplyForwarders(context); + _logger.LogDebug("Post apply"); return _next(context); } @@ -150,6 +152,7 @@ public class ForwardedHeadersMiddleware { checkProto = true; forwardedProto = requestHeaders.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName); + _logger.LogDebug("Checking proto: {forwarded}", forwardedProto); if (_options.RequireHeaderSymmetry && checkFor && forwardedFor!.Length != forwardedProto.Length) { _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); @@ -197,6 +200,7 @@ public class ForwardedHeadersMiddleware var sets = new SetOfForwarders[entryCount]; for (int i = 0; i < sets.Length; i++) { + _logger.LogDebug("Set iter: {i}", i); // They get processed in reverse order, right to left. var set = new SetOfForwarders(); if (checkFor && i < forwardedFor!.Length) @@ -206,6 +210,7 @@ public class ForwardedHeadersMiddleware if (checkProto && i < forwardedProto!.Length) { set.Scheme = forwardedProto[forwardedProto.Length - i - 1]; + _logger.LogDebug("Set scheme: {scheme}", set.Scheme); } if (checkHost && i < forwardedHost!.Length) { @@ -232,6 +237,7 @@ public class ForwardedHeadersMiddleware for (; entriesConsumed < sets.Length; entriesConsumed++) { + _logger.LogDebug("Consume iter: {i}", entriesConsumed); var set = sets[entriesConsumed]; if (checkFor) { @@ -271,8 +277,10 @@ public class ForwardedHeadersMiddleware if (checkProto) { + _logger.LogDebug("Consume check proto: {setScheme}", set.Scheme); if (!string.IsNullOrEmpty(set.Scheme) && set.Scheme.AsSpan().IndexOfAnyExcept(SchemeChars) < 0) { + _logger.LogDebug("Consume apply proto"); applyChanges = true; currentValues.Scheme = set.Scheme; } @@ -315,6 +323,7 @@ public class ForwardedHeadersMiddleware if (applyChanges) { + _logger.LogDebug("Apply changes: {scheme}", currentValues.Scheme); if (checkFor && currentValues.RemoteIpAndPort != null) { if (connection.RemoteIpAddress != null) @@ -353,6 +362,8 @@ public class ForwardedHeadersMiddleware requestHeaders.Remove(_options.ForwardedProtoHeaderName); } request.Scheme = currentValues.Scheme; + + _logger.LogDebug("Do apply proto: {scheme}, {forwarded}", request.Scheme, forwardedProto); } if (checkHost && currentValues.Host != null) From 4c1d5af48c954e68d1d2530b5b5b27154a881b10 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 19:56:17 -0400 Subject: [PATCH 4/7] Crossedfall test 3 --- build/Version.props | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/build/Version.props b/build/Version.props index 5e2e897532..3135589409 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.101 + 6.15.102 5.6.0 10.13.0 0.6.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 11f9e8763a..d292e85c70 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -631,10 +631,19 @@ namespace Tgstation.Server.Host.Core }); // header forwarding important for OIDC - applicationBuilder.UseMiddleware(Options.Create(new ForwardedHeadersOptions + var forwardedHeaderOptions = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, - })); + AllowedHosts = null, + }; + + forwardedHeaderOptions.KnownNetworks.Clear(); + forwardedHeaderOptions.KnownNetworks.Add( + new IPNetwork( + global::System.Net.IPAddress.Any, + 0)); + + applicationBuilder.UseMiddleware(Options.Create(forwardedHeaderOptions)); applicationBuilder.Use((context, next) => { From d2d61b78e74709cecd5b5ddb792ef9a56fcf5301 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 20:07:27 -0400 Subject: [PATCH 5/7] Carbonhell test 4 --- build/Version.props | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../Core/ForwardedHeadersMiddleware.cs | 512 ------------------ 3 files changed, 2 insertions(+), 514 deletions(-) delete mode 100644 src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs diff --git a/build/Version.props b/build/Version.props index 3135589409..619f513bf4 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.102 + 6.15.104 5.6.0 10.13.0 0.6.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index d292e85c70..bf95511814 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -643,7 +643,7 @@ namespace Tgstation.Server.Host.Core global::System.Net.IPAddress.Any, 0)); - applicationBuilder.UseMiddleware(Options.Create(forwardedHeaderOptions)); + applicationBuilder.UseForwardedHeaders(forwardedHeaderOptions); applicationBuilder.Use((context, next) => { diff --git a/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs b/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs deleted file mode 100644 index a128a24e8f..0000000000 --- a/src/Tgstation.Server.Host/Core/ForwardedHeadersMiddleware.cs +++ /dev/null @@ -1,512 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Primitives; - -namespace Tgstation.Server.Host.Core; - -/// -/// A middleware for forwarding proxied headers onto the current request. -/// -public class ForwardedHeadersMiddleware -{ - private readonly ForwardedHeadersOptions _options; - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private bool _allowAllHosts; - private IList? _allowedHosts; - - // RFC 3986 scheme = ALPHA * (ALPHA / DIGIT / "+" / "-" / ".") - private static readonly SearchValues SchemeChars = - SearchValues.Create("+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); - - // Host Matches Http.Sys and Kestrel - // Host Matches RFC 3986 except "*" / "+" / "," / ";" / "=" and "%" HEXDIG HEXDIG which are not allowed by Http.Sys - private static readonly SearchValues HostChars = - SearchValues.Create("!$&'()-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"); - - // 0-9 / A-F / a-f / ":" / "." - private static readonly SearchValues Ipv6HostChars = - SearchValues.Create(".0123456789:ABCDEFabcdef"); - - /// - /// Create a new . - /// - /// The representing the next middleware in the pipeline. - /// The used for logging. - /// The for configuring the middleware. - public ForwardedHeadersMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions options) - { - ArgumentNullException.ThrowIfNull(next); - ArgumentNullException.ThrowIfNull(loggerFactory); - ArgumentNullException.ThrowIfNull(options); - - // Make sure required options is not null or whitespace - EnsureOptionNotNullorWhitespace(options.Value.ForwardedForHeaderName, nameof(options.Value.ForwardedForHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.ForwardedHostHeaderName, nameof(options.Value.ForwardedHostHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.ForwardedProtoHeaderName, nameof(options.Value.ForwardedProtoHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.ForwardedPrefixHeaderName, nameof(options.Value.ForwardedPrefixHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.OriginalForHeaderName, nameof(options.Value.OriginalForHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.OriginalHostHeaderName, nameof(options.Value.OriginalHostHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.OriginalProtoHeaderName, nameof(options.Value.OriginalProtoHeaderName)); - EnsureOptionNotNullorWhitespace(options.Value.OriginalPrefixHeaderName, nameof(options.Value.OriginalPrefixHeaderName)); - - _options = options.Value; - _logger = loggerFactory.CreateLogger(); - _next = next; - - PreProcessHosts(); - - static void EnsureOptionNotNullorWhitespace(string value, string propertyName) - { - if (string.IsNullOrWhiteSpace(value)) - { - throw new ArgumentException($"options.{propertyName} is required", nameof(options)); - } - } - } - - private void PreProcessHosts() - { - if (_options.AllowedHosts == null || _options.AllowedHosts.Count == 0) - { - _allowAllHosts = true; - return; - } - - var allowedHosts = new List(); - foreach (var entry in _options.AllowedHosts) - { - // Punycode. Http.Sys requires you to register Unicode hosts, but the headers contain punycode. - var host = new HostString(entry).ToUriComponent(); - - if (IsTopLevelWildcard(host)) - { - // Disable filtering - _allowAllHosts = true; - return; - } - - if (!allowedHosts.Contains(host, StringSegmentComparer.OrdinalIgnoreCase)) - { - allowedHosts.Add(host); - } - } - - _allowedHosts = allowedHosts; - } - - private static bool IsTopLevelWildcard(string host) - { - return (string.Equals("*", host, StringComparison.Ordinal) // HttpSys wildcard - || string.Equals("[::]", host, StringComparison.Ordinal) // Kestrel wildcard, IPv6 Any - || string.Equals("0.0.0.0", host, StringComparison.Ordinal)); // IPv4 Any - } - - /// - /// Executes the middleware. - /// - /// The for the current request. - public Task Invoke(HttpContext context) - { - _logger.LogDebug("Pre apply"); - ApplyForwarders(context); - _logger.LogDebug("Post apply"); - return _next(context); - } - - /// - /// Forward the proxied headers to the given . - /// - /// The . - public void ApplyForwarders(HttpContext context) - { - // Gather expected headers. - string[]? forwardedFor = null, forwardedProto = null, forwardedHost = null, forwardedPrefix = null; - bool checkFor = false, checkProto = false, checkHost = false, checkPrefix = false; - int entryCount = 0; - - var request = context.Request; - var requestHeaders = context.Request.Headers; - if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedFor)) - { - checkFor = true; - forwardedFor = requestHeaders.GetCommaSeparatedValues(_options.ForwardedForHeaderName); - entryCount = Math.Max(forwardedFor.Length, entryCount); - } - - if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedProto)) - { - checkProto = true; - forwardedProto = requestHeaders.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName); - _logger.LogDebug("Checking proto: {forwarded}", forwardedProto); - if (_options.RequireHeaderSymmetry && checkFor && forwardedFor!.Length != forwardedProto.Length) - { - _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); - return; - } - entryCount = Math.Max(forwardedProto.Length, entryCount); - } - - if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedHost)) - { - checkHost = true; - forwardedHost = requestHeaders.GetCommaSeparatedValues(_options.ForwardedHostHeaderName); - if (_options.RequireHeaderSymmetry - && ((checkFor && forwardedFor!.Length != forwardedHost.Length) - || (checkProto && forwardedProto!.Length != forwardedHost.Length))) - { - _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); - return; - } - entryCount = Math.Max(forwardedHost.Length, entryCount); - } - - if (_options.ForwardedHeaders.HasFlag(ForwardedHeaders.XForwardedPrefix)) - { - checkPrefix = true; - forwardedPrefix = requestHeaders.GetCommaSeparatedValues(_options.ForwardedPrefixHeaderName); - if (_options.RequireHeaderSymmetry - && ((checkFor && forwardedFor!.Length != forwardedPrefix.Length) - || (checkProto && forwardedProto!.Length != forwardedPrefix.Length) - || (checkHost && forwardedHost!.Length != forwardedPrefix.Length))) - { - _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-Prefix and X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); - return; - } - entryCount = Math.Max(forwardedPrefix.Length, entryCount); - } - - // Apply ForwardLimit, if any - if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) - { - entryCount = _options.ForwardLimit.Value; - } - - // Group the data together. - var sets = new SetOfForwarders[entryCount]; - for (int i = 0; i < sets.Length; i++) - { - _logger.LogDebug("Set iter: {i}", i); - // They get processed in reverse order, right to left. - var set = new SetOfForwarders(); - if (checkFor && i < forwardedFor!.Length) - { - set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1]; - } - if (checkProto && i < forwardedProto!.Length) - { - set.Scheme = forwardedProto[forwardedProto.Length - i - 1]; - _logger.LogDebug("Set scheme: {scheme}", set.Scheme); - } - if (checkHost && i < forwardedHost!.Length) - { - set.Host = forwardedHost[forwardedHost.Length - i - 1]; - } - if (checkPrefix && i < forwardedPrefix!.Length) - { - set.Prefix = forwardedPrefix[forwardedPrefix.Length - i - 1]; - } - sets[i] = set; - } - - // Gather initial values - var connection = context.Connection; - var currentValues = new SetOfForwarders() - { - RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, - // Host and Scheme initial values are never inspected, no need to set them here. - }; - - var checkKnownIps = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0; - bool applyChanges = false; - int entriesConsumed = 0; - - for (; entriesConsumed < sets.Length; entriesConsumed++) - { - _logger.LogDebug("Consume iter: {i}", entriesConsumed); - var set = sets[entriesConsumed]; - if (checkFor) - { - // For the first instance, allow remoteIp to be null for servers that don't support it natively. - if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address)) - { - // Stop at the first unknown remote IP, but still apply changes processed so far. - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort); - } - break; - } - - if (IPEndPoint.TryParse(set.IpAndPortText, out var parsedEndPoint)) - { - applyChanges = true; - set.RemoteIpAndPort = parsedEndPoint; - currentValues.IpAndPortText = set.IpAndPortText; - currentValues.RemoteIpAndPort = set.RemoteIpAndPort; - } - else if (!string.IsNullOrEmpty(set.IpAndPortText)) - { - // Stop at the first unparsable IP, but still apply changes processed so far. - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug(1, "Unparsable IP: {IpAndPortText}", set.IpAndPortText); - } - break; - } - else if (_options.RequireHeaderSymmetry) - { - _logger.LogWarning(2, "Missing forwarded IPAddress."); - return; - } - } - - if (checkProto) - { - _logger.LogDebug("Consume check proto: {setScheme}", set.Scheme); - if (!string.IsNullOrEmpty(set.Scheme) && set.Scheme.AsSpan().IndexOfAnyExcept(SchemeChars) < 0) - { - _logger.LogDebug("Consume apply proto"); - applyChanges = true; - currentValues.Scheme = set.Scheme; - } - else if (_options.RequireHeaderSymmetry) - { - _logger.LogWarning(3, $"Forwarded scheme is not present, this is required by {nameof(_options.RequireHeaderSymmetry)}"); - return; - } - } - - if (checkHost) - { - if (!string.IsNullOrEmpty(set.Host) && TryValidateHost(set.Host) - && (_allowAllHosts || HostString.MatchesAny(set.Host, _allowedHosts!))) - { - applyChanges = true; - currentValues.Host = set.Host; - } - else if (_options.RequireHeaderSymmetry) - { - _logger.LogWarning(4, $"Incorrect number of x-forwarded-host header values, see {nameof(_options.RequireHeaderSymmetry)}."); - return; - } - } - - if (checkPrefix) - { - if (!string.IsNullOrEmpty(set.Prefix) && set.Prefix[0] == '/') - { - applyChanges = true; - currentValues.Prefix = set.Prefix; - } - else if (_options.RequireHeaderSymmetry) - { - _logger.LogWarning(5, $"Incorrect number of x-forwarded-prefix header values, see {nameof(_options.RequireHeaderSymmetry)}"); - return; - } - } - } - - if (applyChanges) - { - _logger.LogDebug("Apply changes: {scheme}", currentValues.Scheme); - if (checkFor && currentValues.RemoteIpAndPort != null) - { - if (connection.RemoteIpAddress != null) - { - // Save the original - requestHeaders[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); - } - if (forwardedFor!.Length > entriesConsumed) - { - // Truncate the consumed header values - requestHeaders[_options.ForwardedForHeaderName] = - TruncateConsumedHeaderValues(forwardedFor, entriesConsumed); - } - else - { - // All values were consumed - requestHeaders.Remove(_options.ForwardedForHeaderName); - } - connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; - connection.RemotePort = currentValues.RemoteIpAndPort.Port; - } - - if (checkProto && currentValues.Scheme != null) - { - // Save the original - requestHeaders[_options.OriginalProtoHeaderName] = request.Scheme; - if (forwardedProto!.Length > entriesConsumed) - { - // Truncate the consumed header values - requestHeaders[_options.ForwardedProtoHeaderName] = - TruncateConsumedHeaderValues(forwardedProto, entriesConsumed); - } - else - { - // All values were consumed - requestHeaders.Remove(_options.ForwardedProtoHeaderName); - } - request.Scheme = currentValues.Scheme; - - _logger.LogDebug("Do apply proto: {scheme}, {forwarded}", request.Scheme, forwardedProto); - } - - if (checkHost && currentValues.Host != null) - { - // Save the original - requestHeaders[_options.OriginalHostHeaderName] = request.Host.ToString(); - if (forwardedHost!.Length > entriesConsumed) - { - // Truncate the consumed header values - requestHeaders[_options.ForwardedHostHeaderName] = - TruncateConsumedHeaderValues(forwardedHost, entriesConsumed); - } - else - { - // All values were consumed - requestHeaders.Remove(_options.ForwardedHostHeaderName); - } - request.Host = HostString.FromUriComponent(currentValues.Host); - } - - if (checkPrefix && currentValues.Prefix != null) - { - if (request.PathBase.HasValue) - { - // Save the original - requestHeaders[_options.OriginalPrefixHeaderName] = request.PathBase.ToString(); - } - - if (forwardedPrefix!.Length > entriesConsumed) - { - // Truncate the consumed header values - requestHeaders[_options.ForwardedPrefixHeaderName] = - TruncateConsumedHeaderValues(forwardedPrefix, entriesConsumed); - } - else - { - // All values were consumed - requestHeaders.Remove(_options.ForwardedPrefixHeaderName); - } - - request.PathBase = PathString.FromUriComponent(currentValues.Prefix); - } - } - } - - private bool CheckKnownAddress(IPAddress address) - { - if (address.IsIPv4MappedToIPv6) - { - var ipv4Address = address.MapToIPv4(); - if (CheckKnownAddress(ipv4Address)) - { - return true; - } - } - if (_options.KnownProxies.Contains(address)) - { - return true; - } - foreach (var network in _options.KnownNetworks) - { - if (network.Contains(address)) - { - return true; - } - } - return false; - } - - private struct SetOfForwarders - { - public string IpAndPortText; - public IPEndPoint? RemoteIpAndPort; - public string Host; - public string Scheme; - public string Prefix; - } - - // Empty was checked for by the caller - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryValidateHost(string host) - { - if (host[0] == '[') - { - return TryValidateIPv6Host(host); - } - - if (host[0] == ':') - { - // Only a port - return false; - } - - var firstNonHostCharIdx = host.AsSpan().IndexOfAnyExcept(HostChars); - if (firstNonHostCharIdx == -1) - { - // no port - return true; - } - else - { - return TryValidateHostPort(host, firstNonHostCharIdx); - } - } - - // The lead '[' was already checked - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryValidateIPv6Host(string hostText) - { - var host = hostText.AsSpan(1); - - var hostEndIdx = host.IndexOfAnyExcept(Ipv6HostChars); - if ((uint)hostEndIdx >= (uint)host.Length || // No ']'. The uint cast is there to eliminate the - // bounds check on the 'host[hostEndIdx]' access below. - host[hostEndIdx] != ']' || // We found an invalid host character - hostEndIdx < 3) // [::1] is the shortest valid IPv6 host - { - return false; - } - - // If there's nothing left, we're good. If there's more, validate it as a port. - // +2 to skip the '[' and ']' (the '[' wasn't included in hostEndIdx because we - // cut it off in the AsSpan above). - return (hostEndIdx + 2 == hostText.Length) || TryValidateHostPort(hostText, hostEndIdx + 2); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryValidateHostPort(string hostText, int offset) - { - if (hostText[offset] != ':' || hostText.Length == offset + 1) - { - // Must have at least one number after the colon if present. - return false; - } - - return hostText.AsSpan(offset + 1).IndexOfAnyExceptInRange('0', '9') < 0; - } - - private static string[] TruncateConsumedHeaderValues(string[] forwarded, int entriesConsumed) - { - var newLength = forwarded.Length - entriesConsumed; - var remaining = new string[newLength]; - Array.Copy(forwarded, remaining, newLength); - return remaining; - } -} From da77a0f6349d5fefe10e6ae473d2f9c6e394e95f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 20:13:12 -0400 Subject: [PATCH 6/7] Crossedfall test 5 --- build/Version.props | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 29 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/build/Version.props b/build/Version.props index 619f513bf4..529447aacd 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.104 + 6.15.105 5.6.0 10.13.0 0.6.0 diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index bf95511814..e06c0ff949 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -577,7 +577,6 @@ namespace Tgstation.Server.Host.Core /// The containing the to use. /// The containing the to use. /// The for the . - #pragma warning disable public void Configure( IApplicationBuilder applicationBuilder, IServerControl serverControl, @@ -619,22 +618,10 @@ namespace Tgstation.Server.Host.Core // Wrap exceptions in a 500 (ErrorMessage) response applicationBuilder.UseServerErrorHandling(); - applicationBuilder.Use((context, next) => - { - logger.LogDebug("Crossedfall Pre middleware:"); - foreach (var header in context.Request.Headers) - { - logger.LogDebug("{header}: {value}", header.Key, header.Value); - } - - return next(); - }); - // header forwarding important for OIDC var forwardedHeaderOptions = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, - AllowedHosts = null, }; forwardedHeaderOptions.KnownNetworks.Clear(); @@ -645,22 +632,6 @@ namespace Tgstation.Server.Host.Core applicationBuilder.UseForwardedHeaders(forwardedHeaderOptions); - applicationBuilder.Use((context, next) => - { - logger.LogDebug("Crossedfall Post middleware:"); - foreach (var header in context.Request.Headers) - { - logger.LogDebug("{header}: {value}", header.Key, header.Value); - } - - return next(); - }); - - /*applicationBuilder.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, - });*/ - // metrics capture applicationBuilder.UseHttpMetrics(); From 5d2f531030f10aca8ddc3f1af5f71c4a835502b1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 19 Mar 2025 20:17:56 -0400 Subject: [PATCH 7/7] Sane version bump --- build/Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Version.props b/build/Version.props index 529447aacd..acc1797a58 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ - 6.15.105 + 6.15.2 5.6.0 10.13.0 0.6.0