From 94a7b7144fa7d8b1624a8d992cb77389c01e3b41 Mon Sep 17 00:00:00 2001 From: Klaus Fischer <klaus.fischer@eloware.com> Date: Mon, 31 Oct 2022 08:12:20 +0100 Subject: [PATCH] Added simple json schema for data verification --- FitConnect/Services/Models/v1/Api/Problems.cs | 15 +++++-- FitConnect/Subscriber.cs | 39 +++++++++++++++---- simple_schema.json | 21 ++++++++++ 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 simple_schema.json diff --git a/FitConnect/Services/Models/v1/Api/Problems.cs b/FitConnect/Services/Models/v1/Api/Problems.cs index 713a1acc..2e67824c 100644 --- a/FitConnect/Services/Models/v1/Api/Problems.cs +++ b/FitConnect/Services/Models/v1/Api/Problems.cs @@ -38,6 +38,9 @@ public class Problems { public const string TitleUnsupportedSchema = "Metadatenschema nicht unterstützt"; public const string DetailUnsupportedSchema = "Die angegebene Metadatenschema-URI ('$schema') ist keines der unterstützten Metadatenschemas."; + + public const string TitleUnsupportedDataSchema = "Fachdatenschema nicht unterstützt"; + public const string DetailUnsupportedDataSchema = "Das angegebene Fachdatenschema wird nicht unterstützt."; // @formatter:on public enum ProblemTypeEnum { @@ -53,7 +56,8 @@ public class Problems { ServiceMismatch, SchemaViolation, SyntaxViolation, - UnsupportedSchema, + UnsupportedDataSchema, + UnsupportedMetaSchema, UnsupportedService } @@ -128,7 +132,12 @@ public class Problems { title = TitleSyntaxViolation; instance = "metadata"; break; - case ProblemTypeEnum.UnsupportedSchema: + case ProblemTypeEnum.UnsupportedDataSchema: + type += "unsupported-schema"; + title = TitleUnsupportedDataSchema; + instance = "metadata"; + break; + case ProblemTypeEnum.UnsupportedMetaSchema: type += "unsupported-schema"; title = TitleUnsupportedSchema; instance = "metadata"; @@ -221,7 +230,7 @@ public class Problems { ); public static readonly Problems UnsupportedSchema = new Problems( - ProblemTypeEnum.UnsupportedSchema, + ProblemTypeEnum.UnsupportedMetaSchema, "Metadatenschema nicht unterstützt", "Die angegebene Metadatenschema-URI ('$schema') ist keines der unterstützten Metadatenschemas.", ProblemInstanceEnum.Metadata diff --git a/FitConnect/Subscriber.cs b/FitConnect/Subscriber.cs index 4cefc183..23b58c96 100644 --- a/FitConnect/Subscriber.cs +++ b/FitConnect/Subscriber.cs @@ -10,7 +10,9 @@ using IdentityModel; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using NJsonSchema; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using JsonSchema = NJsonSchema.JsonSchema; using Metadata = FitConnect.Models.Api.Metadata.Metadata; using SecurityEventToken = FitConnect.Models.SecurityEventToken; @@ -121,7 +123,7 @@ public class Subscriber : FitConnectClient, } catch (Exception e) { // SuccessCriteria:3.5 - var problem = new Problems(Problems.ProblemTypeEnum.UnsupportedSchema, + var problem = new Problems(Problems.ProblemTypeEnum.UnsupportedMetaSchema, Problems.DetailUnsupportedSchema); RejectSubmission(problem); throw new SecurityEventException(problem, e); @@ -177,11 +179,16 @@ public class Subscriber : FitConnectClient, // SuccessCriteria:3.11 - // TODO get data schema for data - string? dataSchema = null; - if (dataSchema != null) { - if (destinationService.SubmissionSchemas != null && destinationService.SubmissionSchemas.Select(s => s.SchemaUri) + // TODO No test for data schema implemented, missing schema url + var dataSchema = GetSchemaUrlFromJson(submission.Data); + if (dataSchema == null) { + Logger?.LogWarning("No data schema found for submission {SubmissionId}", submissionId); + } + else { + if (destinationService.SubmissionSchemas != null && destinationService.SubmissionSchemas + .Select(s => s.SchemaUri) .Contains(dataSchema)) { + CheckDataSchema(dataSchema, submission); } } @@ -198,6 +205,24 @@ public class Subscriber : FitConnectClient, return this; } + private string? GetSchemaUrlFromJson(string? jsonString) + => jsonString == null + ? null + : (JsonConvert.DeserializeObject(jsonString) as JObject)?["$schema"]?.ToString(); + + private void CheckDataSchema(string dataSchema, Submission submission) { + var dataSchemaObject = JsonSchema.FromUrlAsync(dataSchema).Result; + var jSchema = JSchema.Parse(dataSchemaObject.ToJson()); + var isValidSchemaData = JObject.Parse(submission.Data!).IsValid(jSchema); + + if (!isValidSchemaData) { + var problem = new Problems(Problems.ProblemTypeEnum.UnsupportedDataSchema, + Problems.DetailUnsupportedDataSchema); + RejectSubmission(submission, problem); + throw new SecurityEventException(problem); + } + } + #region Check Submission and Reject if needed private void VerifyDataHash(Submission submission, string dataString) { @@ -223,7 +248,7 @@ public class Subscriber : FitConnectClient, // SuccessCriteria:3.6 RejectSubmission(submission, - new Problems(Problems.ProblemTypeEnum.UnsupportedSchema, + new Problems(Problems.ProblemTypeEnum.UnsupportedMetaSchema, Problems.DetailUnsupportedSchema)); throw new Exception("Metadata validation failed"); } diff --git a/simple_schema.json b/simple_schema.json new file mode 100644 index 00000000..bb3d7816 --- /dev/null +++ b/simple_schema.json @@ -0,0 +1,21 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} \ No newline at end of file -- GitLab