Skip to content

Commit 3b51b55

Browse files
committed
Create CircuitSecret
Fixes: #13012 This change introduces a circuit id 'secret' as the concept that's used when doing handshaking between the client and the server, and makes CircuitId (visible to user-code) a separate concept (not a secret, can't be used to open a connection). The scope of this grew once I realized that we probably shouldn't be logging Circuit Secret in so many places, we should be logging CircuitId as the piece of data we use for correlation, and try to keep the secret out of logs except where really necessary (and with trace level). I ended up creating a new type to represent the combination of the circuit id and secret and prevent accidental misuse, and then chased down all of the build errors. As an extra detail, the circuit id is part of the data-protected payload that's used as the secret. This way we can always get the id back from the secret without any external storage.
1 parent 7f05415 commit 3b51b55

16 files changed

+403
-254
lines changed

src/Components/Server/src/CircuitDisconnectMiddleware.cs

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,65 +39,71 @@ public async Task Invoke(HttpContext context)
3939
return;
4040
}
4141

42-
var (hasCircuitId, circuitId) = await TryGetCircuitIdAsync(context);
43-
if (!hasCircuitId)
42+
var circuitId = await GetCircuitIdAsync(context);
43+
if (circuitId is null)
4444
{
4545
context.Response.StatusCode = StatusCodes.Status400BadRequest;
4646
return;
4747
}
4848

49-
await TerminateCircuitGracefully(circuitId);
49+
await TerminateCircuitGracefully(circuitId.Value);
5050

5151
context.Response.StatusCode = StatusCodes.Status200OK;
5252
}
5353

54-
private async Task<(bool, string)> TryGetCircuitIdAsync(HttpContext context)
54+
private async Task<CircuitId?> GetCircuitIdAsync(HttpContext context)
5555
{
5656
try
5757
{
5858
if (!context.Request.HasFormContentType)
5959
{
60-
return (false, null);
60+
return default;
6161
}
6262

6363
var form = await context.Request.ReadFormAsync();
64-
if (!form.TryGetValue(CircuitIdKey, out var circuitId) || !CircuitIdFactory.ValidateCircuitId(circuitId))
64+
if (!form.TryGetValue(CircuitIdKey, out var text))
6565
{
66-
return (false, null);
66+
return default;
6767
}
6868

69-
return (true, circuitId);
69+
if (!CircuitIdFactory.TryParseCircuitId(text, out var circuitId))
70+
{
71+
Log.InvalidCircuitId(Logger, text);
72+
return default;
73+
}
74+
75+
return circuitId;
7076
}
7177
catch
7278
{
73-
return (false, null);
79+
return default;
7480
}
7581
}
7682

77-
private async Task TerminateCircuitGracefully(string circuitId)
83+
private async Task TerminateCircuitGracefully(CircuitId circuitId)
7884
{
79-
try
80-
{
81-
await Registry.TerminateAsync(circuitId);
82-
Log.CircuitTerminatedGracefully(Logger, circuitId);
83-
}
84-
catch (Exception e)
85-
{
86-
Log.UnhandledExceptionInCircuit(Logger, circuitId, e);
87-
}
85+
// We don't expect TerminateAsync to throw.
86+
Log.CircuitTerminatingGracefully(Logger, circuitId);
87+
await Registry.TerminateAsync(circuitId);
88+
Log.CircuitTerminatedGracefully(Logger, circuitId);
8889
}
8990

9091
private class Log
9192
{
92-
private static readonly Action<ILogger, string, Exception> _circuitTerminatedGracefully =
93-
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(1, "CircuitTerminatedGracefully"), "Circuit '{CircuitId}' terminated gracefully");
93+
private static readonly Action<ILogger, CircuitId, Exception> _circuitTerminatingGracefully =
94+
LoggerMessage.Define<CircuitId>(LogLevel.Debug, new EventId(1, "CircuitTerminatingGracefully"), "Circuit with id '{CircuitId}' terminating gracefully.");
95+
96+
private static readonly Action<ILogger, CircuitId, Exception> _circuitTerminatedGracefully =
97+
LoggerMessage.Define<CircuitId>(LogLevel.Debug, new EventId(2, "CircuitTerminatedGracefully"), "Circuit with id '{CircuitId}' terminated gracefully.");
98+
99+
private static readonly Action<ILogger, string, Exception> _invalidCircuitId =
100+
LoggerMessage.Define<string>(LogLevel.Debug, new EventId(3, "InvalidCircuitId"), "CircuitDisconnectMiddleware recieved an invalid circuit id '{CircuitIdSecret}'.");
94101

95-
private static readonly Action<ILogger, string, Exception> _unhandledExceptionInCircuit =
96-
LoggerMessage.Define<string>(LogLevel.Warning, new EventId(2, "UnhandledExceptionInCircuit"), "Unhandled exception in circuit {CircuitId} while terminating gracefully.");
102+
public static void CircuitTerminatingGracefully(ILogger logger, CircuitId circuitId) => _circuitTerminatingGracefully(logger, circuitId, null);
97103

98-
public static void CircuitTerminatedGracefully(ILogger logger, string circuitId) => _circuitTerminatedGracefully(logger, circuitId, null);
104+
public static void CircuitTerminatedGracefully(ILogger logger, CircuitId circuitId) => _circuitTerminatedGracefully(logger, circuitId, null);
99105

100-
public static void UnhandledExceptionInCircuit(ILogger logger, string circuitId, Exception exception) => _unhandledExceptionInCircuit(logger, circuitId, exception);
106+
public static void InvalidCircuitId(ILogger logger, string circuitSecret) => _invalidCircuitId(logger, circuitSecret, null);
101107
}
102108
}
103109
}

src/Components/Server/src/Circuits/Circuit.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ internal Circuit(CircuitHost circuitHost)
1818
/// <summary>
1919
/// Gets the identifier for the <see cref="Circuit"/>.
2020
/// </summary>
21-
public string Id => _circuitHost.CircuitId;
21+
public string Id => _circuitHost.CircuitId.Id;
2222
}
2323
}

0 commit comments

Comments
 (0)