diff --git a/.gitignore b/.gitignore index b0040ae..74c478e 100644 --- a/.gitignore +++ b/.gitignore @@ -371,3 +371,4 @@ FodyWeavers.xsd **/Identity.db **/Identity.db-shm **/Identity.db-wal +**/http-client.env.json diff --git a/Poort8.Dataspace.API.Tests/OpenApiDefinitionTests.cs b/Poort8.Dataspace.API.Tests/OpenApiDefinitionTests.cs index 0c6503d..61decc8 100644 --- a/Poort8.Dataspace.API.Tests/OpenApiDefinitionTests.cs +++ b/Poort8.Dataspace.API.Tests/OpenApiDefinitionTests.cs @@ -2,9 +2,9 @@ using Microsoft.Extensions.DependencyInjection; using NSwag.Generation; using Snapshooter.Xunit; +using System.Text.Json; using System.Text.Json.Nodes; -using FluentAssertions.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json.Serialization; namespace Poort8.Dataspace.API.Tests; @@ -19,18 +19,16 @@ public async Task TestApiDefinitionChangedUsingDoc() var jsonNode = JsonNode.Parse(apiDefinition.ToJson()); var orderedApiDefinition = OrderApiDefinition(jsonNode!); - try + var serializerOptions = new JsonSerializerOptions { - Snapshot.Match(orderedApiDefinition); - } - catch (Exception) - { - //On GitHub workflow Snapshot.Match fails, so try again with FluentAssertions - var snapshot = await File.ReadAllTextAsync("__snapshots__/OpenApiDefinitionTests.TestApiDefinitionChangedUsingDoc.snap"); - var snapshotDoc = JToken.Parse(snapshot); - var apiDefinitionDoc = JToken.Parse(apiDefinition.ToJson()); - apiDefinitionDoc.Should().BeEquivalentTo(snapshotDoc); - } + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + var jsonString = orderedApiDefinition!.ToJsonString(serializerOptions); + + Snapshot.Match(jsonString + .Replace("\r\n", "\n") + .Replace("\\r\\n", "\\n")); } private static JsonNode? OrderApiDefinition(JsonNode? jsonNode) diff --git a/Poort8.Dataspace.API.Tests/Poort8.Dataspace.API.Tests.csproj b/Poort8.Dataspace.API.Tests/Poort8.Dataspace.API.Tests.csproj index 315b5e3..4c321c9 100644 --- a/Poort8.Dataspace.API.Tests/Poort8.Dataspace.API.Tests.csproj +++ b/Poort8.Dataspace.API.Tests/Poort8.Dataspace.API.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable true @@ -27,12 +27,12 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Poort8.Dataspace.API.Tests/__snapshots__/OpenApiDefinitionTests.TestApiDefinitionChangedUsingDoc.snap b/Poort8.Dataspace.API.Tests/__snapshots__/OpenApiDefinitionTests.TestApiDefinitionChangedUsingDoc.snap index 9f84851..8f707bc 100644 --- a/Poort8.Dataspace.API.Tests/__snapshots__/OpenApiDefinitionTests.TestApiDefinitionChangedUsingDoc.snap +++ b/Poort8.Dataspace.API.Tests/__snapshots__/OpenApiDefinitionTests.TestApiDefinitionChangedUsingDoc.snap @@ -1,3146 +1,1732 @@ { "components": { "schemas": { - "MicrosoftAspNetCoreAuthenticationBearerTokenAccessTokenResponse": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAROrganizationsGetOrganizationByIdEmployeeDto": { + "additionalProperties": false, "properties": { - "accessToken": { - "type": { - "Options": null - } + "email": { + "type": "string" }, - "expiresIn": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "employeeId": { + "type": "string" }, - "refreshToken": { - "type": { - "Options": null - } + "familyName": { + "type": "string" }, - "tokenType": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } - }, - "MicrosoftAspNetCoreHttpHttpValidationProblemDetails": { - "allOf": [ - { - "$ref": { - "Options": null - } + "givenName": { + "type": "string" }, - { - "additionalProperties": { - "nullable": { - "Options": null - } - }, - "properties": { - "errors": { - "additionalProperties": { - "items": { - "type": { - "Options": null - } - }, - "type": { - "Options": null - } - }, - "type": { - "Options": null - } - } + "properties": { + "items": { + "$ref": "#/components/schemas/Poort8DataspaceAPIAROrganizationsGetOrganizationByIdEmployeePropertyDto" }, - "type": { - "Options": null - } - } - ] - }, - "MicrosoftAspNetCoreIdentityDataForgotPasswordRequest": { - "additionalProperties": { - "Options": null - }, - "properties": { - "email": { - "type": { - "Options": null - } + "type": "array" + }, + "telephone": { + "type": "string" + }, + "useCase": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataInfoRequest": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAROrganizationsGetOrganizationByIdEmployeePropertyDto": { + "additionalProperties": false, "properties": { - "newEmail": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "isIdentifier": { + "type": "boolean" }, - "newPassword": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "key": { + "type": "string" }, - "oldPassword": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "value": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataInfoResponse": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAROrganizationsGetOrganizationByIdOrganizationPropertyDto": { + "additionalProperties": false, "properties": { - "email": { - "type": { - "Options": null - } + "isIdentifier": { + "type": "boolean" }, - "isEmailConfirmed": { - "type": { - "Options": null - } + "key": { + "type": "string" + }, + "value": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataLoginRequest": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAROrganizationsGetOrganizationByIdResponse": { + "additionalProperties": false, "properties": { - "email": { - "type": { - "Options": null - } + "employees": { + "items": { + "$ref": "#/components/schemas/Poort8DataspaceAPIAROrganizationsGetOrganizationByIdEmployeeDto" + }, + "type": "array" }, - "password": { - "type": { - "Options": null - } + "identifier": { + "type": "string" }, - "twoFactorCode": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "invoicingContact": { + "type": "string" + }, + "name": { + "type": "string" }, - "twoFactorRecoveryCode": { - "nullable": { - "Options": null + "properties": { + "items": { + "$ref": "#/components/schemas/Poort8DataspaceAPIAROrganizationsGetOrganizationByIdOrganizationPropertyDto" }, - "type": { - "Options": null - } + "type": "array" + }, + "representative": { + "type": "string" + }, + "url": { + "type": "string" + }, + "useCase": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataRefreshRequest": { - "additionalProperties": { - "Options": null - }, - "properties": { - "refreshToken": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } + "Poort8DataspaceAPIAuthorizationEnforceRequest": { + "additionalProperties": false, + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataRegisterRequest": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAuthorizationEnforceResponse": { + "additionalProperties": false, "properties": { - "email": { - "type": { - "Options": null - } - }, - "password": { - "type": { - "Options": null - } + "allowed": { + "type": "boolean" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataResendConfirmationEmailRequest": { - "additionalProperties": { - "Options": null - }, - "properties": { - "email": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } + "Poort8DataspaceAPIAuthorizationExplainedEnforceRequest": { + "additionalProperties": false, + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataResetPasswordRequest": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIAuthorizationExplainedEnforceResponse": { + "additionalProperties": false, "properties": { - "email": { - "type": { - "Options": null - } - }, - "newPassword": { - "type": { - "Options": null - } + "allowed": { + "type": "boolean" }, - "resetCode": { - "type": { - "Options": null - } + "explainPolicies": { + "items": { + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy" + }, + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataTwoFactorRequest": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationEmployeePropertyDto": { + "additionalProperties": false, "properties": { - "enable": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "forgetMachine": { - "type": { - "Options": null - } - }, - "resetRecoveryCodes": { - "type": { - "Options": null - } + "isIdentifier": { + "type": "boolean" }, - "resetSharedKey": { - "type": { - "Options": null - } + "key": { + "type": "string" }, - "twoFactorCode": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "value": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreIdentityDataTwoFactorResponse": { - "additionalProperties": { - "Options": null - }, + "Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationRequest": { + "additionalProperties": false, "properties": { - "isMachineRemembered": { - "type": { - "Options": null - } + "email": { + "type": "string" }, - "isTwoFactorEnabled": { - "type": { - "Options": null - } + "employeeId": { + "type": "string" + }, + "familyName": { + "type": "string" }, - "recoveryCodes": { + "givenName": { + "type": "string" + }, + "properties": { "items": { - "type": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationEmployeePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, - "recoveryCodesLeft": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "telephone": { + "type": "string" }, - "sharedKey": { - "type": { - "Options": null - } + "useCase": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "MicrosoftAspNetCoreMvcProblemDetails": { - "additionalProperties": { - "nullable": { - "Options": null - } - }, + "Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationResponse": { + "additionalProperties": false, "properties": { - "detail": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "instance": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "email": { + "type": "string" }, - "status": { - "format": { - "Options": null - }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "employeeId": { + "type": "string" }, - "title": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "familyName": { + "type": "string" }, - "type": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAPIAuthorizationEnforceRequest": { - "additionalProperties": { - "Options": null - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAPIAuthorizationEnforceResponse": { - "additionalProperties": { - "Options": null - }, - "properties": { - "allowed": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAPIAuthorizationExplainedEnforceRequest": { - "additionalProperties": { - "Options": null - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAPIAuthorizationExplainedEnforceResponse": { - "additionalProperties": { - "Options": null - }, - "properties": { - "allowed": { - "type": { - "Options": null - } + "givenName": { + "type": "string" }, - "explainPolicies": { + "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationEmployeePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" + }, + "telephone": { + "type": "string" + }, + "useCase": { + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAdditionalDetailsDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "capabilitiesUrl": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "companyEmail": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "companyPhone": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "countriesOfOperation": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" }, "description": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "logoUrl": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "publiclyPublishable": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "boolean" }, "sectors": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" }, "tags": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "websiteUrl": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAdherenceDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "status": { - "type": { - "Options": null - } + "type": "string" }, "validFrom": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" }, "validUntil": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAgreementDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "agreementId": { - "type": { - "Options": null - } + "type": "string" }, "compliancyVerified": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "boolean" }, "contractFile": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "byte", + "type": "string" }, "dataspaceId": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "dateOfExpiry": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" }, "dateOfSigning": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" }, "framework": { - "type": { - "Options": null - } + "type": "string" }, "hashOfSignedContract": { - "type": { - "Options": null - } + "type": "string" }, "status": { - "type": { - "Options": null - } + "type": "string" }, "title": { - "type": { - "Options": null - } + "type": "string" }, "type": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAuthorizationRegistryDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "authorizationRegistryId": { - "type": { - "Options": null - } + "type": "string" }, "authorizationRegistryOrganizationId": { - "type": { - "Options": null - } + "type": "string" }, "authorizationRegistryUrl": { - "type": { - "Options": null - } + "type": "string" }, "dataspaceId": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdCertificateDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "certificateFile": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "byte", + "type": "string" }, "certificateId": { - "type": { - "Options": null - } + "type": "string" }, "enabledFrom": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdOrganizationPropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdOrganizationRoleDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "compliancyVerified": { - "type": { - "Options": null - } + "type": "boolean" }, "endDate": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" }, "legalAdherence": { - "type": { - "Options": null - } + "type": "boolean" }, "loA": { - "type": { - "Options": null - } + "type": "string" }, "role": { - "type": { - "Options": null - } + "type": "string" }, "roleId": { - "type": { - "Options": null - } + "type": "string" }, "startDate": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "date", + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "additionalDetails": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAdditionalDetailsDto" }, "adherence": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAdherenceDto" }, "agreements": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAgreementDto" }, - "type": { - "Options": null - } + "type": "array" }, "authorizationRegistries": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdAuthorizationRegistryDto" }, - "type": { - "Options": null - } + "type": "array" }, "certificates": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdCertificateDto" }, - "type": { - "Options": null - } + "type": "array" }, "identifier": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdOrganizationPropertyDto" }, - "type": { - "Options": null - } + "type": "array" }, "roles": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdOrganizationRoleDto" }, - "type": { - "Options": null - } + "type": "array" }, "services": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdServiceDto" }, - "type": { - "Options": null - } + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdServiceDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "color": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "description": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "logoUrl": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "serviceId": { - "type": { - "Options": null - } + "type": "string" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIPoliciesCreatePolicyPolicyProperty": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIPoliciesCreatePolicyRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "action": { - "type": { - "Options": null - } + "type": "string" }, "attribute": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "expiration": { - "format": { - "Options": null - }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "nullable": true, + "type": "integer" }, "issuedAt": { - "format": { - "Options": null - }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "nullable": true, + "type": "integer" }, "issuerId": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "license": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "notBefore": { - "format": { - "Options": null - }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "nullable": true, + "type": "integer" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIPoliciesCreatePolicyPolicyProperty" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "rules": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "serviceProvider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "subjectId": { - "type": { - "Options": null - } + "type": "string" }, "type": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIPoliciesUpdatePolicyPolicyProperty": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIPoliciesUpdatePolicyRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "action": { - "type": { - "Options": null - } + "type": "string" }, "attribute": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "expiration": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "issuedAt": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "issuerId": { - "type": { - "Options": null - } + "type": "string" }, "license": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "notBefore": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "policyId": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIPoliciesUpdatePolicyPolicyProperty" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "rules": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "serviceProvider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "subjectId": { - "type": { - "Options": null - } + "type": "string" }, "type": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsCreateResourceGroupRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsCreateResourceGroupResourceGroupPropertyDto" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "resources": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceRequest" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsCreateResourceGroupResourceGroupPropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsCreateResourceGroupResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsCreateResourceGroupResourceGroupPropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "resources": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResponse" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsGetAllResourceGroupsResourceGroupPropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsGetAllResourceGroupsResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsGetAllResourceGroupsResourceGroupPropertyDto" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "resources": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResponse" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsGetResourceGroupByIdResourceGroupPropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsGetResourceGroupByIdResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsGetResourceGroupByIdResourceGroupPropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "resources": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResponse" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsUpdateResourceGroupRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsUpdateResourceGroupResourceGroupPropertyDto" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsUpdateResourceGroupResourceGroupPropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourceGroupsUpdateResourceGroupResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsUpdateResourceGroupResourceGroupPropertyDto" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "provider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "resourceGroupId": { - "type": { - "Options": null - } + "type": "string" }, "resources": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResponse" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "url": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupResourcePropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesCreateResourceRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesCreateResourceResourcePropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesCreateResourceResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesGetAllResourcesResourcePropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesGetAllResourcesResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesGetAllResourcesResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesGetResourceByIdResourcePropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesGetResourceByIdResponse": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesGetResourceByIdResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesUpdateResourceRequest": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "description": { - "type": { - "Options": null - } + "type": "string" }, "name": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } - }, - "nullable": { - "Options": null + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesUpdateResourceResourcePropertyDto" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAPIResourcesUpdateResourceResourcePropertyDto": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, - "Poort8DataspaceAuthorizationRegistryEntitiesPolicy": { - "additionalProperties": { - "Options": null + "Poort8DataspaceAPIResourcesUpdateResourceResponse": { + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "properties": { + "items": { + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesUpdateResourceResourcePropertyDto" + }, + "nullable": true, + "type": "array" + }, + "resourceId": { + "type": "string" + }, + "useCase": { + "type": "string" + } }, + "type": "object" + }, + "Poort8DataspaceAuthorizationRegistryEntitiesPolicy": { + "additionalProperties": false, "properties": { "action": { - "type": { - "Options": null - } + "type": "string" }, "attribute": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "expiration": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "issuedAt": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "issuerId": { - "type": { - "Options": null - } + "type": "string" }, "license": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "notBefore": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "policyId": { - "type": { - "Options": null - } + "type": "string" }, "properties": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy_PolicyProperty" }, - "type": { - "Options": null - } + "type": "array" }, "resourceId": { - "type": { - "Options": null - } + "type": "string" }, "rules": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "serviceProvider": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "subjectId": { - "type": { - "Options": null - } + "type": "string" }, "type": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" }, "useCase": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8DataspaceAuthorizationRegistryEntitiesPolicy_PolicyProperty": { - "additionalProperties": { - "Options": null - }, - "properties": { - "isIdentifier": { - "type": { - "Options": null - } - }, - "key": { - "type": { - "Options": null - } - }, - "propertyId": { - "type": { - "Options": null - } - }, - "value": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAuthorizationRegistryEntitiesResource": { - "additionalProperties": { - "Options": null - }, - "properties": { - "description": { - "type": { - "Options": null - } - }, - "name": { - "type": { - "Options": null - } - }, - "properties": { - "items": { - "$ref": { - "Options": null - } - }, - "type": { - "Options": null - } - }, - "resourceId": { - "type": { - "Options": null - } - }, - "useCase": { - "type": { - "Options": null - } - } - }, - "type": { - "Options": null - } - }, - "Poort8DataspaceAuthorizationRegistryEntitiesResource_ResourceProperty": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "isIdentifier": { - "type": { - "Options": null - } + "type": "boolean" }, "key": { - "type": { - "Options": null - } + "type": "string" }, "propertyId": { - "type": { - "Options": null - } + "type": "string" }, "value": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsAccessSubjectTarget": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "accessSubject": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationEvidence": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "notBefore": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "notOnOrAfter": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int64", + "type": "integer" }, "policyIssuer": { - "type": { - "Options": null - } + "type": "string" }, "policySets": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsPolicySet" }, - "type": { - "Options": null - } + "type": "array" }, "target": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsAccessSubjectTarget" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "delegationRequest": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "policyIssuer": { - "type": { - "Options": null - } + "type": "string" }, "policySets": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet" }, - "type": { - "Options": null - } + "type": "array" }, "target": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_TargetObject" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "policies": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "rules": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_Rule" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "target": { - "nullable": { - "Options": null - }, + "nullable": true, "oneOf": [ { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject" } ] } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_Rule": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "effect": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "actions": { "items": { - "type": { - "Options": null - } - }, - "nullable": { - "Options": null + "type": "string" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "environment": { - "nullable": { - "Options": null - }, + "nullable": true, "oneOf": [ { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject_EnvironmentObject" } ] }, "resource": { - "nullable": { - "Options": null - }, + "nullable": true, "oneOf": [ { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject_ResourceObject" } ] } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject_EnvironmentObject": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "serviceProviders": { "items": { - "type": { - "Options": null - } - }, - "nullable": { - "Options": null + "type": "string" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_PolicySet_Policy_TargetObject_ResourceObject": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "attributes": { "items": { - "type": { - "Options": null - } - }, - "nullable": { - "Options": null + "type": "string" }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "identifiers": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "array" }, "type": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsDelegationMask_DelegationRequestObject_TargetObject": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "accessSubject": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } + "nullable": true, + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsLicenseEnvironment": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "licenses": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsLicenseTarget": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "environment": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsLicenseEnvironment" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsPolicy": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "rules": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsRule" }, - "type": { - "Options": null - } + "type": "array" }, "target": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsResourceTarget" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsPolicySet": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "maxDelegationDepth": { - "format": { - "Options": null - }, - "type": { - "Options": null - } + "format": "int32", + "type": "integer" }, "policies": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsPolicy" }, - "type": { - "Options": null - } + "type": "array" }, "target": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsLicenseTarget" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsResource": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "attributes": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" }, "identifiers": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" }, "type": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsResourceTarget": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "actions": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" }, "environment": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsServiceProviderEnvironment" }, "resource": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsResource" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsRule": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "effect": { - "type": { - "Options": null - } + "type": "string" } }, - "type": { - "Options": null - } + "type": "object" }, "Poort8IshareCoreModelsServiceProviderEnvironment": { - "additionalProperties": { - "Options": null - }, + "additionalProperties": false, "properties": { "serviceProviders": { "items": { - "type": { - "Options": null - } + "type": "string" }, - "type": { - "Options": null - } + "type": "array" } }, - "type": { - "Options": null - } + "type": "object" } }, "securitySchemes": { - "JWTBearerAuth": { - "bearerFormat": { - "Options": null - }, - "description": { - "Options": null - }, - "scheme": { - "Options": null - }, - "type": { - "Options": null - } + "Bearer": { + "bearerFormat": "JWT", + "scheme": "Bearer", + "type": "http" } } }, "info": { - "title": { - "Options": null - }, - "version": { - "Options": null - } - }, - "openapi": { - "Options": null + "description": "The NoodleBar API, developed by Poort8, is an advanced dataspace solution designed to enable secure, controlled, and efficient data sharing between businesses. NoodleBar is known for its \u0022dataspace in a day\u0022 capability, meaning it provides all the necessary building blocks to quickly set up and operate a dataspace. The API is inspired by the iSHARE Trust Framework and adopts the same dataspace concepts and roles, ensuring seamless integration with iSHARE-compatible systems.\n\n# Organization Registry\n\nThe Organization Registry is a central database within the NoodleBar dataspace that stores information about all organizations (also referred to as parties) participating in the dataspace. It manages organizational identities, ensuring that all entities are properly identified and authenticated. This registry includes details such as:\n\n- **Identifiers**: Unique IDs for each organization.\n- **Names**: Official names of the organizations.\n- **Adherence Status**: Compliance information with dataspace standards.\n- **Roles**: The roles an organization plays within the dataspace (e.g., data provider, data consumer).\n- **Additional Properties**: Other relevant details like contact information, certificates, and services offered.\n\n# Authorization Registry\n\nThe Authorization Registry is responsible for managing access control within the dataspace. It defines and enforces policies (also known as authorizations or permissions) that determine the rules for accessing resources. Key functions include:\n\n- **Policy Management**: Creation, updating, and deletion of policies that govern resource access.\n- **Access Control**: Enforcement of policies to ensure only authorized entities can perform specific actions on resources.\n- **Delegation Evidence**: Providing signed proofs of authorization when required.\n\n# Dataspace\n\nThe Organization Registry and Authorization Registry work closely together to provide a secure and controlled environment for data sharing:\n\n1. **Authentication and Identification**:\n\n - When a user or system (subject) attempts to access a resource, the Organization Registry authenticates and identifies the entity using stored credentials and identifiers.\n - It ensures that only recognized and authenticated participants of the dataspace can proceed with access requests.\n2. **Authorization Enforcement**:\n\n - After authentication, the Authorization Registry checks whether the authenticated subject has the necessary permissions to perform the requested action on the resource.\n - It evaluates policies based on various factors such as the subject\u0027s role, the resource\u0027s attributes, the action requested, and the specific use case.\n3. **Access Decision**:\n\n - The outcome of the authorization check determines whether access is granted or denied.\n - If permitted, the subject can proceed with the action; if denied, the action is blocked to maintain security and compliance.\n\nBy integrating the management of organizational identities and access control policies, the Organization Registry and Authorization Registry ensure that data sharing within the NoodleBar dataspace is both secure and efficient. They maintain data sovereignty by allowing data owners to control who accesses their data and under what conditions.\n\n# Authentication\n\nOur API uses OAuth 2.0 Client Credentials Flow for authentication. You need to obtain an access token to access the API. Contact Poort8 for access.\n\nRequest a bearer token:\n\u0060\u0060\u0060\nPOST https://poort8.eu.auth0.com/oauth/token\nContent-Type: application/json\n\n{\n\t\u0022client_id\u0022: \u0022{{clientId}}\u0022,\n\t\u0022client_secret\u0022: \u0022{{clientSecret}}\u0022,\n\t\u0022audience\u0022: \u0022Poort8-Dataspace-CoreManager\u0022,\n\t\u0022grant_type\u0022: \u0022client_credentials\u0022,\n\t\u0022scope\u0022: \u0022delegation\u0022,\n\t\u0022requestedPermission\u0022: \u0022read:policies\u0022\n}\n\u0060\u0060\u0060\nAdd the \u0060\u0060\u0060access_token\u0060\u0060\u0060 from the token response to call the API. For example:\n\u0060\u0060\u0060\nGET {{host}}/api/policies?useCase=ishare\nAccept: application/json\nAuthorization: Bearer {{access_token}}\n\u0060\u0060\u0060\n## Permissions\n\nYou must request the appropriate \u0060\u0060\u0060requestedPermission\u0060\u0060\u0060 for each endpoint. The following permissions can be requested:\n- \u0060\u0060\u0060read:resources\u0060\u0060\u0060\n- \u0060\u0060\u0060write:resources\u0060\u0060\u0060\n- \u0060\u0060\u0060delete:resources\u0060\u0060\u0060\n- \u0060\u0060\u0060read:policies\u0060\u0060\u0060\n- \u0060\u0060\u0060write:policies\u0060\u0060\u0060\n- \u0060\u0060\u0060delete:policies\u0060\u0060\u0060\n- \u0060\u0060\u0060read:or-organizations\u0060\u0060\u0060\n- \u0060\u0060\u0060read:ar-organizations\u0060\u0060\u0060", + "title": "NoodleBar API", + "version": "v1" }, + "openapi": "3.0.0", "paths": { - "/Account/Logout": { - "post": { - "operationId": { - "Options": null - }, + "/api/authorization-registry-organizations/{id}": { + "get": { + "operationId": "Poort8DataspaceAPIAROrganizationsGetOrganizationByIdEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } - }, - "x-position": { - "Options": null + "type": "string" } } ], "responses": { "200": { - "description": { - "Options": null - } - } - } - } - }, - "/Account/Manage/DownloadPersonalData": { - "post": { - "operationId": { - "Options": null - }, - "responses": { - "200": { - "description": { - "Options": null - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Poort8DataspaceAPIAROrganizationsGetOrganizationByIdResponse" + } + } + }, + "description": "Success" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, - "security": [ - { - "JWTBearerAuth": [] - } + "tags": [ + "Authorization Registry Organizations" ] } }, - "/Account/Manage/LinkExternalLogin": { + "/api/authorization-registry-organizations/{organizationId}/employees": { "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "organizationId", + "required": true, "schema": { - "type": { - "Options": null - } - }, - "x-position": { - "Options": null + "type": "string" } } ], - "responses": { - "200": { - "description": { - "Options": null + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationRequest" + } } - } + }, + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, - "security": [ - { - "JWTBearerAuth": [] + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Poort8DataspaceAPIEmployeesAddNewEmployeeToOrganizationResponse" + } + } + }, + "description": "Created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "" } + }, + "summary": "Add a new employee to an organization", + "tags": [ + "Authorization Registry Organizations" ] } }, - "/Account/PerformExternalLogin": { - "post": { - "operationId": { - "Options": null - }, + "/api/authorization/enforce": { + "get": { + "operationId": "Poort8DataspaceAPIAuthorizationEnforceEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "subject", + "required": true, "schema": { - "type": { - "Options": null - } - }, - "x-position": { - "Options": null + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "resource", + "required": true, "schema": { - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - } - ], - "responses": { - "200": { - "description": { - "Options": null - } - } - } - } - }, - "/api/authorization/enforce": { - "get": { - "operationId": { - "Options": null - }, - "parameters": [ - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, - "schema": { - "type": { - "Options": null - } - } - }, - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, - "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "action", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "useCase", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -3149,172 +1735,92 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIAuthorizationEnforceResponse" } } }, - "description": { - "Options": null - } + "description": "Success" } }, "tags": [ - { - "Options": null - } + "Authorization" ] } }, "/api/authorization/explained-enforce": { "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIAuthorizationExplainedEnforceEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "subject", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "resource", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "action", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "useCase", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "issuer", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "serviceProvider", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "type", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "attribute", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "query", + "name": "context", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -3323,105 +1829,67 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIAuthorizationExplainedEnforceResponse" } } }, - "description": { - "Options": null - } + "description": "Success" } }, "tags": [ - { - "Options": null - } + "Authorization" ] } }, "/api/authorization/unsigned-delegation": { "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIAuthorizationUnsignedDelegationEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationMask" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "DelegationMask", + "x-position": 1 }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8IshareCoreModelsDelegationEvidence" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" } }, "tags": [ - { - "Options": null - } + "Authorization" ] } }, "/api/organization-registry/{id}": { "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIOROrganizationsGetOrganizationByIdEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -3430,268 +1898,173 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIOROrganizationsGetOrganizationByIdResponse" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Organization Registry" ] } }, "/api/policies": { "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIPoliciesGetAllPoliciesEndpoint", "responses": { "200": { "content": { "application/json": { "schema": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy" }, - "type": { - "Options": null - } + "type": "array" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" } }, "tags": [ - { - "Options": null - } + "Policies" ] }, "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIPoliciesCreatePolicyEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIPoliciesCreatePolicyRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" } }, "tags": [ - { - "Options": null - } + "Policies" ] }, "put": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIPoliciesUpdatePolicyEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIPoliciesUpdatePolicyRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Policies" ] } }, "/api/policies/{id}": { "delete": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIPoliciesDeletePolicyEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": {} - }, - "text/plain": { - "schema": {} - } - }, - "description": { - "Options": null - } + "204": { + "description": "No Content" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Policies" ] }, "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIPoliciesGetPolicyByIdEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -3700,268 +2073,176 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAuthorizationRegistryEntitiesPolicy" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Policies" ] } }, "/api/resourcegroups": { "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourceGroupsGetAllResourceGroupsEndpoint", "responses": { "200": { "content": { "application/json": { "schema": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsGetAllResourceGroupsResponse" }, - "type": { - "Options": null - } + "type": "array" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" } }, "tags": [ - { - "Options": null - } + "Resource Groups" ] }, "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourceGroupsCreateResourceGroupEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsCreateResourceGroupRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsCreateResourceGroupResponse" } } }, - "description": { - "Options": null - } + "description": "Created" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "409": { + "description": "" } }, "tags": [ - { - "Options": null - } + "Resource Groups" ] }, "put": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourceGroupsUpdateResourceGroupEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsUpdateResourceGroupRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsUpdateResourceGroupResponse" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Resource Groups" ] } }, "/api/resourcegroups/{id}": { "delete": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourceGroupsDeleteResourceGroupEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": {} - }, - "text/plain": { - "schema": {} - } - }, - "description": { - "Options": null - } + "204": { + "description": "No Content" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Resource Groups" ] }, "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourceGroupsGetResourceGroupByIdEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -3970,54 +2251,37 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourceGroupsGetResourceGroupByIdResponse" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Resource Groups" ] } }, "/api/resourcegroups/{resourceGroupId}/resources": { "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "resourceGroupId", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -4025,97 +2289,63 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesAddNewResourceToResourceGroupResponse" } } }, - "description": { - "Options": null - } + "description": "Created" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + }, + "409": { + "description": "" } }, - "summary": { - "Options": null - }, + "summary": "Add a new resource to a resource group", "tags": [ - { - "Options": null - } + "Resource Groups" ] } }, "/api/resourcegroups/{resourceGroupId}/resources/{resourceId}": { "delete": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesRemoveResourceFromResourceGroupEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "resourceGroupId", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "resourceId", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -4129,65 +2359,40 @@ "schema": {} } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, - "summary": { - "Options": null - }, + "summary": "Remove a resource from a resource group", "tags": [ - { - "Options": null - } + "Resource Groups" ] }, "put": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesAddExistingResourceToResourceGroupEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "resourceGroupId", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } }, { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "resourceId", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -4201,265 +2406,173 @@ "schema": {} } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, - "summary": { - "Options": null - }, + "summary": "Add an existing resource to a resource group", "tags": [ - { - "Options": null - } + "Resource Groups" ] } }, "/api/resources": { "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesGetAllResourcesEndpoint", "responses": { "200": { "content": { "application/json": { "schema": { "items": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesGetAllResourcesResponse" }, - "type": { - "Options": null - } + "type": "array" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" } }, "tags": [ - { - "Options": null - } + "Resources" ] }, "post": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesCreateResourceEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesCreateResourceResponse" } } }, - "description": { - "Options": null - } + "description": "Created" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "409": { + "description": "" } }, "tags": [ - { - "Options": null - } + "Resources" ] }, "put": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesUpdateResourceEndpoint", "requestBody": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesUpdateResourceRequest" } } }, - "description": { - "Options": null - }, - "required": { - "Options": null - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } + "description": "", + "required": true, + "x-name": "Request", + "x-position": 1 }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesUpdateResourceResponse" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Resources" ] } }, "/api/resources/{id}": { "delete": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesDeleteResourceEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": {} - }, - "text/plain": { - "schema": {} - } - }, - "description": { - "Options": null - } + "204": { + "description": "No Content" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } + "description": "Forbidden" + }, + "404": { + "description": "Not Found" } }, "tags": [ - { - "Options": null - } + "Resources" ] }, "get": { - "operationId": { - "Options": null - }, + "operationId": "Poort8DataspaceAPIResourcesGetResourceByIdEndpoint", "parameters": [ { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "required": { - "Options": null - }, + "in": "path", + "name": "id", + "required": true, "schema": { - "type": { - "Options": null - } + "type": "string" } } ], @@ -4468,568 +2581,53 @@ "content": { "application/json": { "schema": { - "$ref": { - "Options": null - } + "$ref": "#/components/schemas/Poort8DataspaceAPIResourcesGetResourceByIdResponse" } } }, - "description": { - "Options": null - } + "description": "Success" }, "401": { - "description": { - "Options": null - } + "description": "Unauthorized" }, "403": { - "description": { - "Options": null - } - } - }, - "tags": [ - { - "Options": null - } - ] - } - }, - "/confirmEmail": { - "get": { - "operationId": { - "Options": null - }, - "parameters": [ - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "schema": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - }, - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "schema": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - }, - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "schema": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - } - ], - "responses": { - "200": { - "description": { - "Options": null - } - } - } - } - }, - "/forgotPassword": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - } - } - } - }, - "/login": { - "post": { - "operationId": { - "Options": null - }, - "parameters": [ - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "schema": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - }, - { - "in": { - "Options": null - }, - "name": { - "Options": null - }, - "schema": { - "nullable": { - "Options": null - }, - "type": { - "Options": null - } - }, - "x-position": { - "Options": null - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - } - } - } - }, - "/manage/2fa": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } + "description": "Forbidden" }, "404": { - "description": { - "Options": null - } + "description": "Not Found" } }, - "security": [ - { - "JWTBearerAuth": [] - } + "tags": [ + "Resources" ] } + } + }, + "tags": [ + { + "description": "Accessing the **Organization Registry** endpoints lets you interact with the central database of all organizations participating in the dataspace. This interaction enables you to:\n\n- **Authenticate Participants**: Verify the identities of organizations to establish trust within the dataspace.\n- **Retrieve Organizational Information**: Access details such as roles, attributes, and compliance status to inform your application\u0027s logic.\n- **Facilitate Secure Collaboration**: Use organizational data to manage partnerships and data-sharing agreements securely.\n\nThis functionality is crucial for building applications that require secure and verified interactions between multiple entities.", + "name": "Organization Registry" }, - "/manage/info": { - "get": { - "operationId": { - "Options": null - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - }, - "404": { - "description": { - "Options": null - } - } - }, - "security": [ - { - "JWTBearerAuth": [] - } - ] - }, - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - }, - "404": { - "description": { - "Options": null - } - } - }, - "security": [ - { - "JWTBearerAuth": [] - } - ] - } + { + "description": "Through the **Authorization Registry Organizations** endpoints, you can:\n\n- **Audit Access Rights**: Retrieve information about the permissions and policies associated with organizations in the authorization registry.\n- **Monitor and Enforce Compliance**: Ensure that organizations adhere to the defined access control policies and take corrective actions if necessary.\n- **Enhance Security Oversight**: Gain insights into who has access to what, strengthening your application\u0027s security posture.\n\nThis capability allows you to maintain control over data access within the dataspace, ensuring that your applications remain secure and compliant.", + "name": "Authorization Registry Organizations" }, - "/refresh": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - } - } - } + { + "description": "The **Policies** endpoints are essential for defining and managing the rules that govern access to resources within your dataspace. They allow you to:\n\n- **Implement Fine-Grained Access Control**: Specify detailed permissions for who can access which resources and under what conditions.\n- **Adapt to Changing Needs**: Quickly adjust access rules in response to evolving requirements or user roles.\n- **Maintain Security Compliance**: Ensure your applications adhere to security standards and regulatory policies.\n\nUtilizing these endpoints helps you safeguard your resources while providing the flexibility needed to support dynamic environments.", + "name": "Policies" }, - "/register": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - } - } - } + { + "description": "The **Resources** endpoints are your gateway to managing the fundamental assets within your dataspace---be they datasets, APIs, or physical devices. As a developer, you can:\n\n- **Integrate Diverse Assets**: Seamlessly add various types of resources to your dataspace, enhancing the capabilities of your applications.\n- **Customize and Enrich**: Define and modify resource attributes to tailor them to your application\u0027s needs.\n- **Optimize Data Utilization**: Efficiently organize and access resources to improve data retrieval and application performance.\n\nThese endpoints empower you to handle resources flexibly, enabling the creation of robust and scalable solutions without the hassle of low-level management tasks.", + "name": "Resources" }, - "/resendConfirmationEmail": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "description": { - "Options": null - } - } - } - } + { + "description": "The **Resource Groups** endpoints enable efficient management of collections of resources, also known as services or resource types. With these endpoints, you can:\n\n- **Organize Logically**: Group related resources to reflect the structure of your application or business logic.\n- **Streamline Access Control**: Apply policies and permissions at the group level, simplifying security management.\n- **Enhance Scalability**: Manage large numbers of resources collectively, reducing administrative overhead.\n\nBy leveraging resource groups, you can maintain an organized dataspace and simplify the management of complex resource hierarchies.", + "name": "Resource Groups" }, - "/resetPassword": { - "post": { - "operationId": { - "Options": null - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "x-name": { - "Options": null - }, - "x-position": { - "Options": null - } - }, - "responses": { - "200": { - "description": { - "Options": null - } - }, - "400": { - "content": { - "application/json": { - "schema": { - "$ref": { - "Options": null - } - } - } - }, - "description": { - "Options": null - } - } - } - } + { + "description": "The **Authorization** endpoints provide powerful mechanisms to enforce and audit access control decisions within your applications. They enable you to:\n\n- **Verify Permissions in Real-Time**: Check whether a user or system has the rights to perform a specific action on a resource, ensuring immediate compliance with policies.\n- **Understand Access Decisions**: Obtain detailed explanations of authorization outcomes to facilitate debugging and transparency.\n- **Manage Delegated Access**: Handle permission delegations securely, allowing for flexible access hierarchies and trust relationships.\n\nThese endpoints are vital for maintaining robust security and ensuring that only authorized entities can access sensitive resources.", + "name": "Authorization" } - }, - "x-generator": { - "Options": null - } + ], + "x-generator": "NSwag v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))" } diff --git a/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Endpoint.cs b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Endpoint.cs new file mode 100644 index 0000000..2774c31 --- /dev/null +++ b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Endpoint.cs @@ -0,0 +1,44 @@ +using FastEndpoints; +using Poort8.Dataspace.Identity; +using Poort8.Dataspace.AuthorizationRegistry; + +namespace Poort8.Dataspace.API.AROrganizations.GetOrganizationById; + +public class Endpoint : EndpointWithoutRequest +{ + public const string Name = "Authorization Registry Organizations"; + private readonly ILogger _logger; + private readonly IAuthorizationRegistry _authorizationRegistry; + + public Endpoint( + ILoggerFactory loggerFactory, + IAuthorizationRegistry authorizationRegistry) + { + _logger = loggerFactory.CreateLogger(); + _authorizationRegistry = authorizationRegistry; + } + + public override void Configure() + { + Get($"/api/{Name.Replace(' ', '-').ToLower()}/{{id}}"); + Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); + Policies(AuthenticationConstants.ReadAROrganizationsPolicy); + } + + public override async Task HandleAsync(CancellationToken ct) + { + string id = Route("id")!; + var organization = await _authorizationRegistry.ReadOrganization(id); + + if (organization == null) + { + await SendNotFoundAsync(ct); + return; + } + + await SendMapped(organization, 200, ct); + } +} diff --git a/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Mapper.cs b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Mapper.cs new file mode 100644 index 0000000..5bdafb1 --- /dev/null +++ b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Mapper.cs @@ -0,0 +1,34 @@ +using FastEndpoints; +using Poort8.Dataspace.AuthorizationRegistry.Entities; + +namespace Poort8.Dataspace.API.AROrganizations.GetOrganizationById; + +public class Mapper : ResponseMapper +{ + public override Response FromEntity(Organization organization) + { + return new Response( + organization.Identifier, + organization.UseCase, + organization.Name, + organization.Url, + organization.Representative, + organization.InvoicingContact, + organization.Employees.Select(e => new EmployeeDto( + e.EmployeeId, + e.UseCase, + e.GivenName, + e.FamilyName, + e.Telephone, + e.Email, + e.Properties.Select(p => new EmployeePropertyDto( + p.Key, + p.Value, + p.IsIdentifier)).ToList())).ToList(), + organization.Properties.Select(p => new OrganizationPropertyDto( + p.Key, + p.Value, + p.IsIdentifier)).ToList() + ); + } +} diff --git a/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Models.cs b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Models.cs new file mode 100644 index 0000000..963a94c --- /dev/null +++ b/Poort8.Dataspace.API/AROrganizations/GetOrganizationById/Models.cs @@ -0,0 +1,30 @@ +namespace Poort8.Dataspace.API.AROrganizations.GetOrganizationById; + +public record Response( + string Identifier, + string UseCase, + string Name, + string Url, + string Representative, + string InvoicingContact, + ICollection Employees, + ICollection Properties); + +public record EmployeeDto( + string EmployeeId, + string UseCase, + string GivenName, + string FamilyName, + string Telephone, + string Email, + ICollection Properties); + +public record EmployeePropertyDto( + string Key, + string Value, + bool IsIdentifier); + +public record OrganizationPropertyDto( + string Key, + string Value, + bool IsIdentifier); \ No newline at end of file diff --git a/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Endpoint.cs b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Endpoint.cs new file mode 100644 index 0000000..9bb42f2 --- /dev/null +++ b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Endpoint.cs @@ -0,0 +1,70 @@ +using FastEndpoints; +using Poort8.Dataspace.AuthorizationRegistry; +using Poort8.Dataspace.AuthorizationRegistry.Exceptions; +using Poort8.Dataspace.Identity; + +namespace Poort8.Dataspace.API.Employees.AddNewEmployeeToOrganization; + +public class Endpoint : Endpoint +{ + public const string Name = "Authorization Registry Organizations"; + public const string NameId = "organizationId"; + public const string NameChild = "Employees"; + public const string EndpointSummary = "Add a new employee to an organization"; + private readonly ILogger _logger; + private readonly IAuthorizationRegistry _authorizationRegistry; + + public Endpoint( + ILoggerFactory loggerFactory, + IAuthorizationRegistry authorizationRegistry) + { + _logger = loggerFactory.CreateLogger(); + _authorizationRegistry = authorizationRegistry; + } + + public override void Configure() + { + Post("/api/" + Name.Replace(' ', '-').ToLower() + "/{" + NameId + "}/" + NameChild.ToLower()); + Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(201); + x.Produces(404); + x.Produces(409); + }); + + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); + Policies(AuthenticationConstants.WriteResourcesPolicy); + Summary(s => { s.Summary = EndpointSummary; }); + } + + public override async Task HandleAsync(Request request, CancellationToken ct) + { + string organizationId = Route(NameId)!; + var organization = await _authorizationRegistry.ReadOrganization(organizationId); + if (organization == null) + { + await SendNotFoundAsync(ct); + return; + } + + var entity = Map.ToEntity(request); + + try + { + var employee = await _authorizationRegistry.AddNewEmployeeToOrganization(organizationId, entity); + await SendMapped(employee, 201, ct); + } + catch (RepositoryException e) + { + if (e.Message.StartsWith(RepositoryException.IdNotUnique)) + ThrowError(e.Message, 409); + } + catch (Exception e) + { + _logger.LogCritical("P8.crit - Error in endpoint {endpointName}: {msg}", Name, e.Message); + throw; + } + } +} diff --git a/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Mapper.cs b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Mapper.cs new file mode 100644 index 0000000..7c80a89 --- /dev/null +++ b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Mapper.cs @@ -0,0 +1,32 @@ +using FastEndpoints; +using Poort8.Dataspace.AuthorizationRegistry.Entities; + +namespace Poort8.Dataspace.API.Employees.AddNewEmployeeToOrganization; + +public class Mapper : Mapper +{ + public override Employee ToEntity(Request request) + { + return new Employee( + request.EmployeeId, + request.UseCase, + request.GivenName, + request.FamilyName, + request.Telephone, + request.Email, + request.Properties?.Select(p => new Employee.EmployeeProperty(p.Key, p.Value, p.IsIdentifier)).ToList() ?? []); + } + + public override Response FromEntity(Employee employee) + { + return new Response( + employee.EmployeeId, + employee.UseCase, + employee.GivenName, + employee.FamilyName, + employee.Telephone, + employee.Email, + employee.Properties.Select( + p => new EmployeePropertyDto(p.Key, p.Value, p.IsIdentifier)).ToList()); + } +} diff --git a/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Models.cs b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Models.cs new file mode 100644 index 0000000..648b4a6 --- /dev/null +++ b/Poort8.Dataspace.API/Employees/AddNewEmployeeToOrganization/Models.cs @@ -0,0 +1,24 @@ +namespace Poort8.Dataspace.API.Employees.AddNewEmployeeToOrganization; + +public record Request( + string EmployeeId, + string UseCase, + string GivenName, + string FamilyName, + string Telephone, + string Email, + ICollection? Properties); + +public record EmployeePropertyDto( + string Key, + string Value, + bool IsIdentifier); + +public record Response( + string EmployeeId, + string UseCase, + string GivenName, + string FamilyName, + string Telephone, + string Email, + ICollection? Properties); diff --git a/Poort8.Dataspace.API/Extensions/ApiDefinitionExtensions.cs b/Poort8.Dataspace.API/Extensions/ApiDefinitionExtensions.cs new file mode 100644 index 0000000..6148558 --- /dev/null +++ b/Poort8.Dataspace.API/Extensions/ApiDefinitionExtensions.cs @@ -0,0 +1,182 @@ +using FastEndpoints.Swagger; +using NSwag; + +namespace Poort8.Dataspace.API.Extensions; + +public static class ApiDefinitionExtensions +{ + private const string Description = @" +The NoodleBar API, developed by Poort8, is an advanced dataspace solution designed to enable secure, controlled, and efficient data sharing between businesses. NoodleBar is known for its ""dataspace in a day"" capability, meaning it provides all the necessary building blocks to quickly set up and operate a dataspace. The API is inspired by the iSHARE Trust Framework and adopts the same dataspace concepts and roles, ensuring seamless integration with iSHARE-compatible systems. + +# Organization Registry + +The Organization Registry is a central database within the NoodleBar dataspace that stores information about all organizations (also referred to as parties) participating in the dataspace. It manages organizational identities, ensuring that all entities are properly identified and authenticated. This registry includes details such as: + +- **Identifiers**: Unique IDs for each organization. +- **Names**: Official names of the organizations. +- **Adherence Status**: Compliance information with dataspace standards. +- **Roles**: The roles an organization plays within the dataspace (e.g., data provider, data consumer). +- **Additional Properties**: Other relevant details like contact information, certificates, and services offered. + +# Authorization Registry + +The Authorization Registry is responsible for managing access control within the dataspace. It defines and enforces policies (also known as authorizations or permissions) that determine the rules for accessing resources. Key functions include: + +- **Policy Management**: Creation, updating, and deletion of policies that govern resource access. +- **Access Control**: Enforcement of policies to ensure only authorized entities can perform specific actions on resources. +- **Delegation Evidence**: Providing signed proofs of authorization when required. + +# Dataspace + +The Organization Registry and Authorization Registry work closely together to provide a secure and controlled environment for data sharing: + +1. **Authentication and Identification**: + + - When a user or system (subject) attempts to access a resource, the Organization Registry authenticates and identifies the entity using stored credentials and identifiers. + - It ensures that only recognized and authenticated participants of the dataspace can proceed with access requests. +2. **Authorization Enforcement**: + + - After authentication, the Authorization Registry checks whether the authenticated subject has the necessary permissions to perform the requested action on the resource. + - It evaluates policies based on various factors such as the subject's role, the resource's attributes, the action requested, and the specific use case. +3. **Access Decision**: + + - The outcome of the authorization check determines whether access is granted or denied. + - If permitted, the subject can proceed with the action; if denied, the action is blocked to maintain security and compliance. + +By integrating the management of organizational identities and access control policies, the Organization Registry and Authorization Registry ensure that data sharing within the NoodleBar dataspace is both secure and efficient. They maintain data sovereignty by allowing data owners to control who accesses their data and under what conditions. + +# Authentication + +Our API uses OAuth 2.0 Client Credentials Flow for authentication. You need to obtain an access token to access the API. Contact Poort8 for access. + +Request a bearer token: +``` +POST https://poort8.eu.auth0.com/oauth/token +Content-Type: application/json + +{ + ""client_id"": ""{{clientId}}"", + ""client_secret"": ""{{clientSecret}}"", + ""audience"": ""Poort8-Dataspace-CoreManager"", + ""grant_type"": ""client_credentials"", + ""scope"": ""delegation"", + ""requestedPermission"": ""read:policies"" +} +``` +Add the ```access_token``` from the token response to call the API. For example: +``` +GET {{host}}/api/policies?useCase=ishare +Accept: application/json +Authorization: Bearer {{access_token}} +``` +## Permissions + +You must request the appropriate ```requestedPermission``` for each endpoint. The following permissions can be requested: +- ```read:resources``` +- ```write:resources``` +- ```delete:resources``` +- ```read:policies``` +- ```write:policies``` +- ```delete:policies``` +- ```read:or-organizations``` +- ```read:ar-organizations``` + +"; + + private const string ResourcesDescription = @" +The **Resources** endpoints are your gateway to managing the fundamental assets within your dataspace---be they datasets, APIs, or physical devices. As a developer, you can: + +- **Integrate Diverse Assets**: Seamlessly add various types of resources to your dataspace, enhancing the capabilities of your applications. +- **Customize and Enrich**: Define and modify resource attributes to tailor them to your application's needs. +- **Optimize Data Utilization**: Efficiently organize and access resources to improve data retrieval and application performance. + +These endpoints empower you to handle resources flexibly, enabling the creation of robust and scalable solutions without the hassle of low-level management tasks. +"; + + private const string ResourceGroupsDescription = @" +The **Resource Groups** endpoints enable efficient management of collections of resources, also known as services or resource types. With these endpoints, you can: + +- **Organize Logically**: Group related resources to reflect the structure of your application or business logic. +- **Streamline Access Control**: Apply policies and permissions at the group level, simplifying security management. +- **Enhance Scalability**: Manage large numbers of resources collectively, reducing administrative overhead. + +By leveraging resource groups, you can maintain an organized dataspace and simplify the management of complex resource hierarchies. +"; + + private const string PoliciesDescription = @" +The **Policies** endpoints are essential for defining and managing the rules that govern access to resources within your dataspace. They allow you to: + +- **Implement Fine-Grained Access Control**: Specify detailed permissions for who can access which resources and under what conditions. +- **Adapt to Changing Needs**: Quickly adjust access rules in response to evolving requirements or user roles. +- **Maintain Security Compliance**: Ensure your applications adhere to security standards and regulatory policies. + +Utilizing these endpoints helps you safeguard your resources while providing the flexibility needed to support dynamic environments. +"; + + private const string OrganizationRegistryDescription = @" +Accessing the **Organization Registry** endpoints lets you interact with the central database of all organizations participating in the dataspace. This interaction enables you to: + +- **Authenticate Participants**: Verify the identities of organizations to establish trust within the dataspace. +- **Retrieve Organizational Information**: Access details such as roles, attributes, and compliance status to inform your application's logic. +- **Facilitate Secure Collaboration**: Use organizational data to manage partnerships and data-sharing agreements securely. + +This functionality is crucial for building applications that require secure and verified interactions between multiple entities. +"; + + private const string AuthorizationRegistryDescription = @" +Through the **Authorization Registry Organizations** endpoints, you can: + +- **Audit Access Rights**: Retrieve information about the permissions and policies associated with organizations in the authorization registry. +- **Monitor and Enforce Compliance**: Ensure that organizations adhere to the defined access control policies and take corrective actions if necessary. +- **Enhance Security Oversight**: Gain insights into who has access to what, strengthening your application's security posture. + +This capability allows you to maintain control over data access within the dataspace, ensuring that your applications remain secure and compliant. +"; + + private const string AuthoriztionDescription = @" +The **Authorization** endpoints provide powerful mechanisms to enforce and audit access control decisions within your applications. They enable you to: + +- **Verify Permissions in Real-Time**: Check whether a user or system has the rights to perform a specific action on a resource, ensuring immediate compliance with policies. +- **Understand Access Decisions**: Obtain detailed explanations of authorization outcomes to facilitate debugging and transparency. +- **Manage Delegated Access**: Handle permission delegations securely, allowing for flexible access hierarchies and trust relationships. + +These endpoints are vital for maintaining robust security and ensuring that only authorized entities can access sensitive resources. +"; + + public static IServiceCollection AddApiDefinition(this IServiceCollection services) + { + services.SwaggerDocument(options => + { + options.DocumentSettings = s => + { + s.Title = "NoodleBar API"; + s.Version = "v1"; + s.Description = Description.Trim(); + + s.AddAuth("Bearer", new() + { + Type = OpenApiSecuritySchemeType.Http, + Scheme = "Bearer", + BearerFormat = "JWT", + }); + }; + + options.TagDescriptions = t => + { + t["Organization Registry"] = OrganizationRegistryDescription.Trim(); + t["Authorization Registry Organizations"] = AuthorizationRegistryDescription.Trim(); + t["Policies"] = PoliciesDescription.Trim(); + t["Resources"] = ResourcesDescription.Trim(); + t["Resource Groups"] = ResourceGroupsDescription.Trim(); + t["Authorization"] = AuthoriztionDescription.Trim(); + }; + + options.EnableJWTBearerAuth = false; + options.AutoTagPathSegmentIndex = 0; + options.ExcludeNonFastEndpoints = true; + options.EndpointFilter = ep => !(ep.EndpointTags?.Contains("ExcludeFromSwagger") ?? false); + }); + + return services; + } +} diff --git a/Poort8.Dataspace.API/OROrganizations/GetOrganizationById/Endpoint.cs b/Poort8.Dataspace.API/OROrganizations/GetOrganizationById/Endpoint.cs index 5568ecd..c43c3f3 100644 --- a/Poort8.Dataspace.API/OROrganizations/GetOrganizationById/Endpoint.cs +++ b/Poort8.Dataspace.API/OROrganizations/GetOrganizationById/Endpoint.cs @@ -22,6 +22,8 @@ public override void Configure() { Get($"/api/{Name.Replace(' ', '-').ToLower()}/{{id}}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.ReadOROrganizationsPolicy); } diff --git a/Poort8.Dataspace.API/Policies/CreatePolicy/Endpoint.cs b/Poort8.Dataspace.API/Policies/CreatePolicy/Endpoint.cs index 520fcf4..d55d121 100644 --- a/Poort8.Dataspace.API/Policies/CreatePolicy/Endpoint.cs +++ b/Poort8.Dataspace.API/Policies/CreatePolicy/Endpoint.cs @@ -31,7 +31,7 @@ public override async Task HandleAsync(Request request, CancellationToken ct) string issuerId; if (string.IsNullOrEmpty(request.IssuerId)) issuerId = User.Identity!.Name!; - else if (User.IsInRole("CanSetPolicyIssuer")) + else if (User.IsInRole("CanSetPolicyIssuer") || User.HasClaim("scope", "trusted-app")) issuerId = request.IssuerId; else { diff --git a/Poort8.Dataspace.API/Policies/DeletePolicy/Endpoint.cs b/Poort8.Dataspace.API/Policies/DeletePolicy/Endpoint.cs index 4727e31..82cf386 100644 --- a/Poort8.Dataspace.API/Policies/DeletePolicy/Endpoint.cs +++ b/Poort8.Dataspace.API/Policies/DeletePolicy/Endpoint.cs @@ -21,6 +21,13 @@ public override void Configure() { Delete("/api/policies/{id}"); Options(x => x.WithTags("Policies")); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(204); + x.Produces(404); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.DeletePoliciesPolicy); } diff --git a/Poort8.Dataspace.API/Policies/GetPolicyById/Endpoint.cs b/Poort8.Dataspace.API/Policies/GetPolicyById/Endpoint.cs index 6f12fce..e9aef8b 100644 --- a/Poort8.Dataspace.API/Policies/GetPolicyById/Endpoint.cs +++ b/Poort8.Dataspace.API/Policies/GetPolicyById/Endpoint.cs @@ -22,6 +22,8 @@ public override void Configure() { Get("/api/policies/{id}"); Options(x => x.WithTags("Policies")); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.ReadPoliciesPolicy); } diff --git a/Poort8.Dataspace.API/Policies/UpdatePolicy/Endpoint.cs b/Poort8.Dataspace.API/Policies/UpdatePolicy/Endpoint.cs index f788cd5..3ca7668 100644 --- a/Poort8.Dataspace.API/Policies/UpdatePolicy/Endpoint.cs +++ b/Poort8.Dataspace.API/Policies/UpdatePolicy/Endpoint.cs @@ -22,6 +22,8 @@ public override void Configure() { Put("/api/policies"); Options(x => x.WithTags("Policies")); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WritePoliciesPolicy); } diff --git a/Poort8.Dataspace.API/Poort8.Dataspace.API.csproj b/Poort8.Dataspace.API/Poort8.Dataspace.API.csproj index 09f9fc0..66fe37f 100644 --- a/Poort8.Dataspace.API/Poort8.Dataspace.API.csproj +++ b/Poort8.Dataspace.API/Poort8.Dataspace.API.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable true @@ -12,9 +12,11 @@ - - - + + + + + diff --git a/Poort8.Dataspace.API/Program.cs b/Poort8.Dataspace.API/Program.cs index bcf5cf9..9dce681 100644 --- a/Poort8.Dataspace.API/Program.cs +++ b/Poort8.Dataspace.API/Program.cs @@ -1,7 +1,11 @@ //NOTE: This is scaffolding for a future API project. Now it is used by Poort8.Dataspace.CoreManager. +using Azure.Monitor.OpenTelemetry.AspNetCore; + var builder = WebApplication.CreateBuilder(args); +builder.Services.AddOpenTelemetry().UseAzureMonitor(); + var app = builder.Build(); app.UseHttpsRedirection(); diff --git a/Poort8.Dataspace.API/ResourceGroups/CreateResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/ResourceGroups/CreateResourceGroup/Endpoint.cs index 3b4b79a..da2fcb5 100644 --- a/Poort8.Dataspace.API/ResourceGroups/CreateResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/ResourceGroups/CreateResourceGroup/Endpoint.cs @@ -1,12 +1,13 @@ using FastEndpoints; using Poort8.Dataspace.AuthorizationRegistry; +using Poort8.Dataspace.AuthorizationRegistry.Exceptions; using Poort8.Dataspace.Identity; namespace Poort8.Dataspace.API.ResourceGroups.CreateResourceGroup; public class Endpoint : Endpoint { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; private readonly ILogger _logger; private readonly IAuthorizationRegistry _authorizationRegistry; @@ -20,8 +21,15 @@ public Endpoint( public override void Configure() { - Post($"/api/{Name.ToLower()}"); + Post($"/api/{Name.ToLower().Replace(" ", "")}"); Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(201); + x.Produces(409); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WriteResourcesPolicy); } @@ -30,8 +38,20 @@ public override async Task HandleAsync(Request request, CancellationToken ct) { var entity = Map.ToEntity(request); - var resourceGroup = await _authorizationRegistry.CreateResourceGroup(entity); - - await SendMapped(resourceGroup, 201, ct); + try + { + var resourceGroup = await _authorizationRegistry.CreateResourceGroup(entity); + await SendMapped(resourceGroup, 201, ct); + } + catch (RepositoryException e) + { + if (e.Message.StartsWith(RepositoryException.IdNotUnique)) + ThrowError(e.Message, 409); + } + catch (Exception e) + { + _logger.LogCritical("P8.crit - Error in endpoint {endpointName}: {msg}", Name, e.Message); + throw; + } } } diff --git a/Poort8.Dataspace.API/ResourceGroups/DeleteResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/ResourceGroups/DeleteResourceGroup/Endpoint.cs index 28694be..5955a5a 100644 --- a/Poort8.Dataspace.API/ResourceGroups/DeleteResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/ResourceGroups/DeleteResourceGroup/Endpoint.cs @@ -6,7 +6,7 @@ namespace Poort8.Dataspace.API.ResourceGroups.DeleteResourceGroup; public class Endpoint : EndpointWithoutRequest { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; private readonly ILogger _logger; private readonly IAuthorizationRegistry _authorizationRegistry; @@ -20,8 +20,15 @@ public Endpoint( public override void Configure() { - Delete($"/api/{Name.ToLower()}/{{id}}"); + Delete($"/api/{Name.ToLower().Replace(" ", "")}/{{id}}"); Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(204); + x.Produces(404); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.DeleteResourcesPolicy); } diff --git a/Poort8.Dataspace.API/ResourceGroups/GetAllResourceGroups/Endpoint.cs b/Poort8.Dataspace.API/ResourceGroups/GetAllResourceGroups/Endpoint.cs index 026f389..557f74a 100644 --- a/Poort8.Dataspace.API/ResourceGroups/GetAllResourceGroups/Endpoint.cs +++ b/Poort8.Dataspace.API/ResourceGroups/GetAllResourceGroups/Endpoint.cs @@ -6,7 +6,7 @@ namespace Poort8.Dataspace.API.ResourceGroups.GetAllResourceGroups; public class Endpoint : EndpointWithoutRequest, Mapper> { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; private readonly ILogger _logger; private readonly IAuthorizationRegistry _authorizationRegistry; @@ -20,7 +20,7 @@ public Endpoint( public override void Configure() { - Get($"/api/{Name.ToLower()}"); + Get($"/api/{Name.ToLower().Replace(" ", "")}"); Options(x => x.WithTags(Name)); AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.ReadResourcesPolicy); diff --git a/Poort8.Dataspace.API/ResourceGroups/GetResourceGroupById/Endpoint.cs b/Poort8.Dataspace.API/ResourceGroups/GetResourceGroupById/Endpoint.cs index 1c8d5e0..34da61f 100644 --- a/Poort8.Dataspace.API/ResourceGroups/GetResourceGroupById/Endpoint.cs +++ b/Poort8.Dataspace.API/ResourceGroups/GetResourceGroupById/Endpoint.cs @@ -6,7 +6,7 @@ namespace Poort8.Dataspace.API.ResourceGroups.GetResourceGroupById; public class Endpoint : EndpointWithoutRequest { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; private readonly ILogger _logger; private readonly IAuthorizationRegistry _authorizationRegistry; @@ -20,8 +20,10 @@ public Endpoint( public override void Configure() { - Get($"/api/{Name.ToLower()}/{{id}}"); + Get($"/api/{Name.ToLower().Replace(" ", "")}/{{id}}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.ReadResourcesPolicy); } diff --git a/Poort8.Dataspace.API/ResourceGroups/UpdateResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/ResourceGroups/UpdateResourceGroup/Endpoint.cs index 426aaf5..4768e16 100644 --- a/Poort8.Dataspace.API/ResourceGroups/UpdateResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/ResourceGroups/UpdateResourceGroup/Endpoint.cs @@ -7,7 +7,7 @@ namespace Poort8.Dataspace.API.ResourceGroups.UpdateResourceGroup; public class Endpoint : Endpoint { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; private readonly ILogger _logger; private readonly IAuthorizationRegistry _authorizationRegistry; @@ -21,10 +21,12 @@ public Endpoint( public override void Configure() { - Put($"/api/{Name.ToLower()}"); + Put($"/api/{Name.ToLower().Replace(" ", "")}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); - Policies(AuthenticationConstants.WritePoliciesPolicy); + Policies(AuthenticationConstants.WriteResourcesPolicy); } public override async Task HandleAsync(Request request, CancellationToken ct) diff --git a/Poort8.Dataspace.API/Resources/AddExistingResourceToResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/Resources/AddExistingResourceToResourceGroup/Endpoint.cs index 9ef4a9e..a2f0e61 100644 --- a/Poort8.Dataspace.API/Resources/AddExistingResourceToResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/AddExistingResourceToResourceGroup/Endpoint.cs @@ -6,7 +6,7 @@ namespace Poort8.Dataspace.API.Resources.AddExistingResourceToResourceGroup; public class Endpoint : EndpointWithoutRequest { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; public const string NameId = "resourceGroupId"; public const string NameChild = "Resources"; public const string NameChildId = "resourceId"; @@ -24,8 +24,10 @@ public Endpoint( public override void Configure() { - Put("/api/" + Name.ToLower() + "/{" + NameId + "}/" + NameChild.ToLower() + "/{" + NameChildId + "}"); + Put("/api/" + Name.ToLower().Replace(" ", "") + "/{" + NameId + "}/" + NameChild.ToLower() + "/{" + NameChildId + "}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WriteResourcesPolicy); Summary(s => { s.Summary = EndpointSummary; }); diff --git a/Poort8.Dataspace.API/Resources/AddNewResourceToResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/Resources/AddNewResourceToResourceGroup/Endpoint.cs index 487ca22..b44f8a1 100644 --- a/Poort8.Dataspace.API/Resources/AddNewResourceToResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/AddNewResourceToResourceGroup/Endpoint.cs @@ -1,12 +1,13 @@ using FastEndpoints; using Poort8.Dataspace.AuthorizationRegistry; +using Poort8.Dataspace.AuthorizationRegistry.Exceptions; using Poort8.Dataspace.Identity; namespace Poort8.Dataspace.API.Resources.AddNewResourceToResourceGroup; public class Endpoint : Endpoint { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; public const string NameId = "resourceGroupId"; public const string NameChild = "Resources"; public const string EndpointSummary = "Add a new resource to a resource group"; @@ -23,8 +24,16 @@ public Endpoint( public override void Configure() { - Post("/api/" + Name.ToLower() + "/{" + NameId + "}/" + NameChild.ToLower()); + Post("/api/" + Name.ToLower().Replace(" ", "") + "/{" + NameId + "}/" + NameChild.ToLower()); Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(201); + x.Produces(404); + x.Produces(409); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WriteResourcesPolicy); Summary(s => { s.Summary = EndpointSummary; }); @@ -42,8 +51,20 @@ public override async Task HandleAsync(Request request, CancellationToken ct) var entity = Map.ToEntity(request); - var resource = await _authorizationRegistry.AddNewResourceToResourceGroup(resourceGroupId, entity); - - await SendMapped(resource, 201, ct); + try + { + var resource = await _authorizationRegistry.AddNewResourceToResourceGroup(resourceGroupId, entity); + await SendMapped(resource, 201, ct); + } + catch (RepositoryException e) + { + if (e.Message.StartsWith(RepositoryException.IdNotUnique)) + ThrowError(e.Message, 409); + } + catch (Exception e) + { + _logger.LogCritical("P8.crit - Error in endpoint {endpointName}: {msg}", Name, e.Message); + throw; + } } } diff --git a/Poort8.Dataspace.API/Resources/CreateResource/Endpoint.cs b/Poort8.Dataspace.API/Resources/CreateResource/Endpoint.cs index cd61b52..80093a8 100644 --- a/Poort8.Dataspace.API/Resources/CreateResource/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/CreateResource/Endpoint.cs @@ -1,5 +1,6 @@ using FastEndpoints; using Poort8.Dataspace.AuthorizationRegistry; +using Poort8.Dataspace.AuthorizationRegistry.Exceptions; using Poort8.Dataspace.Identity; namespace Poort8.Dataspace.API.Resources.CreateResource; @@ -22,6 +23,13 @@ public override void Configure() { Post($"/api/{Name.ToLower()}"); Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(201); + x.Produces(409); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WriteResourcesPolicy); } @@ -30,8 +38,20 @@ public override async Task HandleAsync(Request request, CancellationToken ct) { var entity = Map.ToEntity(request); - var resource = await _authorizationRegistry.CreateResource(entity); - - await SendMapped(resource, 201, ct); + try + { + var resource = await _authorizationRegistry.CreateResource(entity); + await SendMapped(resource, 201, ct); + } + catch (RepositoryException e) + { + if (e.Message.StartsWith(RepositoryException.IdNotUnique)) + ThrowError(e.Message, 409); + } + catch (Exception e) + { + _logger.LogCritical("P8.crit - Error in endpoint {endpointName}: {msg}", Name, e.Message); + throw; + } } } diff --git a/Poort8.Dataspace.API/Resources/DeleteResource/Endpoint.cs b/Poort8.Dataspace.API/Resources/DeleteResource/Endpoint.cs index 8f80a08..94a82ad 100644 --- a/Poort8.Dataspace.API/Resources/DeleteResource/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/DeleteResource/Endpoint.cs @@ -22,6 +22,13 @@ public override void Configure() { Delete($"/api/{Name.ToLower()}/{{id}}"); Options(x => x.WithTags(Name)); + Description(x => + { + x.ClearDefaultProduces(200); + x.Produces(204); + x.Produces(404); + }); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.DeleteResourcesPolicy); } diff --git a/Poort8.Dataspace.API/Resources/GetResourceById/Endpoint.cs b/Poort8.Dataspace.API/Resources/GetResourceById/Endpoint.cs index ee0d7f6..0585336 100644 --- a/Poort8.Dataspace.API/Resources/GetResourceById/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/GetResourceById/Endpoint.cs @@ -22,6 +22,8 @@ public override void Configure() { Get($"/api/{Name.ToLower()}/{{id}}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.ReadResourcesPolicy); } diff --git a/Poort8.Dataspace.API/Resources/RemoveResourceFromResourceGroup/Endpoint.cs b/Poort8.Dataspace.API/Resources/RemoveResourceFromResourceGroup/Endpoint.cs index 64f1c54..dba46b0 100644 --- a/Poort8.Dataspace.API/Resources/RemoveResourceFromResourceGroup/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/RemoveResourceFromResourceGroup/Endpoint.cs @@ -6,7 +6,7 @@ namespace Poort8.Dataspace.API.Resources.RemoveResourceFromResourceGroup; public class Endpoint : EndpointWithoutRequest { - public const string Name = "ResourceGroups"; + public const string Name = "Resource Groups"; public const string NameId = "resourceGroupId"; public const string NameChild = "Resources"; public const string NameChildId = "resourceId"; @@ -24,8 +24,10 @@ public Endpoint( public override void Configure() { - Delete("/api/" + Name.ToLower() + "/{" + NameId + "}/" + NameChild.ToLower() + "/{" + NameChildId + "}"); + Delete("/api/" + Name.ToLower().Replace(" ", "") + "/{" + NameId + "}/" + NameChild.ToLower() + "/{" + NameChildId + "}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.DeleteResourcesPolicy); Summary(s => { s.Summary = EndpointSummary; }); diff --git a/Poort8.Dataspace.API/Resources/UpdateResource/Endpoint.cs b/Poort8.Dataspace.API/Resources/UpdateResource/Endpoint.cs index a2c7903..232a020 100644 --- a/Poort8.Dataspace.API/Resources/UpdateResource/Endpoint.cs +++ b/Poort8.Dataspace.API/Resources/UpdateResource/Endpoint.cs @@ -5,7 +5,7 @@ namespace Poort8.Dataspace.API.Resources.UpdateResource; -public class Endpoint : Endpoint +public class Endpoint : Endpoint { public const string Name = "Resources"; private readonly ILogger _logger; @@ -23,6 +23,8 @@ public override void Configure() { Put($"/api/{Name.ToLower()}"); Options(x => x.WithTags(Name)); + Description(x => x.Produces(404)); + AuthSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt); Policies(AuthenticationConstants.WriteResourcesPolicy); } diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.Designer.cs b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.Designer.cs new file mode 100644 index 0000000..2aae2b5 --- /dev/null +++ b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.Designer.cs @@ -0,0 +1,540 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Poort8.Dataspace.AuthorizationRegistry; + +#nullable disable + +namespace Poort8.Dataspace.CoreManager.Migrations +{ + [DbContext(typeof(AuthorizationContext))] + [Migration("20240829145714_ChangedEnforceAudit")] + partial class ChangedEnforceAudit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Audit.EnforceAuditRecord", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Allow") + .HasColumnType("bit"); + + b.Property("Attribute") + .HasColumnType("nvarchar(max)"); + + b.Property("Explain") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IssuerId") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestContext") + .HasColumnType("nvarchar(max)"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ServiceProvider") + .HasColumnType("nvarchar(max)"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Timestamp") + .HasColumnType("datetime2"); + + b.Property("Type") + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("User") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("EnforceAuditRecords"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Audit.EntityAuditRecord", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Entity") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntityType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Timestamp") + .HasColumnType("datetime2"); + + b.Property("User") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("EntityAuditRecords"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.Property("EmployeeId") + .HasColumnType("nvarchar(450)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FamilyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GivenName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganizationIdentifier") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Telephone") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("EmployeeId"); + + b.HasIndex("OrganizationIdentifier"); + + b.ToTable("ArEmployee", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee+EmployeeProperty", b => + { + b.Property("PropertyId") + .HasColumnType("nvarchar(450)"); + + b.Property("EmployeeId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("IsIdentifier") + .HasColumnType("bit"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PropertyId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", b => + { + b.Property("Identifier") + .HasColumnType("nvarchar(450)"); + + b.Property("InvoicingContact") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Representative") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Identifier"); + + b.ToTable("ArOrganization", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization+OrganizationProperty", b => + { + b.Property("PropertyId") + .HasColumnType("nvarchar(450)"); + + b.Property("IsIdentifier") + .HasColumnType("bit"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OrganizationIdentifier") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PropertyId"); + + b.HasIndex("OrganizationIdentifier"); + + b.ToTable("OrganizationProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", b => + { + b.Property("PolicyId") + .HasColumnType("nvarchar(450)"); + + b.Property("Action") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Attribute") + .HasColumnType("nvarchar(max)"); + + b.Property("Expiration") + .HasColumnType("bigint"); + + b.Property("IssuedAt") + .HasColumnType("bigint"); + + b.Property("IssuerId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("License") + .HasColumnType("nvarchar(max)"); + + b.Property("NotBefore") + .HasColumnType("bigint"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Rules") + .HasColumnType("nvarchar(max)"); + + b.Property("ServiceProvider") + .HasColumnType("nvarchar(max)"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PolicyId"); + + b.ToTable("ArPolicy", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy+PolicyProperty", b => + { + b.Property("PropertyId") + .HasColumnType("nvarchar(450)"); + + b.Property("IsIdentifier") + .HasColumnType("bit"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PolicyId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PropertyId"); + + b.HasIndex("PolicyId"); + + b.ToTable("PolicyProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", b => + { + b.Property("ResourceId") + .HasColumnType("nvarchar(450)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("ResourceId"); + + b.ToTable("ArResource", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource+ResourceProperty", b => + { + b.Property("PropertyId") + .HasColumnType("nvarchar(450)"); + + b.Property("IsIdentifier") + .HasColumnType("bit"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PropertyId"); + + b.HasIndex("ResourceId"); + + b.ToTable("ResourceProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", b => + { + b.Property("ResourceGroupId") + .HasColumnType("nvarchar(450)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Provider") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("ResourceGroupId"); + + b.ToTable("ArResourceGroup", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup+ResourceGroupProperty", b => + { + b.Property("PropertyId") + .HasColumnType("nvarchar(450)"); + + b.Property("IsIdentifier") + .HasColumnType("bit"); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ResourceGroupId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("PropertyId"); + + b.HasIndex("ResourceGroupId"); + + b.ToTable("ResourceGroupProperty"); + }); + + modelBuilder.Entity("ResourceResourceGroup", b => + { + b.Property("ResourceGroupId") + .HasColumnType("nvarchar(450)"); + + b.Property("ResourcesResourceId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("ResourceGroupId", "ResourcesResourceId"); + + b.HasIndex("ResourcesResourceId"); + + b.ToTable("ResourceResourceGroup"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", null) + .WithMany("Employees") + .HasForeignKey("OrganizationIdentifier") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee+EmployeeProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", null) + .WithMany("Properties") + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization+OrganizationProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", null) + .WithMany("Properties") + .HasForeignKey("OrganizationIdentifier") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy+PolicyProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", null) + .WithMany("Properties") + .HasForeignKey("PolicyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource+ResourceProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", null) + .WithMany("Properties") + .HasForeignKey("ResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup+ResourceGroupProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", null) + .WithMany("Properties") + .HasForeignKey("ResourceGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ResourceResourceGroup", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", null) + .WithMany() + .HasForeignKey("ResourceGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", null) + .WithMany() + .HasForeignKey("ResourcesResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", b => + { + b.Navigation("Employees"); + + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", b => + { + b.Navigation("Properties"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.cs b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.cs new file mode 100644 index 0000000..c82f92e --- /dev/null +++ b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/20240829145714_ChangedEnforceAudit.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Poort8.Dataspace.CoreManager.Migrations +{ + /// + public partial class ChangedEnforceAudit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Attribute", + table: "EnforceAuditRecords", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "IssuerId", + table: "EnforceAuditRecords", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "RequestContext", + table: "EnforceAuditRecords", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "ServiceProvider", + table: "EnforceAuditRecords", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Type", + table: "EnforceAuditRecords", + type: "nvarchar(max)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Attribute", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "IssuerId", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "RequestContext", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "ServiceProvider", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "Type", + table: "EnforceAuditRecords"); + } + } +} diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/AuthorizationContextModelSnapshot.cs b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/AuthorizationContextModelSnapshot.cs index 55575dc..6a36c1b 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/AuthorizationContextModelSnapshot.cs +++ b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Migrations/AuthorizationContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("ProductVersion", "8.0.8") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -34,14 +34,26 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Allow") .HasColumnType("bit"); + b.Property("Attribute") + .HasColumnType("nvarchar(max)"); + b.Property("Explain") .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("IssuerId") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestContext") + .HasColumnType("nvarchar(max)"); + b.Property("ResourceId") .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("ServiceProvider") + .HasColumnType("nvarchar(max)"); + b.Property("SubjectId") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -49,6 +61,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Timestamp") .HasColumnType("datetime2"); + b.Property("Type") + .HasColumnType("nvarchar(max)"); + b.Property("UseCase") .IsRequired() .HasColumnType("nvarchar(max)"); diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations.csproj b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations.csproj index 7a573c6..fae3f56 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations.csproj +++ b/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations/Poort8.Dataspace.AuthorizationRegistry.SqlServerMigrations.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.Designer.cs b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.Designer.cs new file mode 100644 index 0000000..d591f21 --- /dev/null +++ b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.Designer.cs @@ -0,0 +1,535 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Poort8.Dataspace.AuthorizationRegistry; + +#nullable disable + +namespace Poort8.Dataspace.CoreManager.Migrations +{ + [DbContext(typeof(AuthorizationContext))] + [Migration("20240829145552_ChangedEnforceAudit")] + partial class ChangedEnforceAudit + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.8"); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Audit.EnforceAuditRecord", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Action") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Allow") + .HasColumnType("INTEGER"); + + b.Property("Attribute") + .HasColumnType("TEXT"); + + b.Property("Explain") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssuerId") + .HasColumnType("TEXT"); + + b.Property("RequestContext") + .HasColumnType("TEXT"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServiceProvider") + .HasColumnType("TEXT"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("User") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("EnforceAuditRecords"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Audit.EntityAuditRecord", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Action") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Entity") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("EntityId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("EntityType") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("User") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("EntityAuditRecords"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.Property("EmployeeId") + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FamilyName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GivenName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrganizationIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Telephone") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("EmployeeId"); + + b.HasIndex("OrganizationIdentifier"); + + b.ToTable("ArEmployee", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee+EmployeeProperty", b => + { + b.Property("PropertyId") + .HasColumnType("TEXT"); + + b.Property("EmployeeId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsIdentifier") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PropertyId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", b => + { + b.Property("Identifier") + .HasColumnType("TEXT"); + + b.Property("InvoicingContact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Representative") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Identifier"); + + b.ToTable("ArOrganization", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization+OrganizationProperty", b => + { + b.Property("PropertyId") + .HasColumnType("TEXT"); + + b.Property("IsIdentifier") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OrganizationIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PropertyId"); + + b.HasIndex("OrganizationIdentifier"); + + b.ToTable("OrganizationProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", b => + { + b.Property("PolicyId") + .HasColumnType("TEXT"); + + b.Property("Action") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Attribute") + .HasColumnType("TEXT"); + + b.Property("Expiration") + .HasColumnType("INTEGER"); + + b.Property("IssuedAt") + .HasColumnType("INTEGER"); + + b.Property("IssuerId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("License") + .HasColumnType("TEXT"); + + b.Property("NotBefore") + .HasColumnType("INTEGER"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Rules") + .HasColumnType("TEXT"); + + b.Property("ServiceProvider") + .HasColumnType("TEXT"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PolicyId"); + + b.ToTable("ArPolicy", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy+PolicyProperty", b => + { + b.Property("PropertyId") + .HasColumnType("TEXT"); + + b.Property("IsIdentifier") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PolicyId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PropertyId"); + + b.HasIndex("PolicyId"); + + b.ToTable("PolicyProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", b => + { + b.Property("ResourceId") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ResourceId"); + + b.ToTable("ArResource", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource+ResourceProperty", b => + { + b.Property("PropertyId") + .HasColumnType("TEXT"); + + b.Property("IsIdentifier") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ResourceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PropertyId"); + + b.HasIndex("ResourceId"); + + b.ToTable("ResourceProperty"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", b => + { + b.Property("ResourceGroupId") + .HasColumnType("TEXT"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("TEXT"); + + b.Property("Url") + .HasColumnType("TEXT"); + + b.Property("UseCase") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("ResourceGroupId"); + + b.ToTable("ArResourceGroup", (string)null); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup+ResourceGroupProperty", b => + { + b.Property("PropertyId") + .HasColumnType("TEXT"); + + b.Property("IsIdentifier") + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ResourceGroupId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("PropertyId"); + + b.HasIndex("ResourceGroupId"); + + b.ToTable("ResourceGroupProperty"); + }); + + modelBuilder.Entity("ResourceResourceGroup", b => + { + b.Property("ResourceGroupId") + .HasColumnType("TEXT"); + + b.Property("ResourcesResourceId") + .HasColumnType("TEXT"); + + b.HasKey("ResourceGroupId", "ResourcesResourceId"); + + b.HasIndex("ResourcesResourceId"); + + b.ToTable("ResourceResourceGroup"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", null) + .WithMany("Employees") + .HasForeignKey("OrganizationIdentifier") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee+EmployeeProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", null) + .WithMany("Properties") + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization+OrganizationProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", null) + .WithMany("Properties") + .HasForeignKey("OrganizationIdentifier") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy+PolicyProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", null) + .WithMany("Properties") + .HasForeignKey("PolicyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource+ResourceProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", null) + .WithMany("Properties") + .HasForeignKey("ResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup+ResourceGroupProperty", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", null) + .WithMany("Properties") + .HasForeignKey("ResourceGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ResourceResourceGroup", b => + { + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", null) + .WithMany() + .HasForeignKey("ResourceGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", null) + .WithMany() + .HasForeignKey("ResourcesResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Employee", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Organization", b => + { + b.Navigation("Employees"); + + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Policy", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.Resource", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Entities.ResourceGroup", b => + { + b.Navigation("Properties"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.cs b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.cs new file mode 100644 index 0000000..6fedc05 --- /dev/null +++ b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/20240829145552_ChangedEnforceAudit.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Poort8.Dataspace.CoreManager.Migrations +{ + /// + public partial class ChangedEnforceAudit : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Attribute", + table: "EnforceAuditRecords", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "IssuerId", + table: "EnforceAuditRecords", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "RequestContext", + table: "EnforceAuditRecords", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "ServiceProvider", + table: "EnforceAuditRecords", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "Type", + table: "EnforceAuditRecords", + type: "TEXT", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Attribute", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "IssuerId", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "RequestContext", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "ServiceProvider", + table: "EnforceAuditRecords"); + + migrationBuilder.DropColumn( + name: "Type", + table: "EnforceAuditRecords"); + } + } +} diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/AuthorizationContextModelSnapshot.cs b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/AuthorizationContextModelSnapshot.cs index 6777375..9d407c6 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/AuthorizationContextModelSnapshot.cs +++ b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Migrations/AuthorizationContextModelSnapshot.cs @@ -15,7 +15,7 @@ partial class AuthorizationContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.8"); modelBuilder.Entity("Poort8.Dataspace.AuthorizationRegistry.Audit.EnforceAuditRecord", b => { @@ -29,14 +29,26 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Allow") .HasColumnType("INTEGER"); + b.Property("Attribute") + .HasColumnType("TEXT"); + b.Property("Explain") .IsRequired() .HasColumnType("TEXT"); + b.Property("IssuerId") + .HasColumnType("TEXT"); + + b.Property("RequestContext") + .HasColumnType("TEXT"); + b.Property("ResourceId") .IsRequired() .HasColumnType("TEXT"); + b.Property("ServiceProvider") + .HasColumnType("TEXT"); + b.Property("SubjectId") .IsRequired() .HasColumnType("TEXT"); @@ -44,6 +56,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Timestamp") .HasColumnType("TEXT"); + b.Property("Type") + .HasColumnType("TEXT"); + b.Property("UseCase") .IsRequired() .HasColumnType("TEXT"); diff --git a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations.csproj b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations.csproj index 7a573c6..fae3f56 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations.csproj +++ b/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations/Poort8.Dataspace.AuthorizationRegistry.SqliteMigrations.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/Poort8.Dataspace.AuthorizationRegistry.Tests/AuditTests.cs b/Poort8.Dataspace.AuthorizationRegistry.Tests/AuditTests.cs index f55874a..7c3a394 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.Tests/AuditTests.cs +++ b/Poort8.Dataspace.AuthorizationRegistry.Tests/AuditTests.cs @@ -22,11 +22,12 @@ public AuditTests() serviceCollection.AddSingleton(new HttpContextAccessor() { HttpContext = new DefaultHttpContext() { User = claimsPrincipal } }); _serviceProvider = serviceCollection.BuildServiceProvider(); - _authorizationRegistry = _serviceProvider.GetRequiredService(); var factory = _serviceProvider.GetRequiredService>(); using var context = factory.CreateDbContext(); context.Database.Migrate(); + + _authorizationRegistry = _serviceProvider.GetRequiredService(); } [Fact] @@ -37,10 +38,10 @@ public async Task GetAuditRecords() var auditRecords = await _authorizationRegistry.GetEntityAuditRecords(); Assert.NotNull(auditRecords); - Assert.Single(auditRecords.Where(a => + Assert.Single(auditRecords, a => a.EntityId == organizationEntity.Identifier && a.EntityType == "Organization" && - a.Action == "Added")); + a.Action == "Added"); } [Fact] diff --git a/Poort8.Dataspace.AuthorizationRegistry.Tests/Fakes/FakeRepository.cs b/Poort8.Dataspace.AuthorizationRegistry.Tests/Fakes/FakeRepository.cs index 84906c8..e01dd78 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.Tests/Fakes/FakeRepository.cs +++ b/Poort8.Dataspace.AuthorizationRegistry.Tests/Fakes/FakeRepository.cs @@ -8,6 +8,7 @@ namespace Poort8.Dataspace.AuthorizationRegistry.Tests.Fakes; public class FakeRepository : IRepository { private readonly List _organizations = new(); + private readonly List _employees = new(); private readonly List _resourceGroups = new(); private readonly List _resources = new(); private readonly List _policies = new(); @@ -74,7 +75,7 @@ public Task DeleteEmployee(string employeeId) public Task ReadOrganization(string identifier) { - throw new NotImplementedException(); + return Task.FromResult(_organizations.FirstOrDefault(p => p.Identifier == identifier)); } public Task UpdateOrganization(Organization organization) @@ -91,7 +92,7 @@ public Task DeleteOrganization(string identifier) public Task ReadEmployee(string employeeId) { - throw new NotImplementedException(); + return Task.FromResult(_employees.FirstOrDefault(p => p.EmployeeId == employeeId)); } public Task> ReadEmployees(string? useCase, string? organizationId = null, string? familyName = null, string? email = null, string? propertyKey = null, string? propertyValue = null) @@ -168,7 +169,7 @@ public Task AddNewResourceToResourceGroup(string resourceGroupId, Reso public Task ReadResource(string resourceId) { - throw new NotImplementedException(); + return Task.FromResult(_resources.FirstOrDefault(p => p.ResourceId == resourceId)); } public Task> ReadResources(string? useCase, string? name = null, string? propertyKey = null, string? propertyValue = null) @@ -219,7 +220,7 @@ public Task> ReadEnforceAuditRecords(int numbe throw new NotImplementedException(); } - public Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains = null) + public Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains, string? issuerId, string? serviceProvider, string? type, string? attribute, string? requestContext) { return Task.FromResult(new EnforceAuditRecord(user, useCase, subjectId, resourceId, action, allow, explains)); } diff --git a/Poort8.Dataspace.AuthorizationRegistry.Tests/Poort8.Dataspace.AuthorizationRegistry.Tests.csproj b/Poort8.Dataspace.AuthorizationRegistry.Tests/Poort8.Dataspace.AuthorizationRegistry.Tests.csproj index 26ff0c0..afe57d4 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.Tests/Poort8.Dataspace.AuthorizationRegistry.Tests.csproj +++ b/Poort8.Dataspace.AuthorizationRegistry.Tests/Poort8.Dataspace.AuthorizationRegistry.Tests.csproj @@ -1,7 +1,7 @@ - + - net8.0 + net9.0 enable enable false @@ -13,10 +13,12 @@ - - - - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Poort8.Dataspace.AuthorizationRegistry.Tests/RepositoryTests.cs b/Poort8.Dataspace.AuthorizationRegistry.Tests/RepositoryTests.cs index 0a33eef..616d922 100644 --- a/Poort8.Dataspace.AuthorizationRegistry.Tests/RepositoryTests.cs +++ b/Poort8.Dataspace.AuthorizationRegistry.Tests/RepositoryTests.cs @@ -16,11 +16,12 @@ public RepositoryTests() var serviceCollection = new ServiceCollection(); serviceCollection.AddAuthorizationRegistrySqlite(options => options.ConnectionString = $"Data Source={Guid.NewGuid()}.db"); _serviceProvider = serviceCollection.BuildServiceProvider(); - _authorizationRegistry = _serviceProvider.GetRequiredService(); var factory = _serviceProvider.GetRequiredService>(); using var context = factory.CreateDbContext(); context.Database.Migrate(); + + _authorizationRegistry = _serviceProvider.GetRequiredService(); } [Fact] diff --git a/Poort8.Dataspace.AuthorizationRegistry/Audit/EnforceAuditRecord.cs b/Poort8.Dataspace.AuthorizationRegistry/Audit/EnforceAuditRecord.cs index 39bf065..28359ca 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/Audit/EnforceAuditRecord.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/Audit/EnforceAuditRecord.cs @@ -14,6 +14,11 @@ public class EnforceAuditRecord public string Action { get; set; } public bool Allow { get; set; } public string Explain { get; set; } + public string? IssuerId { get; set; } + public string? ServiceProvider { get; set; } + public string? Type { get; set; } + public string? Attribute { get; set; } + public string? RequestContext { get; set; } public EnforceAuditRecord(string id, DateTime timestamp, string user, string useCase, string subjectId, string resourceId, string action, bool allow, string explain) { diff --git a/Poort8.Dataspace.AuthorizationRegistry/AuthorizationRegistry.cs b/Poort8.Dataspace.AuthorizationRegistry/AuthorizationRegistry.cs index ac8b187..73380d7 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/AuthorizationRegistry.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/AuthorizationRegistry.cs @@ -4,21 +4,21 @@ using Poort8.Dataspace.AuthorizationRegistry.Entities; using Poort8.Dataspace.AuthorizationRegistry.Exceptions; using Poort8.Dataspace.AuthorizationRegistry.Extensions; -using System.Security.Claims; +using System.Text.Json; namespace Poort8.Dataspace.AuthorizationRegistry; public class AuthorizationRegistry : IAuthorizationRegistry { private readonly IRepository _repository; private readonly IEnforcer _enforcer; - private readonly ClaimsPrincipal? _currentUser; + private readonly IHttpContextAccessor? _httpContextAccessor; //TODO: Add tests for group reset in all cases. public AuthorizationRegistry(IRepository repository, IHttpContextAccessor? httpContextAccessor = null) { _repository = repository; - _currentUser = httpContextAccessor?.HttpContext?.User; + _httpContextAccessor = httpContextAccessor; _enforcer = new Enforcer(EnforcerModel.Create()); @@ -45,6 +45,10 @@ private async void LoadAllPoliciesAndGroupsFromStorage() public async Task CreateOrganization(Organization organization) { + var existingEntity = await ReadOrganization(organization.Identifier); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: Organization with identifier {organization.Identifier} already exists."); + var organizationEntity = await _repository.CreateOrganization(organization); await ResetSubjectGroup(); return organizationEntity; @@ -52,6 +56,10 @@ public async Task CreateOrganization(Organization organization) public async Task CreateResourceGroup(ResourceGroup resourceGroup) { + var existingEntity = await ReadResourceGroup(resourceGroup.ResourceGroupId); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: ResourceGroup with id {resourceGroup.ResourceGroupId} already exists."); + var resourceGroupEntity = await _repository.CreateResourceGroup(resourceGroup); await ResetResourceGroup(); return resourceGroupEntity; @@ -59,6 +67,10 @@ public async Task CreateResourceGroup(ResourceGroup resourceGroup public async Task CreateResourceGroupWithExistingResources(ResourceGroup resourceGroup, ICollection resourceIds) { + var existingEntity = await ReadResourceGroup(resourceGroup.ResourceGroupId); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: ResourceGroup with id {resourceGroup.ResourceGroupId} already exists."); + var resourceGroupEntity = await CreateResourceGroup(resourceGroup); foreach (var resourceId in resourceIds) @@ -92,6 +104,10 @@ public async Task CreatePolicy(Policy policy) public async Task AddNewEmployeeToOrganization(string organizationId, Employee employee) { + var existingEntity = await ReadEmployee(employee.EmployeeId); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: Employee with id {employee.EmployeeId} already exists."); + var employeeEntity = await _repository.AddNewEmployeeToOrganization(organizationId, employee); await ResetSubjectGroup(); return employeeEntity; @@ -99,6 +115,10 @@ public async Task AddNewEmployeeToOrganization(string organizationId, public async Task CreateResource(Resource resource) { + var existingEntity = await ReadResource(resource.ResourceId); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: Resource with id {resource.ResourceId} already exists."); + var resourceEntity = await _repository.CreateResource(resource); await ResetResourceGroup(); return resourceEntity; @@ -113,6 +133,10 @@ public async Task AddExistingResourceToResourceGroup(string resourceGr public async Task AddNewResourceToResourceGroup(string resourceGroupId, Resource resource) { + var existingEntity = await ReadResource(resource.ResourceId); + if (existingEntity != null) + throw new RepositoryException($"{RepositoryException.IdNotUnique}: Resource with id {resource.ResourceId} already exists."); + var resourceEntity = await _repository.AddNewResourceToResourceGroup(resourceGroupId, resource); await ResetResourceGroup(); return resourceEntity; @@ -324,8 +348,8 @@ public async Task Enforce(string subjectId, string resourceId, string acti var now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(); var allowed = await _enforcer.EnforceAsync(useCase.ToLower(), now, subjectId.ToLower(), resourceId.ToLower(), action.ToLower()); - var user = _currentUser?.Identity?.Name ?? "unknown"; - await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed); + var user = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "unknown"; + await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, null, null, null, null, null, null); return allowed; } @@ -342,8 +366,8 @@ public async Task Enforce(string subjectId, string resourceId, string acti explainPolicies.Add(explainPolicy); } - var user = _currentUser?.Identity?.Name ?? "unknown"; - await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies); + var user = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "unknown"; + await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies, null, null, null, null, null); return (allowed, explainPolicies); } @@ -361,8 +385,8 @@ public async Task Enforce(string subjectId, string resourceId, string acti explainPolicies.Add(explainPolicy); } - var user = _currentUser?.Identity?.Name ?? "unknown"; - await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies); + var user = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "unknown"; + await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies, issuerId, serviceProvider, type, attribute, null); return (allowed, explainPolicies); } @@ -381,8 +405,8 @@ public async Task Enforce(string subjectId, string resourceId, string acti explainPolicies.Add(explainPolicy); } - var user = _currentUser?.Identity?.Name ?? "unknown"; - await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies); + var user = _httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "unknown"; + await _repository.CreateEnforceAuditRecord(user, useCase, subjectId, resourceId, action, allowed, explainPolicies, issuerId, serviceProvider, type, attribute, JsonSerializer.Serialize(requestContext)); return (allowed, explainPolicies); } diff --git a/Poort8.Dataspace.AuthorizationRegistry/Exceptions/EnforcerException.cs b/Poort8.Dataspace.AuthorizationRegistry/Exceptions/EnforcerException.cs index e8cc189..881484d 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/Exceptions/EnforcerException.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/Exceptions/EnforcerException.cs @@ -1,6 +1,6 @@ namespace Poort8.Dataspace.AuthorizationRegistry.Exceptions; [Serializable] -internal class EnforcerException : Exception +public class EnforcerException : Exception { public EnforcerException() { diff --git a/Poort8.Dataspace.AuthorizationRegistry/Exceptions/RepositoryException.cs b/Poort8.Dataspace.AuthorizationRegistry/Exceptions/RepositoryException.cs index 2381b01..fa70a92 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/Exceptions/RepositoryException.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/Exceptions/RepositoryException.cs @@ -1,7 +1,9 @@ namespace Poort8.Dataspace.AuthorizationRegistry.Exceptions; [Serializable] -internal class RepositoryException : Exception +public class RepositoryException : Exception { + public const string IdNotUnique = "The id is not unique"; + public RepositoryException() { } diff --git a/Poort8.Dataspace.AuthorizationRegistry/IRepository.cs b/Poort8.Dataspace.AuthorizationRegistry/IRepository.cs index b66fea9..57c455c 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/IRepository.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/IRepository.cs @@ -46,5 +46,5 @@ public interface IRepository //Audit Task> ReadEntityAuditRecords(int numberOfRecords = 100); Task> ReadEnforceAuditRecords(int numberOfRecords = 100); - Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains = null); + Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains, string? issuerId, string? serviceProvider, string? type, string? attribute, string? requestContext); } \ No newline at end of file diff --git a/Poort8.Dataspace.AuthorizationRegistry/Poort8.Dataspace.AuthorizationRegistry.csproj b/Poort8.Dataspace.AuthorizationRegistry/Poort8.Dataspace.AuthorizationRegistry.csproj index c119079..4a94f87 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/Poort8.Dataspace.AuthorizationRegistry.csproj +++ b/Poort8.Dataspace.AuthorizationRegistry/Poort8.Dataspace.AuthorizationRegistry.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable true @@ -10,9 +10,9 @@ - - - + + + diff --git a/Poort8.Dataspace.AuthorizationRegistry/Repository.cs b/Poort8.Dataspace.AuthorizationRegistry/Repository.cs index 8873bbb..516a892 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/Repository.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/Repository.cs @@ -648,11 +648,18 @@ public async Task> ReadEnforceAuditRecords(int .ToListAsync(); } - public async Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains = null) + public async Task CreateEnforceAuditRecord(string user, string useCase, string subjectId, string resourceId, string action, bool allow, List? explains, string? issuerId, string? serviceProvider, string? type, string? attribute, string? requestContext) { using var context = _contextFactory.CreateDbContext(); - var record = new EnforceAuditRecord(user, useCase, subjectId, resourceId, action, allow, explains); + var record = new EnforceAuditRecord(user, useCase, subjectId, resourceId, action, allow, explains) + { + IssuerId = issuerId, + ServiceProvider = serviceProvider, + Type = type, + Attribute = attribute, + RequestContext = requestContext + }; var enforceAuditRecord = await context.AddAsync(record); await context.SaveChangesAsync(); diff --git a/Poort8.Dataspace.AuthorizationRegistry/UseCases.cs b/Poort8.Dataspace.AuthorizationRegistry/UseCases.cs index 5d0af1d..1628f2b 100644 --- a/Poort8.Dataspace.AuthorizationRegistry/UseCases.cs +++ b/Poort8.Dataspace.AuthorizationRegistry/UseCases.cs @@ -3,18 +3,20 @@ namespace Poort8.Dataspace.AuthorizationRegistry; public class UseCases { - private static readonly Dictionary _authorizationModels = new() + public static readonly Dictionary AuthorizationModels = new() { { "hwct", "default" }, { "ishare", "ishare" }, { "isharerules", "isharerules" }, { "gir", "isharerules" }, - { "noodlebarscopes", "default"} + { "noodlebarscopes", "default"}, + { "dvu-mock", "ishare" }, + { "efti", "ishare" } }; public static string GetAuthorizationModel(string useCase) { - return _authorizationModels.TryGetValue(useCase.ToLower(), out var authModel) ? authModel : "default"; + return AuthorizationModels.TryGetValue(useCase.ToLower(), out var authModel) ? authModel : "default"; } public static string GetPolicyType(Policy policy) diff --git a/Poort8.Dataspace.CoreManager.Tests/OpenApiServiceTests.cs b/Poort8.Dataspace.CoreManager.Tests/OpenApiServiceTests.cs new file mode 100644 index 0000000..e3bc401 --- /dev/null +++ b/Poort8.Dataspace.CoreManager.Tests/OpenApiServiceTests.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.Caching.Hybrid; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Poort8.Dataspace.CoreManager.Services; +using static Poort8.Dataspace.CoreManager.Catalog.Index; + +namespace Poort8.Dataspace.CoreManager.Tests; + +public class OpenApiServiceTests +{ + private const string _sampleUrl = "https://petstore3.swagger.io/api/v3/openapi.json"; + private readonly OpenApiService _openApiService; + + public OpenApiServiceTests() + { + var logger = Substitute.For>(); + var httpClientFactory = Substitute.For(); + httpClientFactory.CreateClient().Returns(new HttpClient()); + + var services = new ServiceCollection(); +#pragma warning disable EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + services.AddHybridCache(); +#pragma warning restore EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + var serviceProvider = services.BuildServiceProvider(); + var cache = serviceProvider.GetRequiredService(); + + _openApiService = new OpenApiService(logger, httpClientFactory, cache); + } + + [Fact] + public async Task GetOpenApiDefinition() + { + var result = await _openApiService.GetOpenApiDefinition(_sampleUrl); + + Assert.NotNull(result); + } + + [Fact] + public async Task GetDataSourceViewModel() + { + var result = await _openApiService.GetDataSourceViewModel(_sampleUrl, "organization", "logoUrl"); + + Assert.NotNull(result); + Assert.IsType(result); + } + + [Fact] + public async Task GetOpenApiDefinitionJson() + { + var result = await _openApiService.GetOpenApiDefinitionJson(_sampleUrl); + + Assert.NotNull(result); + } +} diff --git a/Poort8.Dataspace.CoreManager.Tests/Poort8.Dataspace.CoreManager.Tests.csproj b/Poort8.Dataspace.CoreManager.Tests/Poort8.Dataspace.CoreManager.Tests.csproj new file mode 100644 index 0000000..a269389 --- /dev/null +++ b/Poort8.Dataspace.CoreManager.Tests/Poort8.Dataspace.CoreManager.Tests.csproj @@ -0,0 +1,36 @@ + + + + net9.0 + enable + enable + true + true + Minimum + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor b/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor index ca91f60..f52f07e 100644 --- a/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor +++ b/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor @@ -8,28 +8,31 @@ Authorization register - Audit logs - - - + + - - + + + + + - + + + + + - - - + + - - - + + - - + diff --git a/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor.cs b/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor.cs index 3d467d3..ded8c85 100644 --- a/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor.cs +++ b/Poort8.Dataspace.CoreManager/ARAuditLogs/Index.razor.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Components; using Poort8.Dataspace.AuthorizationRegistry; using Poort8.Dataspace.AuthorizationRegistry.Audit; +using Poort8.Dataspace.CoreManager.Services; namespace Poort8.Dataspace.CoreManager.ARAuditLogs; @@ -8,6 +9,8 @@ public partial class Index : ComponentBase { [Inject] public required IAuthorizationRegistry AuthorizationRegistry { get; set; } + [Inject] + public required StateContainer StateContainer { get; set; } public IReadOnlyList? EntityAuditRecords; public IReadOnlyList? EnforceAuditRecords; @@ -17,4 +20,12 @@ protected override async Task OnInitializedAsync() EntityAuditRecords = [.. (await AuthorizationRegistry.GetEntityAuditRecords()).OrderByDescending(o => o.Timestamp)]; EnforceAuditRecords = [.. (await AuthorizationRegistry.GetEnforceAuditRecords()).OrderByDescending(o => o.Timestamp)]; } + + private string GetOROrganizationName(string? identifier) + { + if (string.IsNullOrEmpty(identifier)) + return string.Empty; + else + return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; + } } diff --git a/Poort8.Dataspace.CoreManager/AROrganizations/Details.razor b/Poort8.Dataspace.CoreManager/AROrganizations/Details.razor index 52a7a2c..608b468 100644 --- a/Poort8.Dataspace.CoreManager/AROrganizations/Details.razor +++ b/Poort8.Dataspace.CoreManager/AROrganizations/Details.razor @@ -26,7 +26,7 @@ New @Options.Value.EmployeeAlternativeName - + diff --git a/Poort8.Dataspace.CoreManager/AROrganizations/Dialogs/AddOrganizationDialog.razor b/Poort8.Dataspace.CoreManager/AROrganizations/Dialogs/AddOrganizationDialog.razor index 553de6c..0ef77da 100644 --- a/Poort8.Dataspace.CoreManager/AROrganizations/Dialogs/AddOrganizationDialog.razor +++ b/Poort8.Dataspace.CoreManager/AROrganizations/Dialogs/AddOrganizationDialog.razor @@ -1,6 +1,6 @@ @using AROrganization = Poort8.Dataspace.AuthorizationRegistry.Entities.Organization; @using OROrganization = Poort8.Dataspace.OrganizationRegistry.Organization; -@implements IDialogContentComponent<(AROrganization AROrganization, IReadOnlyList OROrganizations)> +@implements IDialogContentComponent<(AROrganization AROrganization, List OROrganizations)> @@ -10,7 +10,7 @@ @code { [Parameter] - public required (AROrganization AROrganization, IReadOnlyList OROrganizations) Content { get; set; } + public required (AROrganization AROrganization, List OROrganizations) Content { get; set; } OROrganization? selectedOROrganization; } \ No newline at end of file diff --git a/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor b/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor index d045a04..ffa3d63 100644 --- a/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor +++ b/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor @@ -13,7 +13,7 @@ The Organization Registry contains no organizations which you can add } - + diff --git a/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor.cs b/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor.cs index a1cb47e..4ac1843 100644 --- a/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor.cs +++ b/Poort8.Dataspace.CoreManager/AROrganizations/Index.razor.cs @@ -27,7 +27,7 @@ public partial class Index : ComponentBase, IDisposable public required IOptions Options { get; set; } private IReadOnlyList? AROrganizations; - private IReadOnlyList? NotAddedOROrganizations; + private List? NotAddedOROrganizations; private bool NoOrganizations => !(NotAddedOROrganizations?.Count > 0); @@ -67,7 +67,7 @@ private async Task HandleAddNewClicked(DialogResult result) { if (!result.Cancelled && result.Data is not null) { - await AuthorizationRegistry.CreateOrganization((((AROrganization AROrganization, IReadOnlyList))result.Data).AROrganization); + await AuthorizationRegistry.CreateOrganization((((AROrganization AROrganization, List))result.Data).AROrganization); await FetchOrganizations(); } } diff --git a/Poort8.Dataspace.CoreManager/ARPolicies/Details.razor.cs b/Poort8.Dataspace.CoreManager/ARPolicies/Details.razor.cs index 11d52c5..d58cd7d 100644 --- a/Poort8.Dataspace.CoreManager/ARPolicies/Details.razor.cs +++ b/Poort8.Dataspace.CoreManager/ARPolicies/Details.razor.cs @@ -80,6 +80,9 @@ public void Dispose() private string GetOROrganizationName(string? identifier) { - return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; + if (string.IsNullOrEmpty(identifier)) + return string.Empty; + else + return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; } } \ No newline at end of file diff --git a/Poort8.Dataspace.CoreManager/ARPolicies/Dialogs/PolicyDialog.razor b/Poort8.Dataspace.CoreManager/ARPolicies/Dialogs/PolicyDialog.razor index ee2da10..bf1c7e0 100644 --- a/Poort8.Dataspace.CoreManager/ARPolicies/Dialogs/PolicyDialog.razor +++ b/Poort8.Dataspace.CoreManager/ARPolicies/Dialogs/PolicyDialog.razor @@ -3,7 +3,7 @@ @using OROrganization = Poort8.Dataspace.OrganizationRegistry.Organization; @implements IDialogContentComponent - + @if (StateContainer.CurrentOROrganizations is not null && StateContainer.CurrentOROrganizations.Any(o => o.Identifier.Equals(Content.IssuerId))) { @@ -30,17 +30,48 @@ else } - - - - +@if (selectedUseCase is not null && selectedUseCase.Actions.Any()) +{ + +} +else +{ + +} +@if (selectedUseCase is not null && selectedUseCase.ResourceTypes.Any()) +{ + +} +else +{ + +} +@if (selectedUseCase is not null && selectedUseCase.ResourceIdentifiers.Any()) +{ + +} +else +{ + +} +@if (selectedUseCase is not null && selectedUseCase.ResourceAttributes.Any()) +{ + +} +else +{ + +} @code { [Parameter] public required Policy Content { get; set; } [Inject] public required StateContainer StateContainer { get; set; } + [Inject] + public required UseCaseService UseCaseService { get; set; } + private UseCase? selectedUseCase; private OROrganization? selectedIssuerOROrganization; private OROrganization? selectedActorOROrganization; private OROrganization? selectedServiceProviderOROrganization; diff --git a/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor b/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor index 5c27dc5..5f98eb6 100644 --- a/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor +++ b/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor @@ -13,7 +13,8 @@ The Organization Registry contains no organizations which you can add policies to } - + + diff --git a/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor.cs b/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor.cs index a8a5414..535a55c 100644 --- a/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor.cs +++ b/Poort8.Dataspace.CoreManager/ARPolicies/Index.razor.cs @@ -33,7 +33,7 @@ protected override async Task OnInitializedAsync() { StateContainer.OnChange += StateHasChanged; - Policies = await AuthorizationRegistry.ReadPolicies(Options.Value.UseCase); + Policies = await AuthorizationRegistry.ReadPolicies(); StateContainer.CurrentOROrganizations = await OrganizationRegistry.ReadOrganizations(); } @@ -69,7 +69,7 @@ private async Task HandleAddNewClicked(DialogResult result) var policy = (Policy)result.Data; policy.IssuedAt = DateTimeOffset.Now.ToUnixTimeSeconds(); await AuthorizationRegistry.CreatePolicy(policy); - Policies = await AuthorizationRegistry.ReadPolicies(Options.Value.UseCase); + Policies = await AuthorizationRegistry.ReadPolicies(); } } @@ -103,7 +103,7 @@ private async Task HandleSavePropertiesClicked(DialogResult result) { await AuthorizationRegistry.UpdatePolicy((Policy)result.Data); } - Policies = await AuthorizationRegistry.ReadPolicies(Options.Value.UseCase); + Policies = await AuthorizationRegistry.ReadPolicies(); } private async Task DeleteClicked(Policy policy) @@ -118,7 +118,7 @@ private async Task DeleteClicked(Policy policy) if (!result.Cancelled) { await AuthorizationRegistry.DeletePolicy(policy.PolicyId); - Policies = await AuthorizationRegistry.ReadPolicies(Options.Value.UseCase); + Policies = await AuthorizationRegistry.ReadPolicies(); } } @@ -139,6 +139,9 @@ public void Dispose() private string GetOROrganizationName(string? identifier) { - return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; + if (string.IsNullOrEmpty(identifier)) + return string.Empty; + else + return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; } } diff --git a/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor b/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor index 6d41ce5..07a14f7 100644 --- a/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor +++ b/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor @@ -28,7 +28,7 @@ Add Existing @Options.Value.ResourceAlternativeName - + diff --git a/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor.cs b/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor.cs index 62049b8..923b209 100644 --- a/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor.cs +++ b/Poort8.Dataspace.CoreManager/ARResourceGroups/Details.razor.cs @@ -226,6 +226,9 @@ public void Dispose() private string GetOROrganizationName(string? identifier) { - return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; + if (string.IsNullOrEmpty(identifier)) + return string.Empty; + else + return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; } } \ No newline at end of file diff --git a/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor b/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor index 062b233..3fe4079 100644 --- a/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor +++ b/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor @@ -13,7 +13,7 @@ The Organization Registry contains no organizations which you can add @Options.Value.ResourceGroupAlternativeNamePlural to } - + diff --git a/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor.cs b/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor.cs index e29a181..dbf1808 100644 --- a/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor.cs +++ b/Poort8.Dataspace.CoreManager/ARResourceGroups/Index.razor.cs @@ -132,6 +132,9 @@ public void Dispose() private string GetOROrganizationName(string? identifier) { - return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; + if (string.IsNullOrEmpty(identifier)) + return string.Empty; + else + return (StateContainer.CurrentOROrganizations?.FirstOrDefault(o => o.Identifier == identifier)?.Name + " " ?? string.Empty) + $"({identifier})"; } } diff --git a/Poort8.Dataspace.CoreManager/Catalog/Index.razor b/Poort8.Dataspace.CoreManager/Catalog/Index.razor new file mode 100644 index 0000000..a153ffe --- /dev/null +++ b/Poort8.Dataspace.CoreManager/Catalog/Index.razor @@ -0,0 +1,73 @@ +@page "/catalog" +@rendermode @(new InteractiveServerRenderMode(prerender: false)) + +Catalog + + + Catalog + +

This page displays a catalog of available data services within the dataspace. The catalog showcases various data services, each with an OpenAPI or Swagger specification that defines its available operations and endpoints. To ensure a seamless integration experience, users can add their data services directly to the catalog.

+ +

Adding Your Data Service

+
    +
  1. + Capabilities URL: + Go to the organization details in the Organization register and enter the URL to your data service's OpenAPI/Swagger definition in the + Capabilities URL field. For example: + https://your-service-domain.com/api/swagger.json. +
      +
    • If your service uses the iSHARE standard, these capabilities are supported but are not automatically processed.
    • +
    • For data services following the W3C DCAT standard, you can enter the value for dcat:endpointDescription.
    • +
    +
  2. +
  3. + Logo URL: You may also add your logo, which will appear in the catalog, helping your service stand out visually. +
  4. +
+ +

Once your data service endpoint is added with a valid OpenAPI/Swagger definition, it will be listed in this catalog alongside other available services, making it discoverable to users in the dataspace.

+ + + @foreach (var dataSource in DataSources) + { + + +
+
+ + + + API version: @dataSource.Version + + + + @dataSource.Type + +
+ +

@dataSource.Organization

+
@dataSource.Title
+
+ @dataSource.DescriptionMarkdown +
+
+ +
+ @dataSource.Host + +
+ + Terms + License + Contact + Docs + +
+ +
+ Open API reference +
+
+ } +
+
\ No newline at end of file diff --git a/Poort8.Dataspace.CoreManager/Catalog/Index.razor.cs b/Poort8.Dataspace.CoreManager/Catalog/Index.razor.cs new file mode 100644 index 0000000..2b65e3f --- /dev/null +++ b/Poort8.Dataspace.CoreManager/Catalog/Index.razor.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Components; +using Poort8.Dataspace.CoreManager.Services; +using Poort8.Dataspace.OrganizationRegistry; +namespace Poort8.Dataspace.CoreManager.Catalog; + +public partial class Index : ComponentBase +{ + private const string _noLogoUrl = "https://fakeimg.pl/50x50?text=Logo&font=bebas"; + [Inject] + public required IOrganizationRegistry OrganizationRegistry { get; set; } + [Inject] + public required NavigationManager NavigationManager { get; set; } + [Inject] + public required OpenApiService OpenApiService { get; set; } + [Inject] + public required ILogger Logger { get; set; } + public List DataSources { get; private set; } = []; + + protected override async Task OnInitializedAsync() + { + var organizations = await OrganizationRegistry.ReadOrganizations(); + + foreach (var organization in organizations) + { + if (!string.IsNullOrEmpty(organization.AdditionalDetails.CapabilitiesUrl)) + { + var logoUrl = string.IsNullOrEmpty(organization.AdditionalDetails.LogoUrl) ? _noLogoUrl : organization.AdditionalDetails.LogoUrl; + + try + { + var dataSource = await OpenApiService.GetDataSourceViewModel( + organization.AdditionalDetails.CapabilitiesUrl, + organization.Name, + logoUrl); + + if (dataSource != null) + DataSources.Add(dataSource); + } + catch (Exception) + { + Logger.LogError("P8.err - Could not add catalog datasource: {dataSourceUrl}", organization.AdditionalDetails.CapabilitiesUrl); + } + } + } + } + + private void GoToScalar(DataSourceViewModel dataSource) + { + NavigationManager.NavigateTo("/api-reference?url=" + dataSource.Url, true); + } + + public class DataSourceViewModel + { + public required string Type { get; set; } + public string? LogoUrl { get; set; } + public required string Organization { get; set; } + public required string Title { get; set; } + public string? Description { get; set; } + public MarkupString? DescriptionMarkdown { get; set; } + public required string Version { get; set; } + public required string Swagger { get; set; } + public string? Terms { get; set; } + public string? License { get; set; } + public string? Contact { get; set; } + public string? Docs { get; set; } + public required string Host { get; set; } + public required string Url { get; set; } + } +} diff --git a/Poort8.Dataspace.CoreManager/Extensions/ApiReferenceExtension.cs b/Poort8.Dataspace.CoreManager/Extensions/ApiReferenceExtension.cs new file mode 100644 index 0000000..8eb8fa9 --- /dev/null +++ b/Poort8.Dataspace.CoreManager/Extensions/ApiReferenceExtension.cs @@ -0,0 +1,49 @@ +using Poort8.Dataspace.CoreManager.Services; +using System.Text.Json; + +namespace Poort8.Dataspace.CoreManager.Extensions; + +public static class ApiReferenceExtension +{ + public static void MapApiReferenceEndpoints(this IEndpointRouteBuilder app) + { + app.MapGet("/openapi", async (string url, OpenApiService openApiService) => + { + var openApiJson = await openApiService.GetOpenApiDefinitionJson(url); + return Results.Content(openApiJson, "application/json"); + }); + + app.MapGet("/api-reference", async (HttpContext context, string url, OpenApiService openApiService) => + { + var config = new + { + spec = new { url = "openapi?url=" + url }, + servers = new[] { new { url = await openApiService.GetOpenApiDefinitionServer(url) } } + }; + var configJson = JsonSerializer.Serialize(config); + + var htmlContent = $""" + + + + API Reference + + + + + + + + + + """; + + context.Response.ContentType = "text/html"; + await context.Response.WriteAsync(htmlContent); + }); + } +} diff --git a/Poort8.Dataspace.CoreManager/Extensions/AuthenticationExtension.cs b/Poort8.Dataspace.CoreManager/Extensions/AuthenticationExtension.cs index 95b6951..450d048 100644 --- a/Poort8.Dataspace.CoreManager/Extensions/AuthenticationExtension.cs +++ b/Poort8.Dataspace.CoreManager/Extensions/AuthenticationExtension.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; +using Microsoft.IdentityModel.Tokens; using Poort8.Dataspace.Identity; namespace Poort8.Dataspace.CoreManager.Extensions; @@ -23,6 +24,10 @@ public static IServiceCollection AddAuthenticationSchemes(this IServiceCollectio { options.Authority = coreManagerOptions.JwtTokenAuthority; options.Audience = coreManagerOptions.JwtTokenAudience; + options.TokenValidationParameters = new TokenValidationParameters + { + NameClaimType = "organizationId" + }; }) .AddIdentityCookies(); @@ -39,6 +44,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "read:resources") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -49,6 +55,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "write:resources") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -59,6 +66,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "delete:resources") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -69,6 +77,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "read:policies") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -79,6 +88,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "write:policies") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -89,6 +99,7 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "delete:policies") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() @@ -99,10 +110,22 @@ private static void AddPolicies(IServiceCollection services) .RequireAuthenticatedUser() .RequireAssertion(context => context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "read:or-organizations") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "read:or-organizations") || //For Auth0 M2M Action context.User.IsInRole("ManageEntitiesApi")) .Build(); services.AddAuthorizationBuilder() .AddPolicy(AuthenticationConstants.ReadOROrganizationsPolicy, readOROrganizations); + + var readAROrganizations = new AuthorizationPolicyBuilder() + .AddAuthenticationSchemes(AuthenticationConstants.IdentityBearer, AuthenticationConstants.Auth0Jwt) + .RequireAuthenticatedUser() + .RequireAssertion(context => + context.User.HasClaim(claim => claim.Type == "permission" && claim.Value == "read:ar-organizations") || + context.User.HasClaim(claim => claim.Type == "scope" && claim.Value == "trusted-app") || + context.User.IsInRole("ManageEntitiesApi")) + .Build(); + services.AddAuthorizationBuilder() + .AddPolicy(AuthenticationConstants.ReadAROrganizationsPolicy, readAROrganizations); } } diff --git a/Poort8.Dataspace.CoreManager/Home/Home.razor b/Poort8.Dataspace.CoreManager/Home/Home.razor index d415da1..4869b9f 100644 --- a/Poort8.Dataspace.CoreManager/Home/Home.razor +++ b/Poort8.Dataspace.CoreManager/Home/Home.razor @@ -1,10 +1,10 @@ @page "/" @rendermode InteractiveServer -Noodle Bar +NoodleBar Welcome! -

Welcome to the Noodle Bar.

+

Welcome to the NoodleBar.

diff --git a/Poort8.Dataspace.CoreManager/Layout/App.razor b/Poort8.Dataspace.CoreManager/Layout/App.razor index f66014b..780d0fa 100644 --- a/Poort8.Dataspace.CoreManager/Layout/App.razor +++ b/Poort8.Dataspace.CoreManager/Layout/App.razor @@ -5,8 +5,9 @@ - - + + + diff --git a/Poort8.Dataspace.CoreManager/Layout/MainLayout.razor b/Poort8.Dataspace.CoreManager/Layout/MainLayout.razor index c779bbc..7f480de 100644 --- a/Poort8.Dataspace.CoreManager/Layout/MainLayout.razor +++ b/Poort8.Dataspace.CoreManager/Layout/MainLayout.razor @@ -1,8 +1,9 @@ @inherits LayoutComponentBase + - Noodle Bar + NoodleBar @@ -17,6 +18,7 @@ + diff --git a/Poort8.Dataspace.CoreManager/Layout/NavMenu.razor b/Poort8.Dataspace.CoreManager/Layout/NavMenu.razor index f5613a7..9223b03 100644 --- a/Poort8.Dataspace.CoreManager/Layout/NavMenu.razor +++ b/Poort8.Dataspace.CoreManager/Layout/NavMenu.razor @@ -21,6 +21,7 @@ Policies Audit logs + Catalog diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/AdditionalDetails.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/AdditionalDetails.razor index 4f01cae..d890da4 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/AdditionalDetails.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/AdditionalDetails.razor @@ -6,6 +6,7 @@

Description: @StateContainer.CurrentOROrganization!.AdditionalDetails.Description

Website URL: @StateContainer.CurrentOROrganization.AdditionalDetails.WebsiteUrl

Capabilities URL: @StateContainer.CurrentOROrganization.AdditionalDetails.CapabilitiesUrl

+ To include your service in the NoodleBar Catalog, enter the URL to the OpenAPI/Swagger definition of your data service endpoint. Capabilities conforming to the iSHARE standard are also allowed but are not automatically processed due to limited use. For data services following the W3C DCAT standard, use the value of dcat:endpointDescription.

Logo URL: @StateContainer.CurrentOROrganization.AdditionalDetails.LogoUrl

Company Email: @StateContainer.CurrentOROrganization.AdditionalDetails.CompanyEmail

Company Phone: @StateContainer.CurrentOROrganization.AdditionalDetails.CompanyPhone

diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Agreements.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Agreements.razor index 9f8a282..24c7cfb 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Agreements.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Agreements.razor @@ -2,7 +2,7 @@ New Agreement - + diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/AuthorizationRegistries.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/AuthorizationRegistries.razor index 8a078af..2c6923b 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/AuthorizationRegistries.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/AuthorizationRegistries.razor @@ -2,7 +2,7 @@ New Authorization Register - + diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Certificates.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Certificates.razor index 35996db..cb2ffaf 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Certificates.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Certificates.razor @@ -2,7 +2,7 @@ New Certificate - + diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Roles.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Roles.razor index e8a8951..6e2e0fe 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Roles.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Roles.razor @@ -2,7 +2,7 @@ New Role - + diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Services.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Services.razor index ba7c5ba..46435f7 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Components/Services.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Components/Services.razor @@ -2,7 +2,7 @@ New Service - + diff --git a/Poort8.Dataspace.CoreManager/OROrganizations/Index.razor b/Poort8.Dataspace.CoreManager/OROrganizations/Index.razor index 61b0377..92b6ed6 100644 --- a/Poort8.Dataspace.CoreManager/OROrganizations/Index.razor +++ b/Poort8.Dataspace.CoreManager/OROrganizations/Index.razor @@ -9,7 +9,7 @@ New Organization - + diff --git a/Poort8.Dataspace.CoreManager/Poort8.Dataspace.CoreManager.csproj b/Poort8.Dataspace.CoreManager/Poort8.Dataspace.CoreManager.csproj index 2068c52..9aa9720 100644 --- a/Poort8.Dataspace.CoreManager/Poort8.Dataspace.CoreManager.csproj +++ b/Poort8.Dataspace.CoreManager/Poort8.Dataspace.CoreManager.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable true @@ -13,17 +13,21 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Poort8.Dataspace.CoreManager/Program.cs b/Poort8.Dataspace.CoreManager/Program.cs index b94525f..6fbff6a 100644 --- a/Poort8.Dataspace.CoreManager/Program.cs +++ b/Poort8.Dataspace.CoreManager/Program.cs @@ -1,8 +1,10 @@ +using Azure.Monitor.OpenTelemetry.AspNetCore; using FastEndpoints; using FastEndpoints.Swagger; using Microsoft.FeatureManagement; using Microsoft.FluentUI.AspNetCore.Components; using Poort8.Dataspace.API; +using Poort8.Dataspace.API.Extensions; using Poort8.Dataspace.API.Ishare.ConnectToken; using Poort8.Dataspace.AuthorizationRegistry.Extensions; using Poort8.Dataspace.CoreManager; @@ -12,11 +14,19 @@ using Poort8.Dataspace.Identity; using Poort8.Dataspace.OrganizationRegistry.Extensions; using Poort8.Ishare.Core; +using Scalar.AspNetCore; var builder = WebApplication.CreateBuilder(args); +if (!string.IsNullOrEmpty(builder.Configuration.GetValue("APPLICATIONINSIGHTS_CONNECTION_STRING"))) + builder.Services.AddOpenTelemetry().UseAzureMonitor(); + builder.Services.AddHttpClient(); +#pragma warning disable EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +builder.Services.AddHybridCache(); +#pragma warning restore EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + builder.Services.AddRazorComponents() .AddInteractiveServerComponents(options => options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromHours(1)); builder.Services.AddFluentUIComponents(); @@ -44,6 +54,8 @@ if (ishareEnabled) builder.Services.AddIshareCoreServices(builder.Configuration); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddAuthenticationSchemes(options => { @@ -52,12 +64,8 @@ }); //API -builder.Services.AddFastEndpoints(o => o.Assemblies = [typeof(Poort8.Dataspace.API.Ishare.ConnectToken.Endpoint).Assembly]) - .SwaggerDocument(options => - { - options.AutoTagPathSegmentIndex = 0; - options.EndpointFilter = ep => !(ep.EndpointTags?.Contains("ExcludeFromSwagger") ?? false); - }); +builder.Services.AddFastEndpoints(o => o.Assemblies = [typeof(Poort8.Dataspace.API.Ishare.ConnectToken.Endpoint).Assembly]); +builder.Services.AddApiDefinition(); builder.Services.AddHealthChecks(); var app = builder.Build(); @@ -74,7 +82,7 @@ app.UseHttpsRedirection(); -app.UseStaticFiles(); +app.MapStaticAssets(); app.UseAntiforgery(); app.MapRazorComponents() @@ -84,11 +92,14 @@ var apiDisabled = await featureManager.IsEnabledAsync(FeatureManagement.ApiDisabled); if (!apiDisabled) { - app.UseFastEndpoints(c => + app.UseDefaultExceptionHandler().UseFastEndpoints(c => { EndpointsConfiguration.Filter(c, ishareEnabled); EndpointsConfiguration.ConfigureProcessors(c); - }).UseSwaggerGen(); + }).UseSwaggerGen(); //Swagger + + app.UseOpenApi(options => options.Path = "/openapi/{documentName}.json"); //Scalar + app.MapScalarApiReference(); //Scalar } app.UseMiddleware(); @@ -97,6 +108,25 @@ app.MapIdentityApi(); app.MapAdditionalIdentityEndpoints(); +app.MapApiReferenceEndpoints(); + +var registerDisabled = await featureManager.IsEnabledAsync(FeatureManagement.RegisterNewUsersDisabled); +if (registerDisabled) +{ + app.Use(async (context, next) => + { + if (context.Request.Path.StartsWithSegments("/register")) + { + context.Response.StatusCode = StatusCodes.Status404NotFound; + await context.Response.WriteAsync("Register endpoint is disabled."); + } + else + { + await next.Invoke(); + } + }); +} + app.SetUserRoles(); app.Run(); diff --git a/Poort8.Dataspace.CoreManager/Services/OpenApiService.cs b/Poort8.Dataspace.CoreManager/Services/OpenApiService.cs new file mode 100644 index 0000000..d055c8f --- /dev/null +++ b/Poort8.Dataspace.CoreManager/Services/OpenApiService.cs @@ -0,0 +1,126 @@ +using Markdig; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Caching.Hybrid; +using NSwag; +using static Poort8.Dataspace.CoreManager.Catalog.Index; + +namespace Poort8.Dataspace.CoreManager.Services; + +public class OpenApiService +{ + private readonly ILogger _logger; + private readonly HttpClient _httpClient; + private readonly HybridCache _cache; + + public OpenApiService( + ILogger logger, + IHttpClientFactory httpClientFactory, + HybridCache cache) + { + _logger = logger; + _httpClient = httpClientFactory.CreateClient(); + _cache = cache; + } + + public async Task GetOpenApiDefinition(string url, CancellationToken token = default) + { + var json = await _cache.GetOrCreateAsync( + $"OpenApiJson-{Uri.EscapeDataString(url)}", + async cancel => await _httpClient.GetStringAsync(url, cancel), + new HybridCacheEntryOptions() { Expiration = TimeSpan.FromMinutes(5) }, + cancellationToken: token + ); + + return await ParseOpenApiDocument(json, token); + } + + private static async Task ParseOpenApiDocument(string json, CancellationToken cancellationToken) + { + try + { + var openApiDocument = await OpenApiDocument.FromJsonAsync(json, cancellationToken); + return openApiDocument; + } + catch (Exception) + { + var document = await OpenApiYamlDocument.FromYamlAsync(json, cancellationToken); + var openApiDocument = await OpenApiDocument.FromJsonAsync(document.ToJson(), cancellationToken); + return openApiDocument; + } + } + + public async Task GetOpenApiDefinitionJson(string url) + { + var openApiDocument = await GetOpenApiDefinition(url); + return openApiDocument.ToJson(); + } + + public async Task GetOpenApiDefinitionServer(string url) + { + var openApiDocument = await GetOpenApiDefinition(url); + + if (Uri.TryCreate(url, UriKind.Absolute, out var host)) + { + var serverUrl = openApiDocument.Servers.FirstOrDefault()?.Url; + if (serverUrl != null) + { + if (Uri.TryCreate(serverUrl, UriKind.Absolute, out var absoluteServerUri)) + { + return absoluteServerUri.ToString(); + } + else if (Uri.TryCreate(serverUrl, UriKind.Relative, out var relativeServerUri)) + { + return new Uri(host, relativeServerUri).ToString(); + } + else + { + _logger.LogWarning("P8.warn - Invalid server URL in the OpenAPI document for {openApiUrl}", url); + return $"{host.Scheme}://{host.Host}"; + } + } + else + { + _logger.LogWarning("P8.warn - No servers defined in the OpenAPI document for {openApiUrl}", url); + return $"{host.Scheme}://{host.Host}"; + } + } + else + { + _logger.LogError("P8.err - Invalid URL: {openApiUrl}", url); + return "Invalid URL"; + } + } + + public async Task GetDataSourceViewModel(string url, string organization, string? logoUrl) + { + try + { + var openApi = await GetOpenApiDefinition(url); + + Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var host); + + return new DataSourceViewModel() + { + Type = "Schema: " + openApi.SchemaType, + LogoUrl = logoUrl, + Organization = organization, + Title = openApi.Info.Title, + Description = openApi.Info.Description, + DescriptionMarkdown = new MarkupString(Markdown.ToHtml(openApi.Info.Description ?? string.Empty)), + Version = openApi.Info.Version, + Swagger = url, + Terms = openApi.Info.TermsOfService, + License = openApi.Info.License?.Url, + Contact = string.IsNullOrEmpty(openApi.Info.Contact?.Email) ? null : "mailto:" + openApi.Info.Contact?.Email, + Docs = openApi.ExternalDocumentation?.Url, + Host = host?.Host ?? "Invalid URL", + Url = url + }; + } + catch (Exception e) + { + _logger.LogError(e, "P8.err - Error reading the OpenAPI definition"); + return null; + } + } +} diff --git a/Poort8.Dataspace.CoreManager/Services/UseCaseService.cs b/Poort8.Dataspace.CoreManager/Services/UseCaseService.cs new file mode 100644 index 0000000..6282504 --- /dev/null +++ b/Poort8.Dataspace.CoreManager/Services/UseCaseService.cs @@ -0,0 +1,86 @@ +using Microsoft.Extensions.Options; +using NSwag; + +namespace Poort8.Dataspace.CoreManager.Services; + +public class UseCaseService +{ + private readonly ILogger _logger; + private readonly HttpClient _httpClient; + + public List UseCases { get; set; } = new List(); + + public UseCaseService( + ILogger logger, + IOptions options, + IHttpClientFactory httpClientFactory) + { + _logger = logger; + _httpClient = httpClientFactory.CreateClient(); + + AuthorizationRegistry.UseCases.AuthorizationModels.Keys.ToList().ForEach(key => + { + UseCases.Add(new UseCase(key)); + }); + + var openApiUrls = options.Value.OpenApiUrls; + if (openApiUrls != null) + { + foreach (var url in openApiUrls.Split(";")) + { + if (Uri.TryCreate(url, UriKind.Absolute, out _)) + GetUseCaseFromOpenApi(url); + } + } + } + + private async void GetUseCaseFromOpenApi(string url) + { + try + { + var openApiJson = await _httpClient.GetStringAsync(url); + var openApi = await OpenApiDocument.FromJsonAsync(openApiJson); + + foreach (var path in openApi.Paths) + { + foreach (var operation in path.Value) + { + foreach (var tag in operation.Value.Tags) + { + if (UseCases.Any(x => x.Name.Equals(tag, StringComparison.OrdinalIgnoreCase))) + { + UseCases.First(x => x.Name.Equals(tag, StringComparison.OrdinalIgnoreCase)).Actions.Add(operation.Key.ToString()); + UseCases.First(x => x.Name.Equals(tag, StringComparison.OrdinalIgnoreCase)).ResourceTypes.Add(operation.Value.OperationId); + } + else + { + UseCases.Add(new UseCase(tag.ToLower()) + { + Actions = [operation.Key.ToString()], + ResourceTypes = [operation.Value.OperationId] + }); + } + } + } + } + } + catch (Exception e) + { + _logger.LogError("P8.err - Error while getting use cases from OpenAPI: {msg}", e.Message); + } + } +} + +public class UseCase +{ + public string Name { get; set; } + public List Actions { get; set; } = new(); + public List ResourceTypes { get; set; } = new(); + public List ResourceIdentifiers { get; set; } = new(); + public List ResourceAttributes { get; set; } = new(); + + public UseCase(string name) + { + Name = name; + } +} diff --git a/Poort8.Dataspace.CoreManager/deploy/appServiceModule.bicep b/Poort8.Dataspace.CoreManager/deploy/appServiceModule.bicep index 0baedf3..9aed109 100644 --- a/Poort8.Dataspace.CoreManager/deploy/appServiceModule.bicep +++ b/Poort8.Dataspace.CoreManager/deploy/appServiceModule.bicep @@ -327,7 +327,7 @@ resource appService 'Microsoft.Web/sites@2022-09-01' = { } ] phpVersion: 'OFF' - netFrameworkVersion: 'v8.0' + netFrameworkVersion: 'v9.0' alwaysOn: true webSocketsEnabled: true ipSecurityRestrictionsDefaultAction: 'Allow' diff --git a/Poort8.Dataspace.Identity.SqlServerMigrations/Poort8.Dataspace.Identity.SqlServerMigrations.csproj b/Poort8.Dataspace.Identity.SqlServerMigrations/Poort8.Dataspace.Identity.SqlServerMigrations.csproj index cc788f3..1bdda88 100644 --- a/Poort8.Dataspace.Identity.SqlServerMigrations/Poort8.Dataspace.Identity.SqlServerMigrations.csproj +++ b/Poort8.Dataspace.Identity.SqlServerMigrations/Poort8.Dataspace.Identity.SqlServerMigrations.csproj @@ -1,13 +1,13 @@  - net8.0 + net9.0 enable enable - + diff --git a/Poort8.Dataspace.Identity.SqliteMigrations/Poort8.Dataspace.Identity.SqliteMigrations.csproj b/Poort8.Dataspace.Identity.SqliteMigrations/Poort8.Dataspace.Identity.SqliteMigrations.csproj index 9cc702e..7dead1a 100644 --- a/Poort8.Dataspace.Identity.SqliteMigrations/Poort8.Dataspace.Identity.SqliteMigrations.csproj +++ b/Poort8.Dataspace.Identity.SqliteMigrations/Poort8.Dataspace.Identity.SqliteMigrations.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/Poort8.Dataspace.Identity/AuthenticationConstants.cs b/Poort8.Dataspace.Identity/AuthenticationConstants.cs index fd32283..fa529c3 100644 --- a/Poort8.Dataspace.Identity/AuthenticationConstants.cs +++ b/Poort8.Dataspace.Identity/AuthenticationConstants.cs @@ -11,4 +11,5 @@ public class AuthenticationConstants public const string WritePoliciesPolicy = "WritePoliciesPolicy"; public const string DeletePoliciesPolicy = "DeletePoliciesPolicy"; public const string ReadOROrganizationsPolicy = "ReadOROrganizationsPolicy"; + public const string ReadAROrganizationsPolicy = "ReadAROrganizationsPolicy"; } diff --git a/Poort8.Dataspace.Identity/Poort8.Dataspace.Identity.csproj b/Poort8.Dataspace.Identity/Poort8.Dataspace.Identity.csproj index bffbfba..d96bb48 100644 --- a/Poort8.Dataspace.Identity/Poort8.Dataspace.Identity.csproj +++ b/Poort8.Dataspace.Identity/Poort8.Dataspace.Identity.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable true @@ -10,8 +10,8 @@ - - + + diff --git a/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations.csproj b/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations.csproj index 0525ce6..955e509 100644 --- a/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations.csproj +++ b/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations/Poort8.Dataspace.OrganizationRegistry.SqlServerMigrations.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations.csproj b/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations.csproj index 0525ce6..955e509 100644 --- a/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations.csproj +++ b/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations/Poort8.Dataspace.OrganizationRegistry.SqliteMigrations.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/Poort8.Dataspace.OrganizationRegistry.Tests/AuditTests.cs b/Poort8.Dataspace.OrganizationRegistry.Tests/AuditTests.cs index 4890d79..072c757 100644 --- a/Poort8.Dataspace.OrganizationRegistry.Tests/AuditTests.cs +++ b/Poort8.Dataspace.OrganizationRegistry.Tests/AuditTests.cs @@ -35,11 +35,10 @@ public async Task GetAuditRecords() var organizationEntity = await _organizationRegistry.CreateOrganization(organization); var auditRecords = await _organizationRegistry.GetAuditRecords(); - Assert.NotNull(auditRecords); - Assert.Single(auditRecords.Where(a => + Assert.Single(auditRecords, a => a.EntityId == organizationEntity.Identifier && a.EntityType == "Organization" && - a.Action == "Added")); + a.Action == "Added"); } [Fact] diff --git a/Poort8.Dataspace.OrganizationRegistry.Tests/Poort8.Dataspace.OrganizationRegistry.Tests.csproj b/Poort8.Dataspace.OrganizationRegistry.Tests/Poort8.Dataspace.OrganizationRegistry.Tests.csproj index 53df1f2..a839bf9 100644 --- a/Poort8.Dataspace.OrganizationRegistry.Tests/Poort8.Dataspace.OrganizationRegistry.Tests.csproj +++ b/Poort8.Dataspace.OrganizationRegistry.Tests/Poort8.Dataspace.OrganizationRegistry.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable false @@ -12,9 +12,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Poort8.Dataspace.OrganizationRegistry/Poort8.Dataspace.OrganizationRegistry.csproj b/Poort8.Dataspace.OrganizationRegistry/Poort8.Dataspace.OrganizationRegistry.csproj index 53f73d5..2940923 100644 --- a/Poort8.Dataspace.OrganizationRegistry/Poort8.Dataspace.OrganizationRegistry.csproj +++ b/Poort8.Dataspace.OrganizationRegistry/Poort8.Dataspace.OrganizationRegistry.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable true @@ -10,8 +10,8 @@ - - + + diff --git a/Poort8.Dataspace.sln b/Poort8.Dataspace.sln index c3abca9..5c4e9f8 100644 --- a/Poort8.Dataspace.sln +++ b/Poort8.Dataspace.sln @@ -29,7 +29,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poort8.Dataspace.Identity.S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poort8.Dataspace.API", "Poort8.Dataspace.API\Poort8.Dataspace.API.csproj", "{6AC0AE2F-1F24-4D6C-BF5C-74937D1DB84A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poort8.Dataspace.API.Tests", "Poort8.Dataspace.API.Tests\Poort8.Dataspace.API.Tests.csproj", "{9E206CE0-36AF-4F24-BB28-44119C9C4712}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poort8.Dataspace.API.Tests", "Poort8.Dataspace.API.Tests\Poort8.Dataspace.API.Tests.csproj", "{9E206CE0-36AF-4F24-BB28-44119C9C4712}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poort8.Dataspace.CoreManager.Tests", "Poort8.Dataspace.CoreManager.Tests\Poort8.Dataspace.CoreManager.Tests.csproj", "{B666EE3F-A943-4C69-9C78-E7773DA29CD2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -93,6 +95,10 @@ Global {9E206CE0-36AF-4F24-BB28-44119C9C4712}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E206CE0-36AF-4F24-BB28-44119C9C4712}.Release|Any CPU.ActiveCfg = Release|Any CPU {9E206CE0-36AF-4F24-BB28-44119C9C4712}.Release|Any CPU.Build.0 = Release|Any CPU + {B666EE3F-A943-4C69-9C78-E7773DA29CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B666EE3F-A943-4C69-9C78-E7773DA29CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B666EE3F-A943-4C69-9C78-E7773DA29CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B666EE3F-A943-4C69-9C78-E7773DA29CD2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE