From adbe873f25958a856774b6942834f710762e23ef Mon Sep 17 00:00:00 2001 From: AndrewLamb Date: Thu, 13 Feb 2020 15:45:04 +0000 Subject: SOL003 Adapter Package Management - Notify Change-Id: Iaa428d259c23df581c1aced1978302ede0e854c0 Issue-ID: SO-2420 Signed-off-by: AndrewLamb --- .../resources/ETSI-Catalog-Notification-API.json | 119 +++-- .../vnfmadapter/MessageConverterConfiguration.java | 4 + .../sol003/AbstractPkgNotificationConverter.java | 56 ++ .../sol003/PkgChangeNotificationConverter.java | 79 +++ .../sol003/PkgOnboardingNotificationConverter.java | 69 +++ .../AbstractNotificationServiceProvider.java | 64 +++ .../BasicAuthNotificationServiceProvider.java | 68 +++ .../NotificationManager.java | 137 +++++ .../NotificationServiceProvider.java | 51 ++ .../NotificationServiceProviderFactory.java | 67 +++ .../OAuthNotificationServiceProvider.java | 102 ++++ .../subscriptionmanagement/OAuthTokenResponse.java | 56 ++ .../SubscriptionManager.java | 15 +- .../TlsNotificationServiceProvider.java | 56 ++ .../EtsiSubscriptionNotificationController.java | 83 +++ .../AuthenticationTypeNotSupportedException.java | 44 ++ .../rest/exceptions/ConversionFailedException.java | 44 ++ ...tionNotificationControllerExceptionHandler.java | 112 ++++ .../NotificationTypeNotSupportedException.java | 44 ++ ...ackageManagementControllerExceptionHandler.java | 12 +- .../SubscriptionRequestConversionException.java | 43 -- ...EtsiSubscriptionNotificationControllerTest.java | 592 +++++++++++++++++++++ pom.xml | 44 +- 23 files changed, 1846 insertions(+), 115 deletions(-) create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/ConversionFailedException.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java delete mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/SubscriptionRequestConversionException.java create mode 100644 adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json index 6f9b2c3bbe..6db54435d2 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json @@ -6,18 +6,26 @@ "version": "v1" }, "host": "127.0.0.1:8000", - "schemes": ["http"], + "schemes": [ + "http" + ], "basePath": "/", - "consumes": ["application/json"], - "produces": ["application/json"], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], "securityDefinitions": { "Basic": { "type": "basic" } }, - "security": [{ - "Basic": [] - }], + "security": [ + { + "Basic": [] + } + ], "paths": { "/URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification": { "get": { @@ -35,25 +43,31 @@ } } }, - "tags": ["VNF Package Management interface"] + "tags": [ + "VNF Package Management interface" + ] }, "post": { "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification_create", "description": "", - "parameters": [{ - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PkgChangeNotification" + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PkgChangeNotification" + } } - }], + ], "responses": { "204": { "description": "" } }, - "tags": ["VNF Package Management interface"] + "tags": [ + "VNF Package Management interface" + ] }, "parameters": [] }, @@ -73,25 +87,31 @@ } } }, - "tags": ["VNF Package Management interface"] + "tags": [ + "VNF Package Management interface" + ] }, "post": { "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageOnboardingNotification_create", "description": "", - "parameters": [{ - "name": "data", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PkgOnboardingNotification" + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PkgOnboardingNotification" + } } - }], + ], "responses": { "204": { "description": "" } }, - "tags": ["VNF Package Management interface"] + "tags": [ + "VNF Package Management interface" + ] }, "parameters": [] } @@ -100,7 +120,9 @@ "NOTIFICATION_LINKSERIALIZER": { "title": "Vnfpackage", "description": "Link to the resource representing the VNF package to which the notified change applies.", - "required": ["href"], + "required": [ + "href" + ], "type": "object", "properties": { "href": { @@ -125,7 +147,16 @@ } }, "PkgChangeNotification": { - "required": ["id", "notificationType", "timeStamp", "subscriptionId", "vnfPkgId", "changeType", "vnfdId", "_links"], + "required": [ + "id", + "notificationType", + "timeStamp", + "subscriptionId", + "vnfPkgId", + "changeType", + "vnfdId", + "_links" + ], "type": "object", "properties": { "id": { @@ -138,7 +169,9 @@ "title": "Notificationtype", "description": "Discriminator for the different notification types.", "type": "string", - "enum": ["VnfPackageChangeNotification"] + "enum": [ + "VnfPackageChangeNotification" + ] }, "timeStamp": { "title": "Timestamp", @@ -156,19 +189,25 @@ "title": "Vnfpkgid", "description": "Identifier of the VNF package.", "type": "string", - "format": "uuid" + "minLength": 1 }, "changeType": { "title": "Changetype", "description": "The type of change of the VNF package.", "type": "string", - "enum": ["OP_STATE_CHANGE", "PKG_DELETE"] + "enum": [ + "OP_STATE_CHANGE", + "PKG_DELETE" + ] }, "operationalState": { "title": "Operationalstate", "description": "New operational state of the VNF package.", "type": "string", - "enum": ["ENABLED", "DISABLED"] + "enum": [ + "ENABLED", + "DISABLED" + ] }, "vnfdId": { "title": "Vnfdid", @@ -182,7 +221,15 @@ } }, "PkgOnboardingNotification": { - "required": ["id", "notificationType", "subscriptionId", "timeStamp", "vnfPkgId", "vnfdId", "_links"], + "required": [ + "id", + "notificationType", + "subscriptionId", + "timeStamp", + "vnfPkgId", + "vnfdId", + "_links" + ], "type": "object", "properties": { "id": { @@ -195,7 +242,9 @@ "title": "Notificationtype", "description": "Discriminator for the different notification types.", "type": "string", - "enum": ["VnfPackageOnboardingNotification"] + "enum": [ + "VnfPackageOnboardingNotification" + ] }, "subscriptionId": { "title": "Subscriptionid", @@ -213,13 +262,13 @@ "title": "Vnfpkgid", "description": "Identifier of the VNF package.", "type": "string", - "format": "uuid" + "minLength": 1 }, "vnfdId": { "title": "Vnfdid", "description": "This identifier, which is managed by the VNF provider, identifies the VNF package and the VNFD in a globally unique way.", "type": "string", - "format": "uuid" + "minLength": 1 }, "_links": { "$ref": "#/definitions/PkgmLinks" @@ -227,4 +276,4 @@ } } } -} \ No newline at end of file +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java index 61d5adf9d8..87e8bb4d57 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java @@ -23,6 +23,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.Collection; +import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.PkgChangeNotificationConverter; +import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.PkgOnboardingNotificationConverter; import org.onap.so.adapters.vnfmadapter.converters.etsicatalog.sol003.VnfPkgInfoConverter; import org.onap.so.adapters.vnfmadapter.converters.sol003.etsicatalog.PkgmSubscriptionRequestConverter; import org.onap.so.adapters.vnfmadapter.oauth.OAuth2AccessTokenAdapter; @@ -46,6 +48,8 @@ public class MessageConverterConfiguration { final DefaultConversionService service = new DefaultConversionService(); service.addConverter(new VnfPkgInfoConverter()); service.addConverter(new PkgmSubscriptionRequestConverter()); + service.addConverter(new PkgChangeNotificationConverter()); + service.addConverter(new PkgOnboardingNotificationConverter()); return service; } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java new file mode 100644 index 0000000000..e1c43098f8 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/AbstractPkgNotificationConverter.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.converters.etsicatalog.sol003; + +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgmLinks; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage; + +/** + * A base class that can be extended by classes for converting Etsi Catalog Manager Pkg Notification classes. Provides + * common methods that will be useful to those classes. + * + * @author andrew.a.lamb@est.tech + */ +abstract public class AbstractPkgNotificationConverter { + + protected URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks convert( + final PkgmLinks pkgmLinks) { + final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage linksVnfPackage = + new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage(); + if (pkgmLinks.getVnfPackage() != null) { + linksVnfPackage.setHref(pkgmLinks.getVnfPackage().getHref()); + } + + final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage linksSubscription = + new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinksVnfPackage(); + if (pkgmLinks.getSubscription() != null) { + linksSubscription.setHref(pkgmLinks.getSubscription().getHref()); + } + + final URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks links = + new URIisprovidedbytheclientwhencreatingthesubscriptionVnfPackageOnboardingNotificationLinks(); + links.setVnfPackage(linksVnfPackage); + links.setSubscription(linksSubscription); + return links; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java new file mode 100644 index 0000000000..8c4168632b --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgChangeNotificationConverter.java @@ -0,0 +1,79 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.converters.etsicatalog.sol003; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification; +import org.slf4j.Logger; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Service; + +/** + * Converter to convert from an Etsi Catalog Manager {@link PkgChangeNotification} Object to its equivalent SOL003 + * {@link VnfPackageChangeNotification} Object + * + * @author andrew.a.lamb@est.tech + */ +@Service +public class PkgChangeNotificationConverter extends AbstractPkgNotificationConverter + implements Converter { + private static final Logger logger = getLogger(PkgChangeNotificationConverter.class); + + /** + * Convert a {@link PkgChangeNotification} Object to an {@link VnfPackageChangeNotification} Object + * + * @param pkgChangeNotification The PkgChangeNotification Object to Convert + * @return The Converted VnfPackageChangeNotification Object + */ + @Override + public VnfPackageChangeNotification convert(final PkgChangeNotification pkgChangeNotification) { + logger.info("Converting PkgChangeNotification\n{}", pkgChangeNotification.toString()); + final VnfPackageChangeNotification vnfPackageChangeNotification = new VnfPackageChangeNotification(); + vnfPackageChangeNotification.setId(pkgChangeNotification.getId()); + + if (pkgChangeNotification.getNotificationType() != null) { + vnfPackageChangeNotification.setNotificationType(VnfPackageChangeNotification.NotificationTypeEnum + .fromValue(pkgChangeNotification.getNotificationType().getValue())); + } + + vnfPackageChangeNotification.setSubscriptionId(pkgChangeNotification.getSubscriptionId()); + vnfPackageChangeNotification.setTimeStamp(pkgChangeNotification.getTimeStamp()); + vnfPackageChangeNotification.setVnfPkgId(pkgChangeNotification.getVnfPkgId()); + + vnfPackageChangeNotification.setVnfdId(pkgChangeNotification.getVnfdId()); + + if (pkgChangeNotification.getChangeType() != null) { + vnfPackageChangeNotification.setChangeType(VnfPackageChangeNotification.ChangeTypeEnum + .fromValue(pkgChangeNotification.getChangeType().getValue())); + } + + if (pkgChangeNotification.getOperationalState() != null) { + vnfPackageChangeNotification.setOperationalState(VnfPackageChangeNotification.OperationalStateEnum + .fromValue(pkgChangeNotification.getOperationalState().getValue())); + } + + vnfPackageChangeNotification.setLinks(convert((pkgChangeNotification.getLinks()))); + + return vnfPackageChangeNotification; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java new file mode 100644 index 0000000000..836acb6d36 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/etsicatalog/sol003/PkgOnboardingNotificationConverter.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.converters.etsicatalog.sol003; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification; +import org.slf4j.Logger; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Service; + +/** + * Converter to convert from an Etsi Catalog Manager {@link PkgOnboardingNotification} Object to its equivalent SOL003 + * {@link VnfPackageOnboardingNotification} Object + * + * @author andrew.a.lamb@est.tech + */ +@Service +public class PkgOnboardingNotificationConverter extends AbstractPkgNotificationConverter + implements Converter { + private static final Logger logger = getLogger(PkgOnboardingNotificationConverter.class); + + /** + * Convert a {@link PkgOnboardingNotification} Object to an {@link VnfPackageOnboardingNotification} Object + * + * @param pkgOnboardingNotification The PkgOnboardingNotification Object to Convert + * @return The Converted VnfPackageOnboardingNotification Object + */ + @Override + public VnfPackageOnboardingNotification convert(final PkgOnboardingNotification pkgOnboardingNotification) { + logger.info("Converting PkgChangeNotification\n{}", pkgOnboardingNotification.toString()); + final VnfPackageOnboardingNotification vnfPackageOnboardingNotification = + new VnfPackageOnboardingNotification(); + vnfPackageOnboardingNotification.setId(pkgOnboardingNotification.getId()); + + if (pkgOnboardingNotification.getNotificationType() != null) { + vnfPackageOnboardingNotification.setNotificationType(VnfPackageOnboardingNotification.NotificationTypeEnum + .fromValue(pkgOnboardingNotification.getNotificationType().getValue())); + } + + vnfPackageOnboardingNotification.setSubscriptionId(pkgOnboardingNotification.getSubscriptionId()); + vnfPackageOnboardingNotification.setTimeStamp(pkgOnboardingNotification.getTimeStamp()); + vnfPackageOnboardingNotification.setVnfPkgId(pkgOnboardingNotification.getVnfPkgId()); + vnfPackageOnboardingNotification.setVnfdId(pkgOnboardingNotification.getVnfdId()); + + vnfPackageOnboardingNotification.setLinks(convert((pkgOnboardingNotification.getLinks()))); + + return vnfPackageOnboardingNotification; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java new file mode 100644 index 0000000000..86ca59cffe --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/AbstractNotificationServiceProvider.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import java.nio.charset.StandardCharsets; +import org.apache.commons.codec.binary.Base64; +import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.onap.so.configuration.rest.HttpHeadersProvider; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.onap.so.rest.service.HttpRestServiceProviderImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.client.RestTemplate; + +/** + * A base class that can be extended by classes for providing notification services. Provides common methods that will + * be useful to those classes. + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +public abstract class AbstractNotificationServiceProvider { + + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate restTemplate; + + protected HttpRestServiceProvider getHttpRestServiceProvider(final HttpHeadersProvider httpHeadersProvider) { + final HttpRestServiceProvider httpRestServiceProvider = + new HttpRestServiceProviderImpl(restTemplate, httpHeadersProvider); + return httpRestServiceProvider; + } + + protected BasicHttpHeadersProvider getBasicHttpHeadersProviderWithBasicAuth(final String username, + final String password) { + final byte[] encodedAuth = getBasicAuth(username, password); + final String authHeader = "Basic " + new String(encodedAuth); + return new BasicHttpHeadersProvider(authHeader); + } + + protected byte[] getBasicAuth(final String username, final String password) { + final String auth = username + ":" + password; + return Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1)); + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java new file mode 100644 index 0000000000..6f9d94e9de --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/BasicAuthNotificationServiceProvider.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.configuration.rest.HttpHeadersProvider; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.slf4j.Logger; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +/** + * Implementation of a NotificationServiceProvider which supports Basic Authentication + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@Service +public class BasicAuthNotificationServiceProvider extends AbstractNotificationServiceProvider + implements NotificationServiceProvider { + + private static final Logger logger = getLogger(BasicAuthNotificationServiceProvider.class); + + @Override + public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication, + final String callbackUri) { + logger.info("Sending notification to uri: {}", callbackUri); + final HttpHeadersProvider httpHeadersProvider = + getBasicHttpHeadersProviderWithBasicAuth(subscriptionsAuthentication.getParamsBasic().getUserName(), + subscriptionsAuthentication.getParamsBasic().getPassword()); + final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider); + + final ResponseEntity responseEntity = + httpRestServiceProvider.postHttpRequest(notification, callbackUri, Void.class); + if (responseEntity.getStatusCode().is2xxSuccessful()) { + logger.info("Notification sent successfully."); + return true; + } + + logger.error("Failed to send notification."); + return false; + } + + @Override + public AuthTypeEnum getAuthType() { + return AuthTypeEnum.BASIC; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java new file mode 100644 index 0000000000..c1051d1c9d --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationManager.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import java.util.List; +import java.util.Optional; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.ConversionFailedException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.NotificationTypeNotSupportedException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionNotFoundException; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.stereotype.Service; + +/** + * Manages package management subscription notifications to the VNFMs + * + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ +@Service +public class NotificationManager { + + private static final Logger logger = getLogger(NotificationManager.class); + private final ConversionService conversionService; + private final SubscriptionManager subscriptionManager; + private final NotificationServiceProviderFactory notificationServiceProviderFactory; + + @Autowired + public NotificationManager(final SubscriptionManager subscriptionManager, final ConversionService conversionService, + final NotificationServiceProviderFactory notificationServiceProviderFactory) { + this.subscriptionManager = subscriptionManager; + this.conversionService = conversionService; + this.notificationServiceProviderFactory = notificationServiceProviderFactory; + } + + /** + * Process a subscription notification. Checks for a subscription request stored in the adapter and if there is, it + * sends the notification to the subscribed vnfm. + * + * @param notification the notification to send to the vnfm + * @param subscriptionId the id of the subscription request + * @return true if the notification is successfully sent + */ + public boolean processSubscriptionNotification(final Object notification, final String subscriptionId) { + final Optional optionalSubscription = + subscriptionManager.getSubscriptionRequest(subscriptionId); + if (optionalSubscription.isPresent()) { + final PkgmSubscriptionRequest subscriptionRequest = optionalSubscription.get(); + return notifyVnfm(subscriptionRequest, notification); + } + final String errorMessage = "No subscription found with subscriptionId " + subscriptionId + + ". Unable to forward notification to subscriber."; + logger.error(errorMessage); + throw new SubscriptionNotFoundException(errorMessage); + } + + private boolean notifyVnfm(final PkgmSubscriptionRequest subscriptionRequest, final Object notification) { + if (!(notification instanceof PkgOnboardingNotification) && !(notification instanceof PkgChangeNotification)) { + final String errorMessage = + "An error occurred. Notification type not supported for: " + notification.getClass(); + logger.error(errorMessage); + throw new NotificationTypeNotSupportedException(errorMessage); + } + + final SubscriptionsAuthentication subscriptionsAuthentication = subscriptionRequest.getAuthentication(); + final AuthTypeEnum authType = getAuthType(subscriptionsAuthentication.getAuthType()); + final NotificationServiceProvider sender = notificationServiceProviderFactory.getNotificationSender(authType); + + final Object vnfmNotificationObject = convertEtsiCatalogNotification(notification); + + if (sender.send(vnfmNotificationObject, subscriptionsAuthentication, subscriptionRequest.getCallbackUri())) { + logger.info("Notification delivered successfully {}", notification); + return true; + } + + logger.error("Failed to deliver notification."); + return false; + } + + private SubscriptionsAuthentication.AuthTypeEnum getAuthType(final List authTypes) { + if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT)) { + return SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT; + } + if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS)) { + return SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS; + } + if (authTypes.contains(SubscriptionsAuthentication.AuthTypeEnum.BASIC)) { + return SubscriptionsAuthentication.AuthTypeEnum.BASIC; + } + final String errorMessage = + "An error occurred. No supported authentication type provided in subscription request."; + logger.error(errorMessage); + throw new AuthenticationTypeNotSupportedException(errorMessage); + } + + private Object convertEtsiCatalogNotification(final Object etsiCatalogNotification) { + logger.info("Converting notification:\n {}", etsiCatalogNotification); + if (conversionService.canConvert(etsiCatalogNotification.getClass(), VnfPackageOnboardingNotification.class)) { + return conversionService.convert(etsiCatalogNotification, VnfPackageOnboardingNotification.class); + } else if (conversionService.canConvert(etsiCatalogNotification.getClass(), + VnfPackageChangeNotification.class)) { + return conversionService.convert(etsiCatalogNotification, VnfPackageChangeNotification.class); + } + final String errorMessage = "An error occurred. Unable to convert provided notification object."; + logger.error(errorMessage + "\n" + etsiCatalogNotification); + throw new ConversionFailedException(errorMessage); + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java new file mode 100644 index 0000000000..2be80eec75 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProvider.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; + +/** + * Interface which lays out requirements for a Notification Service Provider + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +public interface NotificationServiceProvider { + + /** + * Method to send a notification to a uri, given the subscription authentication + * + * @param notification The notification to send + * @param subscriptionsAuthentication Object containing the authentication details + * @param callbackUri The uri to send the notification to + * @return true if notification is delivered successfully, otherwise false + */ + boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication, + final String callbackUri); + + /** + * Method to get the supported authorization type of the service provider + * + * @return the supported AuthTypeEnum + */ + AuthTypeEnum getAuthType(); + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java new file mode 100644 index 0000000000..ab67afed82 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/NotificationServiceProviderFactory.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Factory to provide a notification services + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@Component +public class NotificationServiceProviderFactory { + + private static final Logger logger = getLogger(NotificationServiceProviderFactory.class); + private static final Map CACHE = new HashMap<>(); + + @Autowired + public NotificationServiceProviderFactory(final List services) { + for (final NotificationServiceProvider notificationServiceProvider : services) { + logger.debug("Adding {} of type {} to cache", notificationServiceProvider.getClass().getCanonicalName(), + notificationServiceProvider.getAuthType()); + CACHE.put(notificationServiceProvider.getAuthType(), notificationServiceProvider); + } + } + + /** + * Get a notification service for a given authorization type + * + * @param type the type of authentication required + * @return the notification service + */ + public NotificationServiceProvider getNotificationSender(final AuthTypeEnum type) { + final NotificationServiceProvider service = CACHE.get(type); + if (service == null) { + throw new AuthenticationTypeNotSupportedException("Unknown type: " + type); + } + return service; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java new file mode 100644 index 0000000000..496fb083cf --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthNotificationServiceProvider.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException; +import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.onap.so.configuration.rest.HttpHeadersProvider; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.slf4j.Logger; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ +@Service +public class OAuthNotificationServiceProvider extends AbstractNotificationServiceProvider + implements NotificationServiceProvider { + + private static final Logger logger = getLogger(OAuthNotificationServiceProvider.class); + + @Override + public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication, + final String callbackUri) { + logger.info("Sending notification to uri: {}", callbackUri); + final String token = getAccessToken(subscriptionsAuthentication); + + if (token == null) { + return false; + } + + final HttpHeadersProvider httpHeadersProvider = getHttpHeadersProvider(token); + final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider); + final ResponseEntity responseEntity = + httpRestServiceProvider.postHttpRequest(notification, callbackUri, Void.class); + if (responseEntity.getStatusCode().is2xxSuccessful()) { + logger.info("Notification sent successfully."); + return true; + } + + logger.error("Failed to send notification."); + return false; + } + + @Override + public AuthTypeEnum getAuthType() { + return AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS; + } + + private BasicHttpHeadersProvider getHttpHeadersProvider(final String token) { + final String authHeader = "Bearer " + token; + return new BasicHttpHeadersProvider(authHeader); + } + + private String getAccessToken(final SubscriptionsAuthentication subscriptionsAuthentication) { + logger.info("Requesting Access Token."); + + final String tokenEndpoint = subscriptionsAuthentication.getParamsOauth2ClientCredentials().getTokenEndpoint(); + + final HttpHeadersProvider httpHeadersProvider = getBasicHttpHeadersProviderWithBasicAuth( + subscriptionsAuthentication.getParamsOauth2ClientCredentials().getClientId(), + subscriptionsAuthentication.getParamsOauth2ClientCredentials().getClientPassword()); + + final HttpRestServiceProvider httpRestServiceProvider = getHttpRestServiceProvider(httpHeadersProvider); + final ResponseEntity responseEntity = + httpRestServiceProvider.postHttpRequest(null, tokenEndpoint, OAuthTokenResponse.class); + if (responseEntity.getStatusCode().is2xxSuccessful()) { + if (responseEntity.getBody() != null) { + logger.info("Returning Access Token."); + return responseEntity.getBody().getAccessToken(); + } + } + + final String errorMessage = "An error occurred. Unable to retrieve OAuth Token from VNFM for notification."; + logger.error(errorMessage); + throw new InternalServerErrorException(errorMessage); + } + + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java new file mode 100644 index 0000000000..146641cc7c --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/OAuthTokenResponse.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import java.io.Serializable; +import javax.xml.bind.annotation.XmlElement; +import com.google.gson.annotations.SerializedName; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +public class OAuthTokenResponse implements Serializable { + + private static final long serialVersionUID = -6455742984985959926L; + + @XmlElement(name = "access_token") + @SerializedName("access_token") + private String accessToken; + + /** + * Get the Accees Token + * + * @return the Access Token + */ + public String getAccessToken() { + return accessToken; + } + + /** + * Set the Access Token + * + * @param accessToken + */ + public void setAccessToken(final String accessToken) { + this.accessToken = accessToken; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java index d02bd9a345..a4c52fd13d 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java @@ -41,12 +41,11 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model. import org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement.cache.PackageManagementCacheServiceProvider; import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException; import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionNotFoundException; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.SubscriptionRequestConversionException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.ConversionFailedException; import org.onap.so.utils.CryptoUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; import org.springframework.stereotype.Service; @@ -67,7 +66,6 @@ public class SubscriptionManager { private final String msoKeyString; private final String vnfmAdapterAuth; - @Autowired public SubscriptionManager(final PackageManagementCacheServiceProvider packageManagementCacheServiceProvider, final ConversionService conversionService, final EtsiCatalogServiceProvider etsiCatalogServiceProvider, @@ -112,7 +110,6 @@ public class SubscriptionManager { "Received empty response from POST to ETSI Catalog Manager Subscription Endpoint."); } - public Optional getSubscriptionId(final PkgmSubscriptionRequest pkgmSubscriptionRequest) { return packageManagementCacheServiceProvider.getSubscriptionId(pkgmSubscriptionRequest); } @@ -174,6 +171,10 @@ public class SubscriptionManager { vnfmAdapterEndpoint + Constants.PACKAGE_MANAGEMENT_BASE_URL + "/subscriptions/" + subscriptionId); } + public Optional getSubscriptionRequest(final String subscriptionId) { + return packageManagementCacheServiceProvider.getSubscription(subscriptionId); + } + private InlineResponse2002 getInlineResponse2002(final String id, final PkgmSubscriptionRequest subscription) { return new InlineResponse2002().id(id).filter(subscription.getFilter()) .callbackUri(subscription.getCallbackUri()); @@ -186,9 +187,9 @@ public class SubscriptionManager { try { etsiCatalogManagerSubscriptionRequest = conversionService.convert(pkgmSubscriptionRequest, org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.PkgmSubscriptionRequest.class); - } catch (final ConversionException conversionException) { + } catch (final org.springframework.core.convert.ConversionException conversionException) { logger.error(conversionException.getMessage()); - throw new SubscriptionRequestConversionException( + throw new ConversionFailedException( "Could not convert Sol003 PkgmSubscriptionRequest to ETSI-Catalog Manager PkgmSubscriptionRequest"); } catch (final Exception exception) { logger.error(exception.getMessage()); @@ -209,7 +210,7 @@ public class SubscriptionManager { .addAuthTypeItem(BASIC).paramsBasic(new BasicAuth().userName(username).password(password))); return etsiCatalogManagerSubscriptionRequest; } - throw new SubscriptionRequestConversionException( + throw new ConversionFailedException( "Failed to convert Sol003 PkgmSubscriptionRequest to ETSI-Catalog Manager PkgmSubscriptionRequest"); } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java new file mode 100644 index 0000000000..c9babbd345 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/TlsNotificationServiceProvider.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Ericsson. All rights reserved. + * ================================================================================ + * 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.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.AuthenticationTypeNotSupportedException; +import org.slf4j.Logger; +import org.springframework.stereotype.Service; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@Service +public class TlsNotificationServiceProvider extends AbstractNotificationServiceProvider + implements NotificationServiceProvider { + + private static final Logger logger = getLogger(TlsNotificationServiceProvider.class); + + @Override + public boolean send(final Object notification, final SubscriptionsAuthentication subscriptionsAuthentication, + final String callbackUri) { + final String errorMessage = "An error occurred. Authentication type " + + subscriptionsAuthentication.getAuthType().toString() + " not currently supported."; + logger.error(errorMessage); + throw new AuthenticationTypeNotSupportedException(errorMessage); + } + + + @Override + public AuthTypeEnum getAuthType() { + return AuthTypeEnum.TLS_CERT; + } + + + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationController.java index a2f44f9deb..a97f04bcc8 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationController.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationController.java @@ -22,27 +22,110 @@ package org.onap.so.adapters.vnfmadapter.rest; import static org.onap.so.adapters.vnfmadapter.Constants.ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL; import static org.slf4j.LoggerFactory.getLogger; +import java.util.AbstractMap; +import java.util.Map.Entry; +import javax.ws.rs.core.MediaType; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification; +import org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement.NotificationManager; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.InternalServerErrorException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.NotificationTypeNotSupportedException; import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; /** * This controller handles the ETSI Subscription Notification Endpoints. * * @author Ronan Kenny (ronan.kenny@est.tech) * @author Gareth Roper (gareth.roper@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) */ @Controller @RequestMapping(value = ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL) public class EtsiSubscriptionNotificationController { private static final Logger logger = getLogger(EtsiSubscriptionNotificationController.class); + private final NotificationManager notificationManager; + private final Gson gson; + + @Autowired + public EtsiSubscriptionNotificationController(final NotificationManager notificationManager) { + this.notificationManager = notificationManager; + this.gson = new GsonBuilder().create(); + } @GetMapping(value = "/notification") public ResponseEntity testSubscriptionNotificationEndPoint() { logger.debug("Testing Notification Endpoint"); return ResponseEntity.noContent().build(); } + + /** + * POST notification on to subscriber. + * + * @param notification The notification to send. + * @return Response Code: 204 No Content if Successful, ProblemDetails Object if not. + */ + @PostMapping(value = "/notification", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + public ResponseEntity postSubscriptionNotification(@RequestBody final String notification) { + logger.info("Posting subscription notification \n{}", notification); + + final Entry notificationObject = getNotificationObject(notification); + if (notificationManager.processSubscriptionNotification(notificationObject.getValue(), + notificationObject.getKey())) { + logger.info("Notification Delivered Successfully"); + return ResponseEntity.noContent().build(); + } + final String errorMessage = "An error occurred. Sending of notification to VNFM failed."; + logger.error(errorMessage); + throw new InternalServerErrorException(errorMessage); + } + + private Entry getNotificationObject(final String notification) { + final String notificationType = getNotificationType(notification); + if (PkgOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION.getValue() + .equals(notificationType)) { + final PkgOnboardingNotification pkgOnboardingNotification = + gson.fromJson(notification, PkgOnboardingNotification.class); + logger.info("Onboarding notification received:\n{}", pkgOnboardingNotification); + return new AbstractMap.SimpleEntry<>(pkgOnboardingNotification.getSubscriptionId(), + pkgOnboardingNotification); + } + if (PkgChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.getValue() + .equals(notificationType)) { + final PkgChangeNotification pkgChangeNotification = + gson.fromJson(notification, PkgChangeNotification.class); + logger.info("Change notification received:\n{}", pkgChangeNotification); + return new AbstractMap.SimpleEntry<>(pkgChangeNotification.getSubscriptionId(), pkgChangeNotification); + + } + + final String errorMessage = "An error occurred. Notification type not supported for: " + notificationType; + logger.error(errorMessage); + throw new NotificationTypeNotSupportedException(errorMessage); + + } + + private String getNotificationType(final String notification) { + try { + final JsonParser parser = new JsonParser(); + final JsonObject element = (JsonObject) parser.parse(notification); + return element.get("notificationType").getAsString(); + } catch (final Exception e) { + logger.error("An error occurred processing notificiation: {}", e.getMessage()); + } + throw new NotificationTypeNotSupportedException( + "Unable to parse notification type in object \n" + notification); + } + } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java new file mode 100644 index 0000000000..303420f1e8 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/AuthenticationTypeNotSupportedException.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for an unsupported authentication type + * + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class AuthenticationTypeNotSupportedException extends RuntimeException { + + private static final long serialVersionUID = 2939423208362066902L; + + public AuthenticationTypeNotSupportedException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/ConversionFailedException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/ConversionFailedException.java new file mode 100644 index 0000000000..e19a53d1dc --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/ConversionFailedException.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for Conversion Failures + * + * @author Gareth Roper (gareth.roper@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class ConversionFailedException extends RuntimeException { + + private static final long serialVersionUID = 45898561453196895L; + + public ConversionFailedException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java new file mode 100644 index 0000000000..e8e1ce35b9 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiSubscriptionNotificationControllerExceptionHandler.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest.exceptions; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; +import org.onap.so.adapters.vnfmadapter.rest.EtsiSubscriptionNotificationController; +import org.onap.so.rest.exceptions.HttpResouceNotFoundException; +import org.onap.so.rest.exceptions.InvalidRestRequestException; +import org.onap.so.rest.exceptions.RestProcessingException; +import org.slf4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Exception Handler for the Etsi Subscription Notification Controller {@link EtsiSubscriptionNotificationController + * EtsiSubscriptionNotificationController} + * + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@ControllerAdvice(assignableTypes = EtsiSubscriptionNotificationController.class) +public class EtsiSubscriptionNotificationControllerExceptionHandler { + + private static final Logger logger = getLogger(EtsiSubscriptionNotificationControllerExceptionHandler.class); + + @ExceptionHandler(InvalidRestRequestException.class) + public ResponseEntity handleInvalidRestRequestException( + final InvalidRestRequestException invalidRestRequestException) { + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.BAD_REQUEST + ".\n" + invalidRestRequestException.getMessage(); + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage)); + } + + @ExceptionHandler(HttpResouceNotFoundException.class) + public ResponseEntity handleHttpResourceNotFoundException( + final HttpResouceNotFoundException httpResourceNotFoundException) { + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.NOT_FOUND + ".\n" + httpResourceNotFoundException.getMessage(); + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage)); + } + + @ExceptionHandler(RestProcessingException.class) + public ResponseEntity handleRestProcessingException( + final RestProcessingException restProcessingException) { + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + restProcessingException.getStatusCode() + ".\n" + restProcessingException.getMessage(); + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ProblemDetails().detail(errorMessage)); + } + + @ExceptionHandler(InternalServerErrorException.class) + public ResponseEntity handleInternalServerErrorException( + final InternalServerErrorException internalServerErrorException) { + logger.error(internalServerErrorException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ProblemDetails().detail(internalServerErrorException.getMessage())); + } + + @ExceptionHandler(AuthenticationTypeNotSupportedException.class) + public ResponseEntity handleAuthenticationTypeNotSupportedException( + final AuthenticationTypeNotSupportedException authenticationTypeNotSupportedException) { + logger.error(authenticationTypeNotSupportedException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ProblemDetails().detail(authenticationTypeNotSupportedException.getMessage())); + } + + @ExceptionHandler(ConversionFailedException.class) + public ResponseEntity handleConversionFailedException( + final ConversionFailedException conversionFailedException) { + logger.error(conversionFailedException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ProblemDetails().detail(conversionFailedException.getMessage())); + } + + @ExceptionHandler(NotificationTypeNotSupportedException.class) + public ResponseEntity handleNotificationTypeNotSupportedException( + final NotificationTypeNotSupportedException notificationTypeNotSupportedException) { + logger.error(notificationTypeNotSupportedException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ProblemDetails().detail(notificationTypeNotSupportedException.getMessage())); + } + + @ExceptionHandler(SubscriptionNotFoundException.class) + public ResponseEntity handleSubscriptionNotFoundException( + final SubscriptionNotFoundException subscriptionNotFoundException) { + logger.error(subscriptionNotFoundException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ProblemDetails().detail(subscriptionNotFoundException.getMessage())); + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java new file mode 100644 index 0000000000..dcc98864aa --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/NotificationTypeNotSupportedException.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for an unsupported notification type + * + * @author Andrew Lamb (andrew.a.lamb@est.tech) + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class NotificationTypeNotSupportedException extends RuntimeException { + + private static final long serialVersionUID = 2939423208362066902L; + + public NotificationTypeNotSupportedException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java index da8b0cbff2..8091f35da6 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java @@ -22,10 +22,6 @@ package org.onap.so.adapters.vnfmadapter.rest.exceptions; import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; import org.onap.so.adapters.vnfmadapter.rest.Sol003PackageManagementController; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.EtsiCatalogManagerRequestFailureException; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgBadRequestException; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgConflictException; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -64,11 +60,11 @@ public class Sol003PackageManagementControllerExceptionHandler { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(problemDetails); } - @ExceptionHandler(SubscriptionRequestConversionException.class) - public ResponseEntity handleSubscriptionRequestConversionException( - final SubscriptionRequestConversionException subscriptionRequestConversionException) { + @ExceptionHandler(ConversionFailedException.class) + public ResponseEntity handleConversionFailedException( + final ConversionFailedException conversionFailedException) { final ProblemDetails problemDetails = new ProblemDetails(); - problemDetails.setDetail(subscriptionRequestConversionException.getMessage()); + problemDetails.setDetail(conversionFailedException.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(problemDetails); } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/SubscriptionRequestConversionException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/SubscriptionRequestConversionException.java deleted file mode 100644 index daa544f928..0000000000 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/SubscriptionRequestConversionException.java +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -/** - * Exception for an ETSI Catalog Manager Request Failure - * - * @author gareth.roper@est.tech - */ -@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) -public class SubscriptionRequestConversionException extends RuntimeException { - - private static final long serialVersionUID = 45898561453196895L; - - public SubscriptionRequestConversionException(final String message) { - super(message); - } - - @Override - public synchronized Throwable fillInStackTrace() { - return this; - } -} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java new file mode 100644 index 0000000000..8012f7e6cf --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/EtsiSubscriptionNotificationControllerTest.java @@ -0,0 +1,592 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.so.adapters.vnfmadapter.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onap.so.adapters.vnfmadapter.Constants.ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.so.adapters.vnfmadapter.Constants; +import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.NOTIFICATIONLINKSERIALIZER; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgOnboardingNotification; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model.PkgmLinks; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthentication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthenticationParamsBasic; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.SubscriptionsAuthenticationParamsOauth2ClientCredentials; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageChangeNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.notification.model.VnfPackageOnboardingNotification; +import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.http.*; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZoneOffset; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VnfmAdapterApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class EtsiSubscriptionNotificationControllerTest { + + @LocalServerPort + private int port; + + private static final URI CALLBACK_URI = URI.create("http://test_callback_uri/notification"); + private static final String TOKEN_ENDPOINT = "http://test_token_endpoint_uri/"; + private static final String TOKEN = "dXNlcm5hbWU6cGFzc3dvcmQ=......"; + private static final String JSON_TOKEN = "{\"access_token\":\"" + TOKEN + "\"}"; + private static final String LOCALHOST_URL = "http://localhost:"; + private static final String NOTIFICATION_BASE_URL = + ETSI_SUBSCRIPTION_NOTIFICATION_CONTROLLER_BASE_URL + "/notification"; + private static final String USERNAME = "username"; + private static final String PASSWORD = "password"; + private static final String EXPECTED_BASIC_AUTHORIZATION = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; + private static final String EXPECTED_OAUTH_AUTHORIZATION = "Bearer " + TOKEN; + private static final String NOTIFICATION_ID = "NOTIFICATION_ID"; + private static final String SUBSCRIPTION_ID = "SUBSCRIPTION_ID"; + private static final OffsetDateTime TIMESTAMP = + OffsetDateTime.of(LocalDateTime.of(2020, 1, 1, 1, 1, 1, 1), ZoneOffset.ofHours(1)); + private static final String VNFPKG_ID = UUID.randomUUID().toString(); + private static final String VNFD_ID = UUID.randomUUID().toString(); + + private BasicHttpHeadersProvider basicHttpHeadersProvider; + private final Gson gson = new GsonBuilder().create();; + + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate restTemplate; + private MockRestServiceServer mockRestServer; + + @Autowired + private TestRestTemplate testRestTemplate; + + @Autowired + private CacheManager cacheServiceProvider; + private Cache cache; + + @Before + public void setUp() { + mockRestServer = MockRestServiceServer.bindTo(restTemplate).build(); + basicHttpHeadersProvider = new BasicHttpHeadersProvider(); + cache = cacheServiceProvider.getCache(Constants.PACKAGE_MANAGEMENT_SUBSCRIPTION_CACHE); + cache.clear(); + } + + @After + public void tearDown() { + cache.clear(); + } + + @Test + public void testSubscriptionNotificationEndPoint_ReturnsNoContent() { + final ResponseEntity response = sendHttpGet(NOTIFICATION_BASE_URL); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void testOnboardingNotificationSentOnToVnfmCallbackUri_SubscriptionRequestInCache_Success() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andExpect(jsonPath("$.id").value(NOTIFICATION_ID)) + .andExpect(jsonPath("$.notificationType") + .value(VnfPackageOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION + .toString())) + .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID)) + .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString())) + .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString())) + .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString())) + .andExpect(jsonPath("$._links").value(buildPkgmLinks())) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess()); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void testOnboardingNotificationNotSentOnToVnfmCallbackUri_SubscriptionRequestNotInCache_Fail() { + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "No subscription found with subscriptionId " + SUBSCRIPTION_ID + + ". Unable to forward notification to subscriber."; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testOnboardingNotificationSentOnToVnfmCallbackUri_BadRequestResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.BAD_REQUEST + ".\n" + "No result found for given url: " + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testOnboardingNotificationSentOnToVnfmCallbackUri_301MovedPermanentlyResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.MOVED_PERMANENTLY)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed."; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testOnboardingNotificationSentOnToVnfmCallbackUri_NotFoundResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.NOT_FOUND + ".\n" + "No result found for given url: " + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testOnboardingNotificationSentOnToVnfmCallbackUri_InternalServerErrorResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.INTERNAL_SERVER_ERROR.value() + ".\n" + "Unable to invoke HTTP POST using URL: " + + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testChangeNotificationSentOnToVnfmCallbackUri_SubscriptionRequestInCache_Success() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andExpect(jsonPath("$.id").value(NOTIFICATION_ID)) + .andExpect(jsonPath("$.notificationType").value( + VnfPackageChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.toString())) + .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID)) + .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString())) + .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString())) + .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString())) + .andExpect( + jsonPath("$.changeType").value(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE.toString())) + .andExpect(jsonPath("$.operationalState") + .value(PkgChangeNotification.OperationalStateEnum.ENABLED.toString())) + .andExpect(jsonPath("$._links").value(buildPkgmLinks())) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess()); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void testChangeNotificationNotSentOnToVnfmCallbackUri_SubscriptionRequestNotInCache_Fail() { + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "No subscription found with subscriptionId " + SUBSCRIPTION_ID + + ". Unable to forward notification to subscriber."; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testChangeNotificationSentOnToVnfmCallbackUri_BadRequestResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.BAD_REQUEST + ".\n" + "No result found for given url: " + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testChangeNotificationSentOnToVnfmCallbackUri_NotFoundResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.NOT_FOUND + ".\n" + "No result found for given url: " + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testChangeNotificationSentOnToVnfmCallbackUri_InternalServerErrorResponseFromCallbackUri_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.INTERNAL_SERVER_ERROR.value() + ".\n" + "Unable to invoke HTTP POST using URL: " + + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testNotificationSentOnToVnfm_BasicAuthUserPasswordAuthorized_Success() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgOnboardingNotification notification = buildPkgOnboardingNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andExpect(jsonPath("$.id").value(NOTIFICATION_ID)) + .andExpect(jsonPath("$.notificationType") + .value(VnfPackageOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION + .toString())) + .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID)) + .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString())) + .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString())) + .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString())) + .andExpect(jsonPath("$._links").value(buildPkgmLinks())) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess()); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void testNotificationSentOnToVnfm_BasicAuthUserPasswordNotAuthorized_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.BASIC); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)) + .andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Sending of notification to VNFM failed with response: " + + HttpStatus.UNAUTHORIZED.value() + ".\n" + "Unable to invoke HTTP POST using URL: " + CALLBACK_URI; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testNotificationSentOnToVnfm_OAuthAuthorized_Success() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(TOKEN_ENDPOINT)).andExpect(method(HttpMethod.POST)) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)) + .andRespond(withSuccess(JSON_TOKEN, MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo(CALLBACK_URI)).andExpect(method(HttpMethod.POST)) + .andExpect(header("Authorization", EXPECTED_OAUTH_AUTHORIZATION)) + .andExpect(jsonPath("$.id").value(NOTIFICATION_ID)) + .andExpect(jsonPath("$.notificationType").value( + VnfPackageChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION.toString())) + .andExpect(jsonPath("$.subscriptionId").value(SUBSCRIPTION_ID)) + .andExpect(jsonPath("$.timeStamp").value(TIMESTAMP.toString())) + .andExpect(jsonPath("$.vnfPkgId").value(VNFPKG_ID.toString())) + .andExpect(jsonPath("$.vnfdId").value(VNFD_ID.toString())) + .andExpect( + jsonPath("$.changeType").value(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE.toString())) + .andExpect(jsonPath("$.operationalState") + .value(PkgChangeNotification.OperationalStateEnum.ENABLED.toString())) + .andExpect(jsonPath("$._links").value(buildPkgmLinks())).andRespond(withSuccess()); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void testNotificationSentOnToVnfm_OAuthTokenNotReceived_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + mockRestServer.expect(requestTo(TOKEN_ENDPOINT)).andExpect(method(HttpMethod.POST)) + .andExpect(header("Authorization", EXPECTED_BASIC_AUTHORIZATION)).andRespond(withSuccess()); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Unable to retrieve OAuth Token from VNFM for notification."; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + @Test + public void testNotificationSentOnToVnfm_TLSCertNotYetSupported_Fail() { + final PkgmSubscriptionRequest subscriptionRequest = + buildPkgmSubscriptionRequest(SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT); + cache.put(SUBSCRIPTION_ID, subscriptionRequest); + final PkgChangeNotification notification = buildPkgChangeNotification(); + final String notificationString = gson.toJson(notification); + + final ResponseEntity response = sendHttpPost(notificationString); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertTrue(response.getBody() instanceof ProblemDetails); + + final ProblemDetails problemDetails = (ProblemDetails) response.getBody(); + final String errorMessage = "An error occurred. Authentication type " + + subscriptionRequest.getAuthentication().getAuthType().toString() + " not currently supported."; + + assertEquals(errorMessage, problemDetails.getDetail()); + } + + private PkgOnboardingNotification buildPkgOnboardingNotification() { + final PkgOnboardingNotification notification = new PkgOnboardingNotification(); + notification.setId(NOTIFICATION_ID); + notification + .setNotificationType(PkgOnboardingNotification.NotificationTypeEnum.VNFPACKAGEONBOARDINGNOTIFICATION); + notification.setSubscriptionId(SUBSCRIPTION_ID); + notification.setTimeStamp(TIMESTAMP); + notification.setVnfPkgId(VNFPKG_ID); + notification.setVnfdId(VNFD_ID); + notification.setLinks(buildPkgmLinks()); + return notification; + } + + private PkgChangeNotification buildPkgChangeNotification() { + final PkgChangeNotification notification = new PkgChangeNotification(); + notification.setId(NOTIFICATION_ID); + notification.setNotificationType(PkgChangeNotification.NotificationTypeEnum.VNFPACKAGECHANGENOTIFICATION); + notification.setSubscriptionId(SUBSCRIPTION_ID); + notification.setTimeStamp(TIMESTAMP); + notification.setVnfPkgId(VNFPKG_ID); + notification.setVnfdId(VNFD_ID); + notification.setChangeType(PkgChangeNotification.ChangeTypeEnum.OP_STATE_CHANGE); + notification.setOperationalState(PkgChangeNotification.OperationalStateEnum.ENABLED); + notification.setLinks(buildPkgmLinks()); + return notification; + } + + private PkgmLinks buildPkgmLinks() { + final PkgmLinks pkgmLinks = new PkgmLinks(); + + final NOTIFICATIONLINKSERIALIZER subscriptionLinkSerializer = new NOTIFICATIONLINKSERIALIZER(); + subscriptionLinkSerializer.setHref("subscription_href"); + pkgmLinks.setSubscription(subscriptionLinkSerializer); + + final NOTIFICATIONLINKSERIALIZER vnfPackageLinkSerializer = new NOTIFICATIONLINKSERIALIZER(); + vnfPackageLinkSerializer.setHref("vnf_package_href"); + pkgmLinks.setVnfPackage(vnfPackageLinkSerializer); + + return pkgmLinks; + } + + private PkgmSubscriptionRequest buildPkgmSubscriptionRequest( + final SubscriptionsAuthentication.AuthTypeEnum authTypeEnum) { + final PkgmSubscriptionRequest subscriptionRequest = new PkgmSubscriptionRequest(); + subscriptionRequest.setCallbackUri(CALLBACK_URI.toString()); + subscriptionRequest.setAuthentication(buildSubscriptionsAuthentication(authTypeEnum)); + return subscriptionRequest; + } + + // TODO update for auth types other than basicAuth + private SubscriptionsAuthentication buildSubscriptionsAuthentication( + final SubscriptionsAuthentication.AuthTypeEnum authTypeEnum) { + final SubscriptionsAuthentication subscriptionsAuthentication = new SubscriptionsAuthentication(); + final List authTypes = new ArrayList<>(); + authTypes.add(authTypeEnum); + subscriptionsAuthentication.setAuthType(authTypes); + if (authTypeEnum == SubscriptionsAuthentication.AuthTypeEnum.TLS_CERT) { + // TODO: remove basic params and code for TLS + final SubscriptionsAuthenticationParamsBasic basicParams = + new SubscriptionsAuthenticationParamsBasic().userName(USERNAME).password(PASSWORD); + subscriptionsAuthentication.setParamsBasic(basicParams); + } else if (authTypeEnum == SubscriptionsAuthentication.AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS) { + final SubscriptionsAuthenticationParamsOauth2ClientCredentials oathParams = + new SubscriptionsAuthenticationParamsOauth2ClientCredentials().clientId(USERNAME) + .clientPassword(PASSWORD).tokenEndpoint(TOKEN_ENDPOINT); + subscriptionsAuthentication.setParamsOauth2ClientCredentials(oathParams); + } else { + final SubscriptionsAuthenticationParamsBasic basicParams = + new SubscriptionsAuthenticationParamsBasic().userName(USERNAME).password(PASSWORD); + subscriptionsAuthentication.setParamsBasic(basicParams); + } + + return subscriptionsAuthentication; + } + + private ResponseEntity sendHttpPost(final T notification) { + final String testURL = LOCALHOST_URL + port + NOTIFICATION_BASE_URL; + final HttpEntity request = new HttpEntity<>(notification, basicHttpHeadersProvider.getHttpHeaders()); + return testRestTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.POST, request, + ProblemDetails.class); + } + + private ResponseEntity sendHttpGet(final String url) { + final String testURL = LOCALHOST_URL + port + url; + final HttpEntity request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + return testRestTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, Void.class); + } + +} diff --git a/pom.xml b/pom.xml index 0955338a4e..0719b205df 100644 --- a/pom.xml +++ b/pom.xml @@ -337,28 +337,28 @@ - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - - prepare-agent - - prepare-agent - - - - report - - report - - - ${project.build.directory}/code-coverage/jacoco.exec - ${project.reporting.outputDirectory}/jacoco-ut - - - - + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + + report + + + ${project.build.directory}/code-coverage/jacoco.exec + ${project.reporting.outputDirectory}/jacoco-ut + + + + org.codehaus.mojo license-maven-plugin -- cgit 1.2.3-korg