Skip to content

Commit

Permalink
feat: validate DSP catalog messages (#3365)
Browse files Browse the repository at this point in the history
* feat: validate DSP catalog messages

* PR remarks
  • Loading branch information
ndr-brt authored Aug 16, 2023
1 parent ae59844 commit 8ddcc07
Show file tree
Hide file tree
Showing 21 changed files with 452 additions and 430 deletions.
200 changes: 0 additions & 200 deletions DEPENDENCIES

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.validator.jsonobject.validators;

import jakarta.json.JsonObject;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import org.eclipse.edc.validator.jsonobject.JsonLdPath;
import org.eclipse.edc.validator.spi.ValidationResult;
import org.eclipse.edc.validator.spi.Validator;

import java.util.Collection;
import java.util.Optional;

import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.validator.spi.Violation.violation;

/**
* Verify that the @value node has a certain value
*/
public class TypeIs implements Validator<JsonObject> {

private final JsonLdPath path;
private final String expectedType;

public TypeIs(JsonLdPath path, String expectedType) {
this.path = path;
this.expectedType = expectedType;
}

@Override
public ValidationResult validate(JsonObject input) {
var newPath = path.append(TYPE);
var typeStream = Optional.of(input)
.map(it -> it.getJsonArray(TYPE))
.stream().flatMap(Collection::stream);

var result = typeStream
.filter(it -> it.getValueType() == JsonValue.ValueType.STRING)
.map(JsonString.class::cast)
.map(JsonString::getString)
.filter(it -> it.equals(expectedType))
.findFirst();

if (result.isPresent()) {
return ValidationResult.success();
} else {
var violation = violation(
"%s was expected to be %s but it was not".formatted(newPath, expectedType),
newPath.toString(), typeStream
);
return ValidationResult.failure(violation);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.api.validation;
package org.eclipse.edc.validator.jsonobject.validators.model;

import jakarta.json.JsonObject;
import org.eclipse.edc.validator.jsonobject.JsonLdPath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.api.validation;
package org.eclipse.edc.validator.jsonobject.validators.model;

import jakarta.json.JsonObject;
import org.eclipse.edc.spi.query.SortOrder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.api.validation;
package org.eclipse.edc.validator.jsonobject.validators.model;

import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.api.validation;
package org.eclipse.edc.validator.jsonobject.validators.model;

import jakarta.json.Json;
import jakarta.json.JsonArrayBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ dependencies {
api(project(":spi:control-plane:control-plane-spi"))
api(project(":extensions:common:http"))

implementation(project(":core:common:validator-core"))

implementation(libs.jakarta.rsApi)

testImplementation(testFixtures(project(":extensions:common:http:jersey-core")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@
import org.eclipse.edc.connector.spi.catalog.CatalogProtocolService;
import org.eclipse.edc.protocol.dsp.api.configuration.DspApiConfiguration;
import org.eclipse.edc.protocol.dsp.catalog.api.controller.DspCatalogApiController;
import org.eclipse.edc.protocol.dsp.catalog.api.validation.CatalogRequestMessageValidator;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.iam.IdentityService;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry;
import org.eclipse.edc.web.spi.WebService;

import static org.eclipse.edc.protocol.dsp.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE;

/**
* Creates and registers the controller for dataspace protocol catalog requests.
*/
Expand All @@ -47,6 +51,8 @@ public class DspCatalogApiExtension implements ServiceExtension {
private CatalogProtocolService service;
@Inject
private DataServiceRegistry dataServiceRegistry;
@Inject
private JsonObjectValidatorRegistry validatorRegistry;

@Override
public String name() {
Expand All @@ -55,8 +61,10 @@ public String name() {

@Override
public void initialize(ServiceExtensionContext context) {
validatorRegistry.register(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE, CatalogRequestMessageValidator.instance());
var dspCallbackAddress = apiConfiguration.getDspCallbackAddress();
var catalogController = new DspCatalogApiController(context.getMonitor(), identityService, transformerRegistry, dspCallbackAddress, service);
var catalogController = new DspCatalogApiController(context.getMonitor(), identityService, transformerRegistry,
dspCallbackAddress, service, validatorRegistry);
webService.registerResource(apiConfiguration.getContextAlias(), catalogController);

dataServiceRegistry.register(DataService.Builder.newInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.edc.spi.iam.TokenRepresentation;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry;
import org.jetbrains.annotations.NotNull;

import java.util.UUID;
Expand All @@ -38,7 +39,6 @@
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import static jakarta.ws.rs.core.Response.status;
import static java.lang.String.format;
import static org.eclipse.edc.jsonld.spi.TypeUtil.isOfExpectedType;
import static org.eclipse.edc.protocol.dsp.catalog.api.CatalogApiPaths.BASE_PATH;
import static org.eclipse.edc.protocol.dsp.catalog.api.CatalogApiPaths.CATALOG_REQUEST;
import static org.eclipse.edc.protocol.dsp.catalog.api.CatalogApiPaths.DATASET_REQUEST;
Expand All @@ -59,15 +59,17 @@ public class DspCatalogApiController {
private final TypeTransformerRegistry transformerRegistry;
private final String dspCallbackAddress;
private final CatalogProtocolService service;
private final JsonObjectValidatorRegistry validatorRegistry;

public DspCatalogApiController(Monitor monitor, IdentityService identityService,
TypeTransformerRegistry transformerRegistry, String dspCallbackAddress,
CatalogProtocolService service) {
CatalogProtocolService service, JsonObjectValidatorRegistry validatorRegistry) {
this.monitor = monitor;
this.identityService = identityService;
this.transformerRegistry = transformerRegistry;
this.dspCallbackAddress = dspCallbackAddress;
this.service = service;
this.validatorRegistry = validatorRegistry;
}

@POST
Expand All @@ -85,7 +87,8 @@ public Response requestCatalog(JsonObject jsonObject, @HeaderParam(AUTHORIZATION
return error().unauthorized();
}

if (!isOfExpectedType(jsonObject, DSPACE_TYPE_CATALOG_REQUEST_MESSAGE)) {
var validation = validatorRegistry.validate(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE, jsonObject);
if (validation.failed()) {
monitor.debug(format("Bad Request, %s", verificationResult.getFailureMessages()));
return error().badRequest();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.protocol.dsp.catalog.api.validation;

import jakarta.json.JsonObject;
import org.eclipse.edc.validator.jsonobject.JsonObjectValidator;
import org.eclipse.edc.validator.jsonobject.validators.TypeIs;
import org.eclipse.edc.validator.jsonobject.validators.model.QuerySpecValidator;
import org.eclipse.edc.validator.spi.Validator;

import static org.eclipse.edc.protocol.dsp.type.DspCatalogPropertyAndTypeNames.DSPACE_PROPERTY_FILTER;
import static org.eclipse.edc.protocol.dsp.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE;

/**
* Validator for {@link CatalogRequestMessageValidator} Json-LD representation
*/
public class CatalogRequestMessageValidator {
public static Validator<JsonObject> instance() {
return JsonObjectValidator.newValidator()
.verify(path -> new TypeIs(path, DSPACE_TYPE_CATALOG_REQUEST_MESSAGE))
.verifyObject(DSPACE_PROPERTY_FILTER, QuerySpecValidator::instance)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.protocol.dsp.catalog.api;

import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.eclipse.edc.protocol.dsp.type.DspCatalogPropertyAndTypeNames.DSPACE_TYPE_CATALOG_REQUEST_MESSAGE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

@ExtendWith(DependencyInjectionExtension.class)
class DspCatalogApiExtensionTest {

private final JsonObjectValidatorRegistry validatorRegistry = mock();

@BeforeEach
void setUp(ServiceExtensionContext context) {
context.registerService(JsonObjectValidatorRegistry.class, validatorRegistry);
}

@Test
void shouldRegisterMessageValidator(DspCatalogApiExtension extension, ServiceExtensionContext context) {
extension.initialize(context);

verify(validatorRegistry).register(eq(DSPACE_TYPE_CATALOG_REQUEST_MESSAGE), any());
}
}
Loading

0 comments on commit 8ddcc07

Please sign in to comment.