diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs index 4a912c0de..766b73f0d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs @@ -79,11 +79,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; @@ -103,6 +99,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 1acd8ce8c..7a47b8597 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; @@ -2387,6 +2388,56 @@ public async Task SerializeDocumentWithSelfPropertyAsV32Works() Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral()); } + [Theory] + [InlineData(OpenApiSpecVersion.OpenApi3_0)] + [InlineData(OpenApiSpecVersion.OpenApi3_1)] + [InlineData(OpenApiSpecVersion.OpenApi3_2)] + 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)); + } + [Fact] public async Task SerializeDocumentWithSelfPropertyAsV31WritesAsExtension() { 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)));