Skip to content

Commit 1969387

Browse files
authored
Handle equality for SecurityScheme in SecurityRequirement.Schemes dictionary (#93)
- Create a new EqualityComparer and use that in the dictionary constructor. - This EqualityComparer only considers Reference.Id since that's what the final document actually cares about. - If there are two SecurityScheme with same Reference.Id, they should not both be added to the Schemes dictionary since that will at the end yield the same display string and violate the spec. - We also don't need to worry about equality of other downstream objects in the SecurityScheme object. - Unit tests for this equality/dictionary implementation in in SecuirtyRequirementTests. Also, note that the FullDocumentReaderTests now can compare objects directly. - This is a good release point. Upping the versions to 1.0.0-beta002
1 parent 3e1077a commit 1969387

14 files changed

+308
-164
lines changed

src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Company>Microsoft</Company>
77
<Product>Microsoft.OpenApi.Readers</Product>
88
<PackageId>Microsoft.OpenApi.Readers</PackageId>
9-
<Version>1.0.0-beta001</Version>
9+
<Version>1.0.0-beta002</Version>
1010
<Description>OpenAPI.NET Readers for JSON and YAML documents</Description>
1111
<AssemblyName>Microsoft.OpenApi.Readers</AssemblyName>
1212
<RootNamespace>Microsoft.OpenApi.Readers</RootNamespace>

src/Microsoft.OpenApi.Readers/V2/OpenApiSecurityRequirementDeserializer.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// ------------------------------------------------------------
55

66
using Microsoft.OpenApi.Models;
7-
using Microsoft.OpenApi.Readers.Interface;
87
using Microsoft.OpenApi.Readers.ParseNodes;
98

109
namespace Microsoft.OpenApi.Readers.V2
@@ -28,9 +27,13 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node)
2827
mapNode.Diagnostic,
2928
property.Name);
3029

30+
var scopes = property.Value.CreateSimpleList(n2 => n2.GetScalarValue());
31+
3132
if (scheme != null)
3233
{
33-
securityRequirement.Schemes.Add(scheme, property.Value.CreateSimpleList(n2 => n2.GetScalarValue()));
34+
securityRequirement.AddSecurityScheme(
35+
scheme,
36+
scopes);
3437
}
3538
else
3639
{
@@ -43,9 +46,9 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node)
4346
}
4447

4548
private static OpenApiSecurityScheme LoadSecuritySchemeByReference(
46-
ParsingContext context,
47-
OpenApiDiagnostic diagnostic,
48-
string schemeName)
49+
ParsingContext context,
50+
OpenApiDiagnostic diagnostic,
51+
string schemeName)
4952
{
5053
var securitySchemeObject = (OpenApiSecurityScheme)context.GetReferencedObject(
5154
diagnostic,

src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55

66
using System.Collections.Generic;
77
using System.Linq;
8-
using Microsoft.OpenApi.Exceptions;
9-
using Microsoft.OpenApi.Interfaces;
10-
using Microsoft.OpenApi.Models;
118
using Microsoft.OpenApi.Readers.ParseNodes;
129

1310
namespace Microsoft.OpenApi.Readers.V2
@@ -50,4 +47,4 @@ private static string LoadString(ParseNode node)
5047
return node.GetScalarValue();
5148
}
5249
}
53-
}
50+
}

src/Microsoft.OpenApi.Readers/V3/OpenApiSecurityRequirementDeserializer.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// ------------------------------------------------------------
55

66
using Microsoft.OpenApi.Models;
7-
using Microsoft.OpenApi.Readers.Interface;
87
using Microsoft.OpenApi.Readers.ParseNodes;
98

109
namespace Microsoft.OpenApi.Readers.V3
@@ -19,7 +18,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node)
1918
{
2019
var mapNode = node.CheckMapNode("security");
2120

22-
var obj = new OpenApiSecurityRequirement();
21+
var securityRequirement = new OpenApiSecurityRequirement();
2322

2423
foreach (var property in mapNode)
2524
{
@@ -28,10 +27,20 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node)
2827
mapNode.Diagnostic,
2928
property.Name);
3029

31-
obj.Schemes.Add(scheme, property.Value.CreateSimpleList(n2 => n2.GetScalarValue()));
30+
var scopes = property.Value.CreateSimpleList(n2 => n2.GetScalarValue());
31+
32+
if (scheme != null)
33+
{
34+
securityRequirement.AddSecurityScheme(scheme, scopes);
35+
}
36+
else
37+
{
38+
node.Diagnostic.Errors.Add(
39+
new OpenApiError(node.Context.GetLocation(), $"Scheme {property.Name} is not found"));
40+
}
3241
}
3342

34-
return obj;
43+
return securityRequirement;
3544
}
3645

3746
private static OpenApiSecurityScheme LoadSecuritySchemeByReference(
@@ -41,7 +50,7 @@ private static OpenApiSecurityScheme LoadSecuritySchemeByReference(
4150
{
4251
var securitySchemeObject = (OpenApiSecurityScheme)context.GetReferencedObject(
4352
diagnostic,
44-
ReferenceType.SecurityScheme,
53+
ReferenceType.SecurityScheme,
4554
schemeName);
4655

4756
return securitySchemeObject;

src/Microsoft.OpenApi.Readers/V3/OpenApiV3Deserializer.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55

66
using System.Collections.Generic;
77
using System.Linq;
8-
using Microsoft.OpenApi.Exceptions;
98
using Microsoft.OpenApi.Expressions;
10-
using Microsoft.OpenApi.Interfaces;
119
using Microsoft.OpenApi.Models;
1210
using Microsoft.OpenApi.Readers.ParseNodes;
1311

@@ -84,4 +82,4 @@ private static string LoadString(ParseNode node)
8482
return node.GetScalarValue();
8583
}
8684
}
87-
}
85+
}

src/Microsoft.OpenApi/Microsoft.OpenApi.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Company>Microsoft</Company>
77
<Product>Microsoft.OpenApi</Product>
88
<PackageId>Microsoft.OpenApi</PackageId>
9-
<Version>1.0.0-beta001</Version>
9+
<Version>1.0.0-beta002</Version>
1010
<Description>.NET models and JSON/YAML writers for OpenAPI specification</Description>
1111
<AssemblyName>Microsoft.OpenApi</AssemblyName>
1212
<RootNamespace>Microsoft.OpenApi</RootNamespace>

src/Microsoft.OpenApi/Models/OpenApiElementExtensions.cs

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
// ------------------------------------------------------------
55

66
using System;
7-
using System.Linq;
87
using System.Collections.Generic;
8+
using System.Linq;
99
using Microsoft.OpenApi.Any;
1010
using Microsoft.OpenApi.Exceptions;
1111
using Microsoft.OpenApi.Interfaces;
@@ -31,7 +31,7 @@ public static void AddPathItem(this OpenApiDocument document, string name, Actio
3131
throw Error.ArgumentNull(nameof(document));
3232
}
3333

34-
if (String.IsNullOrWhiteSpace(name))
34+
if (string.IsNullOrWhiteSpace(name))
3535
{
3636
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
3737
}
@@ -58,7 +58,10 @@ public static void AddPathItem(this OpenApiDocument document, string name, Actio
5858
/// <param name="pathItem">The Open API path item.</param>
5959
/// <param name="operationType">The operation type kind.</param>
6060
/// <param name="configure">The operation configuration action.</param>
61-
public static void AddOperation(this OpenApiPathItem pathItem, OperationType operationType, Action<OpenApiOperation> configure)
61+
public static void AddOperation(
62+
this OpenApiPathItem pathItem,
63+
OperationType operationType,
64+
Action<OpenApiOperation> configure)
6265
{
6366
if (pathItem == null)
6467
{
@@ -90,7 +93,7 @@ public static void AddHeader(this OpenApiResponse response, string name, Action<
9093
throw Error.ArgumentNull(nameof(response));
9194
}
9295

93-
if (String.IsNullOrWhiteSpace(name))
96+
if (string.IsNullOrWhiteSpace(name))
9497
{
9598
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
9699
}
@@ -100,7 +103,7 @@ public static void AddHeader(this OpenApiResponse response, string name, Action<
100103
throw Error.ArgumentNull(nameof(configure));
101104
}
102105

103-
OpenApiHeader header = new OpenApiHeader();
106+
var header = new OpenApiHeader();
104107
configure(header);
105108

106109
if (response.Headers == null)
@@ -124,7 +127,7 @@ public static void AddMediaType(this OpenApiResponse response, string name, Acti
124127
throw Error.ArgumentNull(nameof(response));
125128
}
126129

127-
if (String.IsNullOrWhiteSpace(name))
130+
if (string.IsNullOrWhiteSpace(name))
128131
{
129132
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
130133
}
@@ -134,7 +137,7 @@ public static void AddMediaType(this OpenApiResponse response, string name, Acti
134137
throw Error.ArgumentNull(nameof(configure));
135138
}
136139

137-
OpenApiMediaType mediaType = new OpenApiMediaType();
140+
var mediaType = new OpenApiMediaType();
138141
configure(mediaType);
139142

140143
if (response.Content == null)
@@ -158,7 +161,7 @@ public static void AddLink(this OpenApiResponse response, string name, Action<Op
158161
throw Error.ArgumentNull(nameof(response));
159162
}
160163

161-
if (String.IsNullOrWhiteSpace(name))
164+
if (string.IsNullOrWhiteSpace(name))
162165
{
163166
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
164167
}
@@ -168,7 +171,7 @@ public static void AddLink(this OpenApiResponse response, string name, Action<Op
168171
throw Error.ArgumentNull(nameof(configure));
169172
}
170173

171-
OpenApiLink link = new OpenApiLink();
174+
var link = new OpenApiLink();
172175
configure(link);
173176

174177
if (response.Links == null)
@@ -192,7 +195,7 @@ public static void AddResponse(this OpenApiOperation operation, string name, Act
192195
throw Error.ArgumentNull(nameof(operation));
193196
}
194197

195-
if (String.IsNullOrWhiteSpace(name))
198+
if (string.IsNullOrWhiteSpace(name))
196199
{
197200
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
198201
}
@@ -213,6 +216,40 @@ public static void AddResponse(this OpenApiOperation operation, string name, Act
213216
operation.Responses.Add(name, response);
214217
}
215218

219+
/// <summary>
220+
/// Add a <see cref="OpenApiSecurityScheme"/> into the <see cref="OpenApiSecurityRequirement"/>.
221+
/// </summary>
222+
/// <param name="securityRequirement">The security requirement to add the security scheme to.</param>
223+
/// <param name="securityScheme">The security scheme to add as key.</param>
224+
/// <param name="scopes">The scopes array to be used as the value.</param>
225+
public static void AddSecurityScheme(
226+
this OpenApiSecurityRequirement securityRequirement,
227+
OpenApiSecurityScheme securityScheme,
228+
List<string> scopes)
229+
{
230+
if (securityRequirement == null)
231+
{
232+
throw Error.ArgumentNull(nameof(securityRequirement));
233+
}
234+
235+
if (securityScheme == null)
236+
{
237+
throw Error.ArgumentNull(nameof(securityScheme));
238+
}
239+
240+
if (scopes == null)
241+
{
242+
throw Error.ArgumentNull(nameof(scopes));
243+
}
244+
245+
if (securityRequirement.Schemes == null)
246+
{
247+
securityRequirement.Schemes = new OpenApiSecuritySchemeDictionary();
248+
}
249+
250+
securityRequirement.Schemes.Add(securityScheme, scopes);
251+
}
252+
216253
/// <summary>
217254
/// Try find the referenced element.
218255
/// </summary>
@@ -231,7 +268,7 @@ public static IOpenApiElement Find<T>(this T reference, OpenApiDocument document
231268
return null;
232269
}
233270

234-
switch(reference.Reference.Type)
271+
switch (reference.Reference.Type)
235272
{
236273
case ReferenceType.Schema:
237274
return document.Components.Schemas?[reference.Reference.Id];
@@ -273,11 +310,13 @@ public static IOpenApiElement Find<T>(this T reference, OpenApiDocument document
273310
/// </summary>
274311
/// <typeparam name="T"><see cref="IOpenApiElement"/>.</typeparam>
275312
/// <param name="element">The referencable element.</param>
276-
/// <returns>True if the element implements <see cref="IOpenApiReferenceable"/> and pointer is not null,
277-
/// False otherwise.</returns>
313+
/// <returns>
314+
/// True if the element implements <see cref="IOpenApiReferenceable"/> and pointer is not null,
315+
/// False otherwise.
316+
/// </returns>
278317
public static bool IsReference<T>(this T element) where T : IOpenApiElement
279318
{
280-
IOpenApiReferenceable reference = element as IOpenApiReferenceable;
319+
var reference = element as IOpenApiReferenceable;
281320
return reference?.Reference != null;
282321
}
283322

@@ -308,15 +347,15 @@ public static void AddExtension<T>(this T element, string name, IOpenApiAny any)
308347

309348
private static void VerifyExtensionName(string name)
310349
{
311-
if (String.IsNullOrWhiteSpace(name))
350+
if (string.IsNullOrWhiteSpace(name))
312351
{
313352
throw Error.ArgumentNullOrWhiteSpace(nameof(name));
314353
}
315354

316355
if (!name.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix))
317356
{
318-
throw new OpenApiException(String.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name));
357+
throw new OpenApiException(string.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name));
319358
}
320359
}
321360
}
322-
}
361+
}

0 commit comments

Comments
 (0)