From 1839f38e054a958793ec40f524d911253086c74e Mon Sep 17 00:00:00 2001 From: DylanB95EST Date: Tue, 8 Mar 2022 17:26:34 +0000 Subject: Additional validation for names/identifiers Implementing additional regex validation for names/identifiers in CPS - Introduces a CpsValidator - Applies to relevent java public API's - Tests have been updated where necessary Issue-ID: CPS-322 Change-Id: I29ab8820bb1fe0eee247e425d6bb018bcd38f28e Signed-off-by: DylanB95EST --- .../java/org/onap/cps/api/CpsAdminService.java | 2 +- .../java/org/onap/cps/api/CpsModuleService.java | 15 +++---- .../java/org/onap/cps/api/CpsQueryService.java | 7 ++- .../org/onap/cps/api/impl/CpsAdminServiceImpl.java | 11 ++++- .../org/onap/cps/api/impl/CpsDataServiceImpl.java | 13 ++++++ .../onap/cps/api/impl/CpsModuleServiceImpl.java | 7 +++ .../org/onap/cps/api/impl/CpsQueryServiceImpl.java | 2 + .../cps/api/impl/YangTextSchemaSourceSetCache.java | 4 ++ .../main/java/org/onap/cps/utils/CpsValidator.java | 51 ++++++++++++++++++++++ .../cps/api/impl/CpsDataServiceImplSpec.groovy | 6 +-- .../cps/api/impl/CpsQueryServiceImplSpec.groovy | 4 +- .../org/onap/cps/utils/CpsValidatorSpec.groovy | 48 ++++++++++++++++++++ 12 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java create mode 100644 cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy (limited to 'cps-service') diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java index 44f7f7715..2cb01ac1e 100755 --- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2021 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java index ecc9bf098..79d6e03d4 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java @@ -23,7 +23,6 @@ package org.onap.cps.api; import java.util.Collection; import java.util.Map; -import org.checkerframework.checker.nullness.qual.NonNull; import org.onap.cps.spi.CascadeDeleteAllowed; import org.onap.cps.spi.exceptions.DataInUseException; import org.onap.cps.spi.model.ModuleReference; @@ -42,8 +41,8 @@ public interface CpsModuleService { * @param yangResourcesNameToContentMap yang resources (files) as a mep where key is resource name * and value is content */ - void createSchemaSet(@NonNull String dataspaceName, @NonNull String schemaSetName, - @NonNull Map yangResourcesNameToContentMap); + void createSchemaSet(String dataspaceName, String schemaSetName, + Map yangResourcesNameToContentMap); /** * Create a schema set from new modules and existing modules. @@ -52,8 +51,8 @@ public interface CpsModuleService { * @param newModuleNameToContentMap YANG resources map where key is a module name and value is content * @param moduleReferences List of YANG resources module references of the modules */ - void createSchemaSetFromModules(@NonNull String dataspaceName, @NonNull String schemaSetName, - @NonNull Map newModuleNameToContentMap, + void createSchemaSetFromModules(String dataspaceName, String schemaSetName, + Map newModuleNameToContentMap, Collection moduleReferences); /** @@ -63,7 +62,7 @@ public interface CpsModuleService { * @param schemaSetName schema set name * @return a SchemaSet */ - SchemaSet getSchemaSet(@NonNull String dataspaceName, @NonNull String schemaSetName); + SchemaSet getSchemaSet(String dataspaceName, String schemaSetName); /** * Deletes Schema Set. @@ -74,8 +73,8 @@ public interface CpsModuleService { * @throws DataInUseException if cascadeDeleteAllowed is set to CASCADE_DELETE_PROHIBITED and there * is associated anchor record exists in database */ - void deleteSchemaSet(@NonNull String dataspaceName, @NonNull String schemaSetName, - @NonNull CascadeDeleteAllowed cascadeDeleteAllowed); + void deleteSchemaSet(String dataspaceName, String schemaSetName, + CascadeDeleteAllowed cascadeDeleteAllowed); /** * Retrieve module references for the given dataspace name. diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java index beb0a1540..68ae1ebf0 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2022 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ package org.onap.cps.api; import java.util.Collection; -import org.checkerframework.checker.nullness.qual.NonNull; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; @@ -40,7 +39,7 @@ public interface CpsQueryService { * included in the output * @return a collection of data nodes */ - Collection queryDataNodes(@NonNull String dataspaceName, @NonNull String anchorName, - @NonNull String cpsPath, @NonNull FetchDescendantsOption fetchDescendantsOption); + Collection queryDataNodes(String dataspaceName, String anchorName, + String cpsPath, FetchDescendantsOption fetchDescendantsOption); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java index 1013addbe..7bec1e39f 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020 Nordix Foundation + * Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ @@ -30,6 +30,7 @@ import org.onap.cps.api.CpsAdminService; import org.onap.cps.api.CpsDataService; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.model.Anchor; +import org.onap.cps.utils.CpsValidator; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -43,42 +44,50 @@ public class CpsAdminServiceImpl implements CpsAdminService { @Override public void createDataspace(final String dataspaceName) { + CpsValidator.validateNameCharacters(dataspaceName); cpsAdminPersistenceService.createDataspace(dataspaceName); } @Override public void deleteDataspace(final String dataspaceName) { + CpsValidator.validateNameCharacters(dataspaceName); cpsAdminPersistenceService.deleteDataspace(dataspaceName); } @Override public void createAnchor(final String dataspaceName, final String schemaSetName, final String anchorName) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName, anchorName); cpsAdminPersistenceService.createAnchor(dataspaceName, schemaSetName, anchorName); } @Override public Collection getAnchors(final String dataspaceName) { + CpsValidator.validateNameCharacters(dataspaceName); return cpsAdminPersistenceService.getAnchors(dataspaceName); } @Override public Collection getAnchors(final String dataspaceName, final String schemaSetName) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetName); } @Override public Anchor getAnchor(final String dataspaceName, final String anchorName) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName); } @Override public void deleteAnchor(final String dataspaceName, final String anchorName) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataService.deleteDataNodes(dataspaceName, anchorName, OffsetDateTime.now()); cpsAdminPersistenceService.deleteAnchor(dataspaceName, anchorName); } @Override public Collection queryAnchorNames(final String dataspaceName, final Collection moduleNames) { + CpsValidator.validateNameCharacters(dataspaceName); final Collection anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames); return anchors.stream().map(Anchor::getName).collect(Collectors.toList()); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java index 643614f4f..399457dd6 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java @@ -36,6 +36,7 @@ import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DataNodeBuilder; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.utils.YangUtils; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -56,6 +57,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveData(final String dataspaceName, final String anchorName, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final var dataNode = buildDataNode(dataspaceName, anchorName, ROOT_NODE_XPATH, jsonData); cpsDataPersistenceService.storeDataNode(dataspaceName, anchorName, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, ROOT_NODE_XPATH, Operation.CREATE); @@ -64,6 +66,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveData(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.addChildDataNode(dataspaceName, anchorName, parentNodeXpath, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.CREATE); @@ -72,6 +75,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void saveListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection listElementDataNodeCollection = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.addListElements(dataspaceName, anchorName, parentNodeXpath, @@ -82,12 +86,14 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public DataNode getDataNode(final String dataspaceName, final String anchorName, final String xpath, final FetchDescendantsOption fetchDescendantsOption) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsDataPersistenceService.getDataNode(dataspaceName, anchorName, xpath, fetchDescendantsOption); } @Override public void updateNodeLeaves(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService .updateDataLeaves(dataspaceName, anchorName, dataNode.getXpath(), dataNode.getLeaves()); @@ -102,6 +108,7 @@ public class CpsDataServiceImpl implements CpsDataService { final Collection dataNodeUpdates = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodeUpdatesAsJson); + CpsValidator.validateNameCharacters(dataspaceName, anchorName); for (final DataNode dataNodeUpdate : dataNodeUpdates) { processDataNodeUpdate(dataspaceName, anchorName, dataNodeUpdate); } @@ -122,6 +129,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void replaceNodeTree(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final var dataNode = buildDataNode(dataspaceName, anchorName, parentNodeXpath, jsonData); cpsDataPersistenceService.replaceDataNodeTree(dataspaceName, anchorName, dataNode); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE); @@ -130,6 +138,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final Collection newListElements = buildDataNodes(dataspaceName, anchorName, parentNodeXpath, jsonData); replaceListContent(dataspaceName, anchorName, parentNodeXpath, newListElements, observedTimestamp); @@ -138,6 +147,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath, final Collection dataNodes, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, dataNodes); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, parentNodeXpath, Operation.UPDATE); } @@ -145,6 +155,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteDataNode(final String dataspaceName, final String anchorName, final String dataNodeXpath, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.deleteDataNode(dataspaceName, anchorName, dataNodeXpath); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, dataNodeXpath, Operation.DELETE); } @@ -152,6 +163,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteDataNodes(final String dataspaceName, final String anchorName, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); final var anchor = cpsAdminService.getAnchor(dataspaceName, anchorName); cpsDataPersistenceService.deleteDataNodes(dataspaceName, anchorName); processDataUpdatedEventAsync(anchor, ROOT_NODE_XPATH, Operation.DELETE, observedTimestamp); @@ -160,6 +172,7 @@ public class CpsDataServiceImpl implements CpsDataService { @Override public void deleteListOrListElement(final String dataspaceName, final String anchorName, final String listNodeXpath, final OffsetDateTime observedTimestamp) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); cpsDataPersistenceService.deleteListDataNode(dataspaceName, anchorName, listNodeXpath); processDataUpdatedEventAsync(dataspaceName, anchorName, observedTimestamp, listNodeXpath, Operation.DELETE); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java index f0e79c60c..8e43227f9 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java @@ -33,6 +33,7 @@ import org.onap.cps.spi.exceptions.SchemaSetInUseException; import org.onap.cps.spi.model.Anchor; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.spi.model.SchemaSet; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -48,6 +49,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public void createSchemaSet(final String dataspaceName, final String schemaSetName, final Map yangResourcesNameToContentMap) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final var yangTextSchemaSourceSet = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap); cpsModulePersistenceService.storeSchemaSet(dataspaceName, schemaSetName, yangResourcesNameToContentMap); @@ -58,6 +60,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName, final Map newModuleNameToContentMap, final Collection moduleReferences) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); cpsModulePersistenceService.storeSchemaSetFromModules(dataspaceName, schemaSetName, newModuleNameToContentMap, moduleReferences); @@ -65,6 +68,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public SchemaSet getSchemaSet(final String dataspaceName, final String schemaSetName) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final var yangTextSchemaSourceSet = yangTextSchemaSourceSetCache .get(dataspaceName, schemaSetName); return SchemaSet.builder().name(schemaSetName).dataspaceName(dataspaceName) @@ -75,6 +79,7 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Transactional public void deleteSchemaSet(final String dataspaceName, final String schemaSetName, final CascadeDeleteAllowed cascadeDeleteAllowed) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final Collection anchors = cpsAdminService.getAnchors(dataspaceName, schemaSetName); if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) { throw new SchemaSetInUseException(dataspaceName, schemaSetName); @@ -89,12 +94,14 @@ public class CpsModuleServiceImpl implements CpsModuleService { @Override public Collection getYangResourceModuleReferences(final String dataspaceName) { + CpsValidator.validateNameCharacters(dataspaceName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName); } @Override public Collection getYangResourcesModuleReferences(final String dataspaceName, final String anchorName) { + CpsValidator.validateNameCharacters(dataspaceName); return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName, anchorName); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java index dd9f160db..c2003d6bf 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java @@ -25,6 +25,7 @@ import org.onap.cps.api.CpsQueryService; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; +import org.onap.cps.utils.CpsValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -37,6 +38,7 @@ public class CpsQueryServiceImpl implements CpsQueryService { @Override public Collection queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { + CpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); } } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java index 03b52a308..fb881a97b 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/YangTextSchemaSourceSetCache.java @@ -24,6 +24,7 @@ package org.onap.cps.api.impl; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.Map; import org.onap.cps.spi.CpsModulePersistenceService; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.yang.YangTextSchemaSourceSet; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,7 @@ public class YangTextSchemaSourceSetCache { */ @Cacheable(key = "#p0.concat('-').concat(#p1)") public YangTextSchemaSourceSet get(final String dataspaceName, final String schemaSetName) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); final Map yangResourceNameToContent = cpsModulePersistenceService.getYangSchemaResources(dataspaceName, schemaSetName); return YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent); @@ -69,6 +71,7 @@ public class YangTextSchemaSourceSetCache { @CanIgnoreReturnValue public YangTextSchemaSourceSet updateCache(final String dataspaceName, final String schemaSetName, final YangTextSchemaSourceSet yangTextSchemaSourceSet) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); return yangTextSchemaSourceSet; } @@ -81,6 +84,7 @@ public class YangTextSchemaSourceSetCache { */ @CacheEvict(key = "#p0.concat('-').concat(#p1)") public void removeFromCache(final String dataspaceName, final String schemaSetName) { + CpsValidator.validateNameCharacters(dataspaceName, schemaSetName); // Spring provides implementation for removing object from cache } diff --git a/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java new file mode 100644 index 000000000..dd1649563 --- /dev/null +++ b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.utils; + +import com.google.common.collect.Lists; +import java.util.Collection; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.spi.exceptions.DataValidationException; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class CpsValidator { + + private static final char[] UNSUPPORTED_NAME_CHARACTERS = "!\" #$%&'()*+,./\\:;<=>?@[]^`{|}~".toCharArray(); + + /** + * Validate characters in names within cps. + * @param names names of data to be validated + */ + public static void validateNameCharacters(final String... names) { + for (final String name : names) { + final Collection charactersOfName = Lists.charactersOf(name); + for (final char unsupportedCharacter : UNSUPPORTED_NAME_CHARACTERS) { + if (charactersOfName.contains(unsupportedCharacter)) { + throw new DataValidationException("Name or ID Validation Error.", + name + " invalid token encountered at position " + (name.indexOf(unsupportedCharacter) + 1)); + } + } + } + } +} diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy index eb06199d1..fc1293cb7 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy @@ -50,9 +50,9 @@ class CpsDataServiceImplSpec extends Specification { mockCpsAdminService.getAnchor(dataspaceName, anchorName) >> anchor } - def dataspaceName = 'some dataspace' - def anchorName = 'some anchor' - def schemaSetName = 'some schema set' + def dataspaceName = 'some-dataspace' + def anchorName = 'some-anchor' + def schemaSetName = 'some-schema-set' def anchor = Anchor.builder().name(anchorName).schemaSetName(schemaSetName).build() def observedTimestamp = OffsetDateTime.now() diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy index 4878f4c11..aa01b4401 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy @@ -35,8 +35,8 @@ class CpsQueryServiceImplSpec extends Specification { def 'Query data nodes by cps path with #fetchDescendantsOption.'() { given: 'a dataspace name, an anchor name and a cps path' - def dataspaceName = 'some dataspace' - def anchorName = 'some anchor' + def dataspaceName = 'some-dataspace' + def anchorName = 'some-anchor' def cpsPath = '/cps-path' when: 'queryDataNodes is invoked' objectUnderTest.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption) diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy new file mode 100644 index 000000000..191472cee --- /dev/null +++ b/cps-service/src/test/groovy/org/onap/cps/utils/CpsValidatorSpec.groovy @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.utils + +import org.onap.cps.spi.exceptions.DataValidationException +import spock.lang.Specification + +class CpsValidatorSpec extends Specification { + + + def 'Validating a valid string.'() { + when: 'the string is validated using a valid name' + CpsValidator.validateNameCharacters('name-with-no-spaces') + then: 'no exception is thrown' + noExceptionThrown() + } + + def 'Validating an invalid string.'() { + when: 'the string is validated using an invalid name' + CpsValidator.validateNameCharacters(name) + then: 'a data validation exception is thrown' + def exceptionThrown = thrown(DataValidationException) + and: 'the error was encountered at the following index in #scenario' + assert exceptionThrown.getDetails().contains(expectedErrorMessage) + where: 'the following names are used' + scenario | name || expectedErrorMessage + 'position 5' | 'name with spaces' || 'name with spaces invalid token encountered at position 5' + 'position 9' | 'nameWith Space' || 'nameWith Space invalid token encountered at position 9' + } +} -- cgit 1.2.3-korg