From d4ca8e7e7a008b3f2a2dc6956e2554953a00f52f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 31 Mar 2026 12:52:26 -0400 Subject: [PATCH] Merge pull request #2802 from microsoft/fix/security-requirement-ref fix/security requirement ref Signed-off-by: Vincent Biret --- .../Models/OpenApiSecurityRequirement.cs | 25 +++++-- .../Models/OpenApiDocumentTests.cs | 50 ++++++++++++++ .../Models/OpenApiSecurityRequirementTests.cs | 67 +++---------------- 3 files changed, 80 insertions(+), 62 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index fe2d78145..dfa4c5078 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -65,11 +65,7 @@ private void SerializeInternal(IOpenApiWriter writer, Action p.Key?.Target is not null)) + foreach (var securitySchemeAndScopesValuePair in this.Where(static p => CanSerializeSecurityScheme(p.Key))) { var securityScheme = securitySchemeAndScopesValuePair.Key; var scopes = securitySchemeAndScopesValuePair.Value; @@ -89,6 +85,25 @@ private void SerializeInternal(IOpenApiWriter writer, Action /// Serialize to Open Api v2.0 /// diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 8480269d2..10b1f6016 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Text.Json.Nodes; using System.Threading.Tasks; using VerifyXunit; using Xunit; @@ -2358,5 +2359,54 @@ public async Task SerializeDocWithEmptyOperationSecurityWorks() Assert.NotNull(actualOperation.Security); Assert.Empty(actualOperation.Security); } + + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi3_1)] + public async Task SerializeDocumentWithSecurityRequirementAsJsonWorks(OpenApiSpecVersion openApiSpecVersion) + { + // Arrange + var doc = new OpenApiDocument + { + Info = new OpenApiInfo { Title = "Test", Version = "1.0" }, + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary(StringComparer.Ordinal) + { + ["Bearer"] = new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "Bearer", + BearerFormat = "JWT", + }, + }, + }, + }; + + doc.Security = + [ + new OpenApiSecurityRequirement + { + { new OpenApiSecuritySchemeReference("Bearer", doc), [] }, + }, + ]; + + var expected = + """ + [ + { + "Bearer": [] + } + ] + """; + + // Act + var actual = await doc.SerializeAsJsonAsync(openApiSpecVersion); + + // Assert + var actualSecurity = JsonNode.Parse(actual)?["security"]; + Assert.NotNull(actualSecurity); + Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), actualSecurity)); + } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs index 4ae9aedfd..29f5af3c6 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs @@ -130,35 +130,10 @@ public async Task SerializeSecurityRequirementAsV3JsonWorksAsync(bool produceTer await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput); } - [Fact] - public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV3JsonWorks() - { - // Arrange - var expected = - """ - { - "scheme1": [ - "scope1", - "scope2", - "scope3" - ], - "scheme2": [ - "scope4", - "scope5" - ], - "scheme3": [ ] - } - """; - - // Act - var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); - - // Assert - Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); - } - - [Fact] - public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2JsonWorks() + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi2_0)] + public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsJsonWorks(OpenApiSpecVersion openApiSpecVersion) { // Arrange var expected = @@ -178,37 +153,16 @@ public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2Js """; // Act - var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); + var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion); // Assert Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); } - [Fact] - public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV3JsonShouldSkipUnserializableKeyValuePair() - { - // Arrange - var expected = - """ - { - "scheme1": [ - "scope1", - "scope2", - "scope3" - ], - "scheme3": [ ] - } - """; - - // Act - var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0); - - // Assert - Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual))); - } - - [Fact] - public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2JsonShouldSkipUnserializableKeyValuePair() + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi2_0)] + public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsJsonShouldSkipUnserializableKeyValuePair(OpenApiSpecVersion openApiSpecVersion) { // Arrange var expected = @@ -224,8 +178,7 @@ public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2 """; // Act - var actual = - await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0); + var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion); // Assert Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));