Skip to content

Commit 0945eec

Browse files
authored
fix: security requirement reference serialization
Merge pull request #2802 from microsoft/fix/security-requirement-ref
2 parents e18a5b0 + d4ca8e7 commit 0945eec

File tree

3 files changed

+80
-62
lines changed

3 files changed

+80
-62
lines changed

src/Microsoft.OpenApi/Models/OpenApiSecurityRequirement.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,7 @@ private void SerializeInternal(IOpenApiWriter writer, Action<IOpenApiWriter, Ope
6565

6666
writer.WriteStartObject();
6767

68-
// Reaching this point means the reference to a specific OpenApiSecurityScheme fails.
69-
// We are not able to serialize this SecurityScheme/Scopes key value pair since we do not know what
70-
// string to output.
71-
72-
foreach (var securitySchemeAndScopesValuePair in this.Where(static p => p.Key?.Target is not null))
68+
foreach (var securitySchemeAndScopesValuePair in this.Where(static p => CanSerializeSecurityScheme(p.Key)))
7369
{
7470
var securityScheme = securitySchemeAndScopesValuePair.Key;
7571
var scopes = securitySchemeAndScopesValuePair.Value;
@@ -89,6 +85,25 @@ private void SerializeInternal(IOpenApiWriter writer, Action<IOpenApiWriter, Ope
8985
writer.WriteEndObject();
9086
}
9187

88+
private static bool CanSerializeSecurityScheme(OpenApiSecuritySchemeReference? securityScheme)
89+
{
90+
if (securityScheme is null)
91+
{
92+
return false;
93+
}
94+
95+
if (securityScheme.Target is not null)
96+
{
97+
return true;
98+
}
99+
100+
var schemeId = securityScheme.Reference?.Id;
101+
var securitySchemes = securityScheme.Reference?.HostDocument?.Components?.SecuritySchemes;
102+
return !string.IsNullOrEmpty(schemeId)
103+
&& securitySchemes is not null
104+
&& securitySchemes.ContainsKey(schemeId!);
105+
}
106+
92107
/// <summary>
93108
/// Serialize <see cref="OpenApiSecurityRequirement"/> to Open Api v2.0
94109
/// </summary>

test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.IO;
1010
using System.Linq;
1111
using System.Net.Http;
12+
using System.Text.Json.Nodes;
1213
using System.Threading.Tasks;
1314
using VerifyXunit;
1415
using Xunit;
@@ -2358,5 +2359,54 @@ public async Task SerializeDocWithEmptyOperationSecurityWorks()
23582359
Assert.NotNull(actualOperation.Security);
23592360
Assert.Empty(actualOperation.Security);
23602361
}
2362+
2363+
[Theory]
2364+
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
2365+
[InlineData(OpenApiSpecVersion.OpenApi3_1)]
2366+
public async Task SerializeDocumentWithSecurityRequirementAsJsonWorks(OpenApiSpecVersion openApiSpecVersion)
2367+
{
2368+
// Arrange
2369+
var doc = new OpenApiDocument
2370+
{
2371+
Info = new OpenApiInfo { Title = "Test", Version = "1.0" },
2372+
Components = new OpenApiComponents
2373+
{
2374+
SecuritySchemes = new Dictionary<string, IOpenApiSecurityScheme>(StringComparer.Ordinal)
2375+
{
2376+
["Bearer"] = new OpenApiSecurityScheme
2377+
{
2378+
Type = SecuritySchemeType.Http,
2379+
Scheme = "Bearer",
2380+
BearerFormat = "JWT",
2381+
},
2382+
},
2383+
},
2384+
};
2385+
2386+
doc.Security =
2387+
[
2388+
new OpenApiSecurityRequirement
2389+
{
2390+
{ new OpenApiSecuritySchemeReference("Bearer", doc), [] },
2391+
},
2392+
];
2393+
2394+
var expected =
2395+
"""
2396+
[
2397+
{
2398+
"Bearer": []
2399+
}
2400+
]
2401+
""";
2402+
2403+
// Act
2404+
var actual = await doc.SerializeAsJsonAsync(openApiSpecVersion);
2405+
2406+
// Assert
2407+
var actualSecurity = JsonNode.Parse(actual)?["security"];
2408+
Assert.NotNull(actualSecurity);
2409+
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), actualSecurity));
2410+
}
23612411
}
23622412
}

test/Microsoft.OpenApi.Tests/Models/OpenApiSecurityRequirementTests.cs

Lines changed: 10 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -130,35 +130,10 @@ public async Task SerializeSecurityRequirementAsV3JsonWorksAsync(bool produceTer
130130
await Verifier.Verify(outputStringWriter).UseParameters(produceTerseOutput);
131131
}
132132

133-
[Fact]
134-
public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV3JsonWorks()
135-
{
136-
// Arrange
137-
var expected =
138-
"""
139-
{
140-
"scheme1": [
141-
"scope1",
142-
"scope2",
143-
"scope3"
144-
],
145-
"scheme2": [
146-
"scope4",
147-
"scope5"
148-
],
149-
"scheme3": [ ]
150-
}
151-
""";
152-
153-
// Act
154-
var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0);
155-
156-
// Assert
157-
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
158-
}
159-
160-
[Fact]
161-
public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2JsonWorks()
133+
[Theory]
134+
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
135+
[InlineData(OpenApiSpecVersion.OpenApi2_0)]
136+
public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsJsonWorks(OpenApiSpecVersion openApiSpecVersion)
162137
{
163138
// Arrange
164139
var expected =
@@ -178,37 +153,16 @@ public async Task SerializeSecurityRequirementWithReferencedSecuritySchemeAsV2Js
178153
""";
179154

180155
// Act
181-
var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0);
156+
var actual = await SecurityRequirementWithReferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion);
182157

183158
// Assert
184159
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
185160
}
186161

187-
[Fact]
188-
public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV3JsonShouldSkipUnserializableKeyValuePair()
189-
{
190-
// Arrange
191-
var expected =
192-
"""
193-
{
194-
"scheme1": [
195-
"scope1",
196-
"scope2",
197-
"scope3"
198-
],
199-
"scheme3": [ ]
200-
}
201-
""";
202-
203-
// Act
204-
var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_0);
205-
206-
// Assert
207-
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
208-
}
209-
210-
[Fact]
211-
public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2JsonShouldSkipUnserializableKeyValuePair()
162+
[Theory]
163+
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
164+
[InlineData(OpenApiSpecVersion.OpenApi2_0)]
165+
public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsJsonShouldSkipUnserializableKeyValuePair(OpenApiSpecVersion openApiSpecVersion)
212166
{
213167
// Arrange
214168
var expected =
@@ -224,8 +178,7 @@ public async Task SerializeSecurityRequirementWithUnreferencedSecuritySchemeAsV2
224178
""";
225179

226180
// Act
227-
var actual =
228-
await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi2_0);
181+
var actual = await SecurityRequirementWithUnreferencedSecurityScheme.SerializeAsJsonAsync(openApiSpecVersion);
229182

230183
// Assert
231184
Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));

0 commit comments

Comments
 (0)