From a6d5f599bb18425cfb13575480b84ecb87ec75d4 Mon Sep 17 00:00:00 2001 From: Waldek Mastykarz Date: Wed, 21 Oct 2026 15:55:31 +0200 Subject: [PATCH] Allow ':' in jwt create --claims values Split each claim only on the first ':' so values such as URLs are accepted. Closes #1960 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a88a09b8-015b-4693-be80-e91b9632ece8 --- DevProxy.Tests/JwtCommandTests.cs | 60 +++++++++++++++++++++++++++++++ DevProxy/Commands/JwtCommand.cs | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 DevProxy.Tests/JwtCommandTests.cs diff --git a/DevProxy.Tests/JwtCommandTests.cs b/DevProxy.Tests/JwtCommandTests.cs new file mode 100644 index 000000000..cd88a3916 --- /dev/null +++ b/DevProxy.Tests/JwtCommandTests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using DevProxy.Commands; +using System.CommandLine; + +using Xunit; + +namespace DevProxy.Tests; + +public class JwtCommandTests +{ + private static Dictionary? ParseClaims(params string[] claimArgs) + { + var jwtCommand = new JwtCommand(); + var createCommand = jwtCommand.Subcommands.Single(c => c.Name == "create"); + var claimsOption = (Option>)createCommand.Options.Single(o => o.Name == "--claims"); + + var args = new List { "create" }; + foreach (var claim in claimArgs) + { + args.Add("--claims"); + args.Add(claim); + } + + var parseResult = jwtCommand.Parse(args); + Assert.Empty(parseResult.Errors); + return parseResult.GetValue(claimsOption); + } + + [Fact] + public void Claims_SimpleValue_IsParsed() + { + var claims = ParseClaims("dept:eng"); + + Assert.NotNull(claims); + Assert.Equal("eng", claims["dept"]); + } + + [Fact] + public void Claims_ValueContainingColon_SplitsOnFirstColonOnly() + { + var claims = ParseClaims("iss2:https://example.com", "time:12:30:00"); + + Assert.NotNull(claims); + Assert.Equal("https://example.com", claims["iss2"]); + Assert.Equal("12:30:00", claims["time"]); + } + + [Fact] + public void Claims_MissingSeparator_ReportsError() + { + var jwtCommand = new JwtCommand(); + + var parseResult = jwtCommand.Parse(["create", "--claims", "dept"]); + + Assert.Contains(parseResult.Errors, e => e.Message.Contains("Invalid claim format", StringComparison.Ordinal)); + } +} diff --git a/DevProxy/Commands/JwtCommand.cs b/DevProxy/Commands/JwtCommand.cs index 90c39a602..96f03d605 100644 --- a/DevProxy/Commands/JwtCommand.cs +++ b/DevProxy/Commands/JwtCommand.cs @@ -56,7 +56,7 @@ private void ConfigureCommand() var claims = new Dictionary(); foreach (var token in result.Tokens) { - var claim = token.Value.Split(":"); + var claim = token.Value.Split(':', 2); if (claim.Length != 2) {