From f9cf5b807d71c49e5bd7e2bec97f12d3b50ca180 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 21 Jan 2026 07:41:01 -0800 Subject: [PATCH] Support mutualTLS security scheme type (#2696) feat(models): support mutualTLS security scheme * fix(writers): throw for mutualTLS in OAS 3.0 --- .../Models/OpenApiSecurityScheme.cs | 16 ++++++++++++++++ .../Models/SecuritySchemeType.cs | 7 ++++++- .../mutualTlsSecurityScheme.yaml | 2 ++ .../Models/OpenApiSecuritySchemeTests.cs | 19 +++++++++++++++++++ .../PublicApi/PublicApi.approved.txt | 2 ++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/mutualTlsSecurityScheme.yaml diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs index 7d82f3219..50c2ba545 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs @@ -115,6 +115,14 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version // openIdConnectUrl writer.WriteProperty(OpenApiConstants.OpenIdConnectUrl, OpenIdConnectUrl?.ToString()); break; + case SecuritySchemeType.MutualTLS: + // No additional properties for mutualTLS + if (version < OpenApiSpecVersion.OpenApi3_1) + { + // mutualTLS is introduced in OpenAPI 3.1 + throw new OpenApiException($"mutualTLS security scheme is only supported in OpenAPI 3.1 and later versions. Current version: {version}"); + } + break; } // extensions @@ -146,6 +154,14 @@ public virtual void SerializeAsV2(IOpenApiWriter writer) return; } + if (Type == SecuritySchemeType.MutualTLS) + { + // Bail because V2 does not support mutualTLS + writer.WriteStartObject(); + writer.WriteEndObject(); + return; + } + writer.WriteStartObject(); // type diff --git a/src/Microsoft.OpenApi/Models/SecuritySchemeType.cs b/src/Microsoft.OpenApi/Models/SecuritySchemeType.cs index 6c304597a..5640caa9a 100644 --- a/src/Microsoft.OpenApi/Models/SecuritySchemeType.cs +++ b/src/Microsoft.OpenApi/Models/SecuritySchemeType.cs @@ -26,6 +26,11 @@ public enum SecuritySchemeType /// /// Use OAuth2 with OpenId Connect URL to discover OAuth2 configuration value. /// - [Display("openIdConnect")] OpenIdConnect + [Display("openIdConnect")] OpenIdConnect, + + /// + /// Use mutual TLS authentication. + /// + [Display("mutualTLS")] MutualTLS } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/mutualTlsSecurityScheme.yaml b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/mutualTlsSecurityScheme.yaml new file mode 100644 index 000000000..72b4e9ae8 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/mutualTlsSecurityScheme.yaml @@ -0,0 +1,2 @@ +type: mutualTLS +description: Sample Description diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index 1415d62a1..0b69e9de7 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -100,6 +100,12 @@ public class OpenApiSecuritySchemeTests OpenIdConnectUrl = new("https://example.com/openIdConnect") }; + private static OpenApiSecurityScheme MutualTlsSecurityScheme => new() + { + Description = "description1", + Type = SecuritySchemeType.MutualTLS + }; + private static OpenApiSecuritySchemeReference OpenApiSecuritySchemeReference => new("sampleSecurityScheme"); private static OpenApiSecurityScheme ReferencedSecurityScheme => new() { @@ -198,6 +204,19 @@ public async Task SerializeHttpBearerSecuritySchemeAsV3JsonWorks() Assert.Equal(expected, actual); } + [Fact] + public void SerializeMutualTlsSecuritySchemeAsV3Throws() + { + // Arrange + var outputStringWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputStringWriter); + + // Act & Assert + var exception = Assert.Throws(() => MutualTlsSecurityScheme.SerializeAsV3(writer)); + Assert.Contains("mutualTLS security scheme is only supported in OpenAPI 3.1 and later versions", exception.Message); + Assert.Contains($"Current version: {OpenApiSpecVersion.OpenApi3_0}", exception.Message); + } + [Fact] public async Task SerializeOAuthSingleFlowSecuritySchemeAsV3JsonWorks() { diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index d0b8989ef..fc0b3db73 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1808,6 +1808,8 @@ namespace Microsoft.OpenApi OAuth2 = 2, [Microsoft.OpenApi.Display("openIdConnect")] OpenIdConnect = 3, + [Microsoft.OpenApi.Display("mutualTLS")] + MutualTLS = 4, } public abstract class SourceExpression : Microsoft.OpenApi.RuntimeExpression {