Skip to content

Commit d05fecb

Browse files
sander1095Aniruddh25RubenCerna2079
authored
Add authentication validation to the JSON schema (#2646)
## Why make this change? Closes #2643 The JSON schema does not contain a list of auth providers, nor does it validate the use of the `jwt` property. This results in a suboptimal developer experience. By adding this list and validation, developers have an easier time learning about all the options and can be more productive. ## What is this change? - This change modifies the JSON schema with a list of providers and validation of the providers and the `jwt` property. [StackOverflow helped me](https://stackoverflow.com/q/79557612/3013479) with the finer details of the validation. - I also added tests to validate my changes. - Migrate from `NJsonSchema` to `Newtonsoft.Json.Schema` because `NJsonSchema` [doesn't validate `anyof + const` correctly](RicoSuter/NJsonSchema#1596). `Newtonsoft.Json.Schema` does work in this case. - Changed `https` to `http` in the schema file to be spec compliant. Draft-07's original URL is http-based. - If you try to validate a document with the `https` url, it will fail because of the unknown schema URL. - This does **not** impact security. The schema should just be a placeholder for the json validator binary to know what rules to use, and it's redirected to https when you navigate to it, anyway. ## How was this tested? - [x] Integration Tests - [x] Unit Tests ## Sample Request(s) ![image](https://github.com/user-attachments/assets/3d70b56f-78e4-4f10-90ab-4f8a1356ce6c) ![image](https://github.com/user-attachments/assets/37b11c95-d443-4ee2-81c2-a54365a47cbe) ![image](https://github.com/user-attachments/assets/a04030cf-cec8-41cc-80a3-78e17f155bb6) --------- Co-authored-by: Aniruddh Munde <[email protected]> Co-authored-by: RubenCerna2079 <[email protected]>
1 parent 9bfadc4 commit d05fecb

File tree

10 files changed

+246
-32
lines changed

10 files changed

+246
-32
lines changed

docs/design/dab-validate.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,3 @@ The following types of validations are run on the config file (in the order spec
5151

5252
## Limitations
5353
1. Currently the `validate` command support is limited to single datasource config file.
54-
2. `NJsonSchema.Net` package currently has an open issue that overlooks/ ignores "if then else" conditions in json schema for attribute checks. (refer [here](https://github.com/RicoSuter/NJsonSchema/issues/1240))

schemas/dab.draft.schema.json

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://json-schema.org/draft-07/schema",
2+
"$schema": "http://json-schema.org/draft-07/schema",
33
"$id": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json",
44
"title": "Data API builder",
55
"description": "Schema for Data API builder engine",
@@ -277,8 +277,33 @@
277277
"additionalProperties": false,
278278
"properties": {
279279
"provider": {
280-
"type": "string",
281280
"description": "The name of authentication provider",
281+
"oneOf": [
282+
{
283+
"const": "StaticWebApps",
284+
"description": "Authentication provided by Azure Static Web Apps."
285+
},
286+
{
287+
"const": "EntraID",
288+
"description": "Authentication provided by Microsoft Entra ID (formerly Azure AD). Use the JWT property to configure this provider."
289+
},
290+
{
291+
"const": "Simulator",
292+
"description": "Simulated authentication for development and testing purposes."
293+
},
294+
{
295+
"const": "AppService",
296+
"description": "Authentication provided by Azure App Service."
297+
},
298+
{
299+
"const": "AzureAD",
300+
"description": "Synonymous with the EntraID value. Use the JWT property to configure this provider."
301+
},
302+
{
303+
"const": "Custom",
304+
"description": "Custom authentication provider defined by the user. Use the JWT property to configure the custom provider."
305+
}
306+
],
282307
"default": "StaticWebApps"
283308
},
284309
"jwt": {
@@ -291,9 +316,29 @@
291316
"issuer": {
292317
"type": "string"
293318
}
294-
}
319+
},
320+
"required": ["audience", "issuer"]
295321
}
296-
}
322+
},
323+
"allOf": [
324+
{
325+
"$comment": "We want the user to provide the JWT property when the provider requires it, and omit JWT when the provider does not require it.",
326+
"if": {
327+
"properties": {
328+
"provider": {
329+
"anyOf": [
330+
{ "const": "EntraID" },
331+
{ "const": "AzureAD" },
332+
{ "const": "Custom" }
333+
]
334+
}
335+
},
336+
"required": ["provider"]
337+
},
338+
"then": { "required": ["jwt"] },
339+
"else": { "properties": { "jwt": false } }
340+
}
341+
]
297342
}
298343
}
299344
},

src/Cli.Tests/ValidateConfigTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ public void TestValidateConfigFailsWithInvalidGraphQLDepthLimit(object? depthLim
151151
[DataTestMethod]
152152
[DataRow("AzureAD")]
153153
[DataRow("EntraID")]
154+
[DataRow("Custom")]
154155
public void TestMissingJwtProperties(string authScheme)
155156
{
156157
string ConfigWithJwtAuthentication = $"{{{SAMPLE_SCHEMA_DATA_SOURCE}, {RUNTIME_SECTION_JWT_AUTHENTICATION_PLACEHOLDER}, \"entities\": {{ }}}}";

src/Core/Azure.DataApiBuilder.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
<PackageReference Include="HotChocolate.Types.NodaTime" />
1818
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
1919
<PackageReference Include="Microsoft.IdentityModel.Validators" />
20-
<PackageReference Include="NJsonSchema" />
2120
<PackageReference Include="Microsoft.Azure.Cosmos" />
2221
<PackageReference Include="Microsoft.Data.SqlClient" />
2322
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
@@ -28,6 +27,7 @@
2827
<PackageReference Include="MSTest.TestFramework" />
2928
<PackageReference Include="MySqlConnector" />
3029
<PackageReference Include="Newtonsoft.Json" />
30+
<PackageReference Include="Newtonsoft.Json.Schema" />
3131
<PackageReference Include="Npgsql" />
3232
<PackageReference Include="Polly" />
3333
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" />

src/Core/Configurations/JsonConfigSchemaValidator.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
using Azure.DataApiBuilder.Config.ObjectModel;
88
using Azure.DataApiBuilder.Core.Models;
99
using Microsoft.Extensions.Logging;
10-
using NJsonSchema;
11-
using NJsonSchema.Validation;
10+
using Newtonsoft.Json.Linq;
11+
using Newtonsoft.Json.Schema;
1212

1313
namespace Azure.DataApiBuilder.Core.Configurations;
1414

@@ -38,21 +38,22 @@ public JsonConfigSchemaValidator(ILogger<JsonConfigSchemaValidator> jsonSchemaVa
3838
/// <param name="jsonData">The JSON data to validate.</param>
3939
/// <returns>A tuple containing a boolean indicating
4040
/// if the validation was successful and a collection of validation errors if there were any.</returns>
41-
public async Task<JsonSchemaValidationResult> ValidateJsonConfigWithSchemaAsync(string jsonSchema, string jsonData)
41+
public JsonSchemaValidationResult ValidateJsonConfigWithSchema(string jsonSchema, string jsonData)
4242
{
4343
try
4444
{
45-
JsonSchema schema = await JsonSchema.FromJsonAsync(jsonSchema);
46-
ICollection<ValidationError> validationErrors = schema.Validate(jsonData, SchemaType.JsonSchema);
45+
JSchema schema = JSchema.Parse(jsonSchema);
46+
JToken json = JToken.Parse(jsonData, new() { CommentHandling = CommentHandling.Ignore });
47+
bool isValid = json.IsValid(schema, out IList<ValidationError> errors);
4748

48-
if (!validationErrors.Any())
49+
if (isValid)
4950
{
5051
_logger!.LogInformation("The config satisfies the schema requirements.");
5152
return new(isValid: true, errors: null);
5253
}
5354
else
5455
{
55-
return new(isValid: false, errors: validationErrors);
56+
return new(isValid: false, errors: errors);
5657
}
5758
}
5859
catch (Exception e)

src/Core/Configurations/RuntimeConfigValidator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ public async Task<JsonSchemaValidationResult> ValidateConfigSchema(RuntimeConfig
213213
return new JsonSchemaValidationResult(isValid: false, errors: null);
214214
}
215215

216-
return await jsonConfigSchemaValidator.ValidateJsonConfigWithSchemaAsync(jsonSchema, jsonData);
216+
return jsonConfigSchemaValidator.ValidateJsonConfigWithSchema(jsonSchema, jsonData);
217217
}
218218

219219
/// <summary>

src/Core/Models/JsonSchemaValidationResult.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using NJsonSchema.Validation;
4+
using Newtonsoft.Json.Schema;
55

66
namespace Azure.DataApiBuilder.Core.Models;
77

@@ -34,7 +34,7 @@ public JsonSchemaValidationResult(bool isValid, ICollection<ValidationError>? er
3434
private static string FormatSchemaValidationErrorMessage(ICollection<ValidationError> validationErrors)
3535
{
3636
return $"> Total schema validation errors: {validationErrors.Count}\n" +
37-
string.Join("", validationErrors.Select(e => $"> {e} at " +
37+
string.Join("", validationErrors.Select(e => $"> {e.Message} at " +
3838
$"{e.LineNumber}:{e.LinePosition}\n\n"));
3939
}
4040
}

src/Directory.Packages.props

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,13 @@
5252
<PackageVersion Include="MSTest.TestFramework" Version="3.3.1" />
5353
<PackageVersion Include="MySqlConnector" Version="2.1.5" />
5454
<PackageVersion Include="Newtonsoft.Json" Version="13.0.2" />
55+
<!--
56+
We use an older version of Newtonsoft.Json.Schema because newer versions depend on Newtonsoft.Json >=13.0.3
57+
which is not (and can not be made) available in Microsoft Private Nuget Feeds
58+
-->
59+
<PackageVersion Include="Newtonsoft.Json.Schema" Version="3.0.14" />
5560
<PackageVersion Include="Npgsql" Version="8.0.3" />
5661
<PackageVersion Include="Polly" Version="7.2.3" />
57-
<PackageVersion Include="NJsonSchema" Version="10.9.0" />
5862
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
5963
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
6064
<PackageVersion Include="System.Drawing.Common" Version="8.0.3" />

0 commit comments

Comments
 (0)