From 5775de7b0fc84a29511dc4a1a480c3ab32da2ade Mon Sep 17 00:00:00 2001 From: efiacor Date: Tue, 26 Mar 2019 14:29:01 +0000 Subject: [PATCH] DR AAF CADI integration Change-Id: I01548882f813e4029dddf7ddee2af12472163761 Issue-ID: DMAAP-1016 Signed-off-by: efiacor --- .../src/main/resources/database/sql_init_01.sql | 21 +- .../src/main/resources/docker-compose.yml | 4 +- .../node_data/aaf_certs/org.onap.dmaap-dr.keyfile | 27 ++ .../src/main/resources/node_data/node.properties | 80 +++--- .../prov_data/aaf_certs/org.onap.dmaap-dr.keyfile | 27 ++ .../src/main/resources/prov_data/addSubscriber.txt | 23 +- .../main/resources/prov_data/provserver.properties | 19 ++ .../aaf_certs/org.onap.dmaap-dr.keyfile | 27 ++ datarouter-node/pom.xml | 5 + .../dmaap/datarouter/node/DRNodeCadiFilter.java | 99 +++++++ .../onap/dmaap/datarouter/node/DeliveryTask.java | 15 +- .../org/onap/dmaap/datarouter/node/DestInfo.java | 17 +- .../org/onap/dmaap/datarouter/node/IsFrom.java | 30 ++- .../org/onap/dmaap/datarouter/node/LogManager.java | 3 +- .../org/onap/dmaap/datarouter/node/NodeConfig.java | 143 ++++++++-- .../dmaap/datarouter/node/NodeConfigManager.java | 202 ++++++++++++--- .../org/onap/dmaap/datarouter/node/NodeMain.java | 106 ++++++-- .../onap/dmaap/datarouter/node/NodeServlet.java | 160 ++++++++---- .../org/onap/dmaap/datarouter/node/PathUtil.java | 88 +++++++ .../org/onap/dmaap/datarouter/node/ProvData.java | 15 +- .../onap/dmaap/datarouter/node/SubnetMatcher.java | 2 - .../src/main/resources/drNodeCadi.properties | 23 ++ datarouter-node/src/main/resources/node.properties | 80 +++--- .../datarouter/node/DRNodeCadiFilterTest.java | 121 +++++++++ .../dmaap/datarouter/node/DeliveryQueueTest.java | 23 +- .../onap/dmaap/datarouter/node/DeliveryTest.java | 2 +- .../onap/dmaap/datarouter/node/NodeConfigTest.java | 2 + .../dmaap/datarouter/node/NodeServletTest.java | 16 +- .../aaf_certs/org.onap.dmaap-dr.keyfile | 27 ++ datarouter-prov/pom.xml | 5 + .../dmaap/datarouter/provisioning/BaseServlet.java | 287 +++++++++++++++------ .../datarouter/provisioning/DRFeedsServlet.java | 92 +++++-- .../dmaap/datarouter/provisioning/FeedServlet.java | 100 +++++-- .../onap/dmaap/datarouter/provisioning/Main.java | 283 +++++++++++--------- .../datarouter/provisioning/SubscribeServlet.java | 85 ++++-- .../provisioning/SubscriptionServlet.java | 91 +++++-- .../dmaap/datarouter/provisioning/beans/Feed.java | 91 ++++--- .../provisioning/beans/Subscription.java | 93 ++++--- .../dmaap/datarouter/provisioning/utils/DB.java | 8 +- .../provisioning/utils/DRProvCadiFilter.java | 259 +++++++++++++++++++ .../provisioning/utils/LogfileLoader.java | 12 +- .../provisioning/utils/PasswordProcessor.java | 73 ++++++ .../src/main/resources/drProvCadi.properties | 23 ++ .../src/main/resources/misc/sql_init_01.sql | 25 +- .../src/main/resources/provserver.properties | 18 +- .../provisioning/DRFeedsServletTest.java | 247 +++++++++++------- .../datarouter/provisioning/DrServletTestBase.java | 11 +- .../datarouter/provisioning/FeedServletTest.java | 128 +++++++-- .../provisioning/SubscribeServletTest.java | 219 +++++++++++----- .../provisioning/SubscriptionServletTest.java | 137 ++++++++-- .../provisioning/utils/DRProvCadiFilterTest.java | 269 +++++++++++++++++++ datarouter-prov/src/test/resources/create.sql | 41 ++- .../src/test/resources/h2Database.properties | 3 +- pom.xml | 1 + 54 files changed, 3105 insertions(+), 903 deletions(-) create mode 100755 datarouter-docker-compose/src/main/resources/node_data/aaf_certs/org.onap.dmaap-dr.keyfile create mode 100755 datarouter-docker-compose/src/main/resources/prov_data/aaf_certs/org.onap.dmaap-dr.keyfile create mode 100755 datarouter-node/aaf_certs/org.onap.dmaap-dr.keyfile create mode 100644 datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilter.java create mode 100644 datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/PathUtil.java create mode 100644 datarouter-node/src/main/resources/drNodeCadi.properties create mode 100644 datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilterTest.java create mode 100755 datarouter-prov/aaf_certs/org.onap.dmaap-dr.keyfile create mode 100644 datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilter.java create mode 100644 datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/PasswordProcessor.java create mode 100644 datarouter-prov/src/main/resources/drProvCadi.properties create mode 100644 datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilterTest.java diff --git a/datarouter-docker-compose/src/main/resources/database/sql_init_01.sql b/datarouter-docker-compose/src/main/resources/database/sql_init_01.sql index 14c59a65..83dfd0bc 100644 --- a/datarouter-docker-compose/src/main/resources/database/sql_init_01.sql +++ b/datarouter-docker-compose/src/main/resources/database/sql_init_01.sql @@ -4,7 +4,7 @@ CREATE TABLE FEEDS ( FEEDID INT UNSIGNED NOT NULL PRIMARY KEY, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, NAME VARCHAR(255) NOT NULL, - VERSION VARCHAR(20) NOT NULL, + VERSION VARCHAR(20) NULL, DESCRIPTION VARCHAR(1000), BUSINESS_DESCRIPTION VARCHAR(1000) DEFAULT NULL, AUTH_CLASS VARCHAR(32) NOT NULL, @@ -16,13 +16,14 @@ CREATE TABLE FEEDS ( DELETED BOOLEAN DEFAULT FALSE, LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + AAF_INSTANCE VARCHAR(256) ); CREATE TABLE FEED_ENDPOINT_IDS ( FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20) NOT NULL, - PASSWORD VARCHAR(32) NOT NULL + USERID VARCHAR(60) NOT NULL, + PASSWORD VARCHAR(100) NOT NULL ); CREATE TABLE FEED_ENDPOINT_ADDRS ( @@ -35,8 +36,9 @@ CREATE TABLE SUBSCRIPTIONS ( FEEDID INT UNSIGNED NOT NULL, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, DELIVERY_URL VARCHAR(256), - DELIVERY_USER VARCHAR(20), - DELIVERY_PASSWORD VARCHAR(32), + FOLLOW_REDIRECTS TINYINT(1) NOT NULL DEFAULT 0, + DELIVERY_USER VARCHAR(60), + DELIVERY_PASSWORD VARCHAR(100), DELIVERY_USE100 BOOLEAN DEFAULT FALSE, METADATA_ONLY BOOLEAN DEFAULT FALSE, SUBSCRIBER VARCHAR(8) NOT NULL, @@ -45,8 +47,9 @@ CREATE TABLE SUBSCRIPTIONS ( LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, PRIVILEGED_SUBSCRIBER BOOLEAN DEFAULT FALSE, + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DECOMPRESS BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + AAF_INSTANCE VARCHAR(256) ); @@ -89,7 +92,7 @@ CREATE TABLE LOG_RECORDS ( CREATE TABLE INGRESS_ROUTES ( SEQUENCE INT UNSIGNED NOT NULL, FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20), + USERID VARCHAR(50), SUBNET VARCHAR(44), NODESET INT UNSIGNED NOT NULL ); @@ -144,6 +147,6 @@ INSERT INTO PARAMETERS VALUES ('PROV_MAXFEED_COUNT', '10000'), ('PROV_MAXSUB_COUNT', '100000'), ('PROV_REQUIRE_CERT', 'false'), - ('PROV_REQUIRE_SECURE', 'false'), + ('PROV_REQUIRE_SECURE', 'true'), ('_INT_VALUES', 'LOGROLL_INTERVAL|PROV_MAXFEED_COUNT|PROV_MAXSUB_COUNT|DELIVERY_INIT_RETRY_INTERVAL|DELIVERY_MAX_RETRY_INTERVAL|DELIVERY_RETRY_RATIO|DELIVERY_MAX_AGE|DELIVERY_FILE_PROCESS_INTERVAL') ; diff --git a/datarouter-docker-compose/src/main/resources/docker-compose.yml b/datarouter-docker-compose/src/main/resources/docker-compose.yml index 8784ee68..bd4726aa 100644 --- a/datarouter-docker-compose/src/main/resources/docker-compose.yml +++ b/datarouter-docker-compose/src/main/resources/docker-compose.yml @@ -68,7 +68,7 @@ services: datarouter-subscriber: image: nexus3.onap.org:10001/onap/dmaap/datarouter-subscriber container_name: subscriber-node - hostname: subscriber.com + hostname: dmaap-dr-subscriber ports: - "7070:7070" volumes: @@ -76,7 +76,7 @@ services: networks: testing_net: aliases: - - subscriber.com + - dmaap-dr-subscriber mariadb_container: image: mariadb:10.2.14 diff --git a/datarouter-docker-compose/src/main/resources/node_data/aaf_certs/org.onap.dmaap-dr.keyfile b/datarouter-docker-compose/src/main/resources/node_data/aaf_certs/org.onap.dmaap-dr.keyfile new file mode 100755 index 00000000..85bfa61f --- /dev/null +++ b/datarouter-docker-compose/src/main/resources/node_data/aaf_certs/org.onap.dmaap-dr.keyfile @@ -0,0 +1,27 @@ +j4IkjDmzOE_ZdHuN_cePYmySXrhmqM4WuGp86_RTiBlJ1TTvUaP_SOSZOqH0fxjk32gRvxJ01_iO +mLtbQ-wZKk-fwCK_o6xrXJcN0G_Y8VGK2OMeqypm98ji25CSMvTdFLaohdPJwiRNMdmwwyF5q1Od +pKviCISBlQ49ytwy3Mv0x7aV3kjkDWSgpx9TiMbWoAKlddcdQMUTEMh0CT0nLGv9uhwmRQ4I8UuE +IzvR1Rit9HayMlXFND6n0IWggYqtAeRV-8wDrI2rAXGOrfLF0RC5-c0Wd0N000BWXvsT_nCYBCM6 +ffA5eAKCJmOVjJFzQTRXJq7Zhwij0CtEPgqqaipKUQhHaft9xeKXW3SPhREIn75F2u2uCcU1sNmd +ytAk7yBPwdEcCQD-KVE9ZB3_57H0WIEr45SpU5ZePJkt2YV85H2Tlc_hGK18gTAcvGqDO3qELmV5 +SBHX5X_ZNL93mOkt37R0SGRdMZVIPJXNTgl4fGAsapvU7Y7sGMYrf2Ea0D-3hctk-aOKuuPEI1Ug +0lqKjghJdvHYRFbm4C_7H-ai7UcBuixBd54Mp-hyBX-gjnFZuMHazFX2toKNe9RgDXIavHzTfF-l +8fjdQpTplc2ECLINf-X6gs7w0zPYv04kLKixwlFff4ZocoxelGDEBlYYGNNxQBZvQtUX_dZetXF1 +VPNnwTB7Sp0fqaXR2aVaZNFSZYeL7VdxkiT0becNRa9QE9s2gU7oO_KTE8JyAiJyO-ojAvSUi-p_ +rq2Ivmab_L4t6GwMpv-EmRcntUQ_PM4s_XvJL2RmmSPWoNvbgCS0IilpYi2CPnEEgxqX37-Unx8m +tYoNkiN-j9rA3Hr4EjEhrbOLf2wAh6RUeULerBpLKnf0Ans6UhjT7XVDaNvzxtAE-GrUCKHQ0ml2 +P_vzDBlGKobaRo-WQzQA-mZKGo1W4Q-qwFdusUflgfJ7iTrvw62jn30f4xGZcaP5Oa-9JvdZJggW +1UvAM-85LdjGTxuI9KXbqRLWZk46B-UF7mDOce6dbRXjY48bZWIHEXcpzPQg6QA02cO10TN5K89V +qXeCnz03ePf0u6YhMAOt5xiUvJpd1y_WI0jh4SH2dT26SegcuRTVLnEG0aL6ClypObwj3FLB1Pek +UESqziiG4mQf_rzBAdPqcjbP8oeM2-mz09VYNyUOQ-7gk6bMAMWVqBx0uDxgIwUzr2UMbahB2Kg6 +9V7yE7obAKZa8x5oMiDGnvgjL9QeHwhUsNbwhhgqTDnB10vj4gh8RkNK8OsxQ53Nofj2PQZfY0GJ +a6It7DCmnAgQ9N51RvCeodmmK9Zh3n_zoxt8gA-eV8zbidXZYQwYWx6ai7ooP7yol2bE_TLDDY9l +_oYO_db73wSmqgTvoAdmrQGO4NI_g2iYN-Gd4XK4V_xgYPKyY5tHNSd4OKr_UuYiSioyNxE4IK1t +zWyJ3tUXAyeq_ZjUDjabsnGnxmgujShRfK-rBh_1AapY3Oh99-aehETtcXihUmFX4lohowniWTA3 +MF1MMlRM5N1phF7xFgkAaZJfkQ-inqgWYvQ9XuW0LfumN4QeO8KnfknukSSgZ86PYTrgJKDIOKWn +UYsxSoE_U02WxQThW8ayrFtKRLGR2x9bMaKzaON0tfltwyQO7ttsKlSyORIWVrGO48CyEDxpDs8U +RDvN_SgFq1gWarCKLL0HDUdLGMfimZP7sPfVEKkprMlDp_gpx7kD7SaB1m7xuNjhBd-6I3gqSR7g +lizTgKmuGalPRGorxX72vlTEYqLtgNWok6e9qjMGhEYCf02li6Ksoxp4ZejN_9S1-FGlcuq3SE9f +Pm0HckGtPJ8u3u2mmLpT1QzzS0RG3XJU5kNJvZcSEG0GOsU7OnWTXoZnleFJvEoQrOuQeZJLyuxn +mnmd49xrTirtxkLB83L8HQdAHvY5Phx8LbR9NJYvkH1MIEbBrrfUUx-x_llROOAYdPxvtpYcMkSt +ApZwRgyvaBiwUirWbnlpmf8QV1MYMlZeBbbqPZIC4eaqcxOSmZa8ox4aR3XQg9zjCxm_jXdE \ No newline at end of file diff --git a/datarouter-docker-compose/src/main/resources/node_data/node.properties b/datarouter-docker-compose/src/main/resources/node_data/node.properties index 98b7137a..62b0f824 100644 --- a/datarouter-docker-compose/src/main/resources/node_data/node.properties +++ b/datarouter-docker-compose/src/main/resources/node_data/node.properties @@ -3,7 +3,6 @@ # * org.onap.dmaap # * =========================================================================== # * Copyright � 2017 AT&T Intellectual Property. All rights reserved. -# * Modifications Copyright (C) 2018 Nokia. 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. @@ -22,90 +21,83 @@ # * #------------------------------------------------------------------------------- # -# Configuration parameters fixed at startup for the DataRouter node +# Configuration parameters set at startup for the DataRouter node # # URL to retrieve dynamic configuration -# -#ProvisioningURL: ${DRTR_PROV_INTURL} -ProvisioningURL=https://dmaap-dr-prov:8443/internal/prov - +ProvisioningURL = https://dmaap-dr-prov:8443/internal/prov # # URL to upload PUB/DEL/EXP logs -# -#LogUploadURL: ${DRTR_LOG_URL} -LogUploadURL=https://dmaap-dr-prov:8443/internal/logs - +LogUploadURL = https://dmaap-dr-prov:8443/internal/logs # # The port number for http as seen within the server -# -#IntHttpPort: ${DRTR_NODE_INTHTTPPORT:-8080} -IntHttpPort=8080 +IntHttpPort = 8080 # # The port number for https as seen within the server -# -IntHttpsPort=8443 +IntHttpsPort = 8443 # # The external port number for https taking port mapping into account +ExtHttpsPort = 443 # -ExtHttpsPort=443 -# -# The minimum interval between fetches of the dynamic configuration -# from the provisioning server -# -MinProvFetchInterval=10000 +# The minimum interval between fetches of the dynamic configuration from the provisioning server +MinProvFetchInterval = 10000 # # The minimum interval between saves of the redirection data file -# -MinRedirSaveInterval=10000 +MinRedirSaveInterval = 10000 # # The path to the directory where log files are stored -# -LogDir=/opt/app/datartr/logs +LogDir = /opt/app/datartr/logs # # The retention interval (in days) for log files -# -LogRetention=30 +LogRetention = 30 # # The path to the directories where data and meta data files are stored -# -SpoolDir=/opt/app/datartr/spool +SpoolDir = /opt/app/datartr/spool # # The path to the redirection data file -# -#RedirectionFile: etc/redirections.dat +RedirectionFile = etc/redirections.dat # # The type of keystore for https -KeyStoreType: jks +KeyStoreType = jks # # The path to the keystore for https -# -KeyStoreFile:/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks +KeyStoreFile = /opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks # # The password for the https keystore -# KeyStorePassword=]3V)($O&.Mv]W{f8^]6SxGNL # # The password for the private key in the https keystore -# KeyPassword=]3V)($O&.Mv]W{f8^]6SxGNL # # The type of truststore for https -# -TrustStoreType=jks +TrustStoreType = jks # # The path to the truststore for https -# -TrustStoreFile=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks +TrustStoreFile = /opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks # # The password for the https truststore -# TrustStorePassword=(Rd,&{]%ePdp}4JZjqoJ2G+g # # The path to the file used to trigger an orderly shutdown -# -QuiesceFile=etc/SHUTDOWN +QuiesceFile = etc/SHUTDOWN # # The key used to generate passwords for node to node transfers +NodeAuthKey = Node123! +# +# DR_NODE DEFAULT ENABLED TLS PROTOCOLS +NodeHttpsProtocols = TLSv1.1|TLSv1.2 +# +# AAF type to generate permission string +AAFType = org.onap.dmaap-dr.feed +# +# AAF default instance to generate permission string - default should be legacy +AAFInstance = legacy +# +# AAF action to generate permission string - default should be publish +AAFAction = publish +# +# AAF URL to connect to AAF server +AafUrl = https://aaf-onap-test.osaaf.org:8095 # -NodeAuthKey=Node123! +# AAF CADI enabled flag +CadiEnabled = false diff --git a/datarouter-docker-compose/src/main/resources/prov_data/aaf_certs/org.onap.dmaap-dr.keyfile b/datarouter-docker-compose/src/main/resources/prov_data/aaf_certs/org.onap.dmaap-dr.keyfile new file mode 100755 index 00000000..a586a72e --- /dev/null +++ b/datarouter-docker-compose/src/main/resources/prov_data/aaf_certs/org.onap.dmaap-dr.keyfile @@ -0,0 +1,27 @@ +VDu7g5rP2-JMemc6RwP0HqM4ILJnuja8R_bzdCG1u0_Z2EQJN_7ZNPDb28V6JCDF-59sX10_i9vT +-nw77ViAuwJO7ffSut8ipVhESeQxTokZsErzMFpeJZDhMM16W5LLtxwUs_tgh_EQIJSc-WcFUNYS +NagugzjmNE5-hUosLgnt7mZ1nX4zFER9Nq1ce0EQS--kAB9rxcRmoywPlBlHvPmP_caiwpa1SzJp +gbFF6smyLEWhjDhJkgvM_4FwaQCbJBVGcy2a3Lc9orHsz9S1RJTZ9CExhasM0qEp3kk0fMEFE9k6 +TomOpUBGizLfHPpg18KtXyM8zErj8qdS0KMwaCKtwGzCWw08MF5rVZrMYWLKDMOs8U2ESU7x28nV +KSrAsR11QD7vX4PTVTfjEpcHSGe-9nPD7TckY8_O-9l67v_OUW1Fw4MSESCN0RtT7ZlNYwDV0syA +X94rv1Y45N41tfX76jz8PDB9G-PF36BtkICJWK24zwuQDgpkURhCLPYzvBhPmCPyQil810X9s_bX +icmV2cSN3oYQRz5dNSjUYH1CDt9edAJt4p2PQhM3A2xXyw1FVvbAIYA7iF-3qYG9csroBzsCcS5C +hX8929jZHQWU5pygtpedEWhX__tnSrd-xIpxPnhOxrb-lNLva5JGKauU2DrGoLd_7RTwbuRdCiQo +uGFtYOtjLciPz81oEEpXQTReeSnvGyGiZNxRrKWMEmq-biyQd4DuRVmTDuLAG4rd92QWS6qUz0uf +9TtJiYlN3mNkxz3ahEGWLKR79rH9juJ3xqpcF-Rb7Y1bmiCDBv3DVVFiYIpwQuto1iSIYabL34Ql +QqX65E1c3uvPksN6Nl1nvAVxSKM94wAFsMiA9Rp8AN9pDSxtj7D3kZCG8I0YaIxF_s-OeJtr1RPx +ifv8vrwN23GUQCmpGBbyNXNe6zz-hz_HJdAsBr6WjLny9LQkeYszHGF-OL5ps6K5gHBRV0Ui1C7H +Gj7egsjnV_Lu5MpBxhTrquDrZKK3t38kf0zrV-zfSGzJlGbLS91h8bR-7FAZiNEzgXPWYi26w81i +W3Csx4oqsfKswp0pO80rggkFf9LL9pjCkSUTTVyF-toa9kY2h7JsVtqntP4Mjagp4Tnj01988kne +Mj8SLm2mJySTLdH5Hi4arKW943iCqYjEaZ7wXFNJSZ6vvBm3KC1XX6C0DjRrgQoKIHw_4JcGhvOU +P5LdpBT1AOcE8lIKrGGq8hyfJKLVUMec-NkzAT2aIl0YJoUcJv4fs-lKccGL4FDrq5y_yvD3xQ6v +xt7KTanFxntqLYmM72Y2eFwJGlDEHhm0SejAV64-odksA_zMLLuYwkq_KSj0If9AVpRXz7KzIj9P +9y-WMfAWKFfIyqGWXt5sYdMTQPG4qKCcFQBx3T0E6kiQMBuOZz0dR032eFPMexrymEowjosr2jt3 +ib8rFxmPMyyUWoV1iBafFMLf5PN2oapTq76gqeQQGGwpmYJB8cWlS1Eq_ZbzZpK2PSwX-fC6NSf3 +KtOV_r2VI3e_V6csnWTY8nxCJj9FlQCvLOzp964DNsBeUwDpsD7T_pgQy0THgAnq32ZtDvQfgeUE +TUJC7oQeOEY7QBWjbZkumds51j7oTlsp2dPForlHwBk_2Nd5VCwVRNa1QMS8WcghLYbUCX5zeplc +u2bopHn9GD614gt7f7wysDgTGegOCAuMoL7wA9TXN4BSfAF9mwpdtRFE4lT3N1xmfhKt9rM6Lu8T +RGvBOmTOTT5IwJrrE5mpvmESw05sHUcCZ9ENv-VhoeC3Ffk9uXqrDggQgaDs9XcXqzEPBp9wDPTt +UJpbtBGECSSTuXAZyUh3I0WFz96kVuHmQpDYVTpy1sxPjmgjgKyhu_6jLGSsYpVBH063n7KSKVdF +ROKojZN4-FsBlPhoOhNEd7x1OBfgCG79HKGk33jhESObZkPIrcTc17jiE-ud2D1B1_Fl-OJNR7Vh +GIk4WMZrH9NeVwDuIgBxF74plqg6tSl0Cdd4m7e3Drsq-wRfsU2gNTo5oL-2SgbsO5n3ubQf \ No newline at end of file diff --git a/datarouter-docker-compose/src/main/resources/prov_data/addSubscriber.txt b/datarouter-docker-compose/src/main/resources/prov_data/addSubscriber.txt index 45e12732..ccb55f6b 100644 --- a/datarouter-docker-compose/src/main/resources/prov_data/addSubscriber.txt +++ b/datarouter-docker-compose/src/main/resources/prov_data/addSubscriber.txt @@ -21,16 +21,15 @@ # * #------------------------------------------------------------------------------- { - "delivery" : - - { - "url" : "http://172.100.0.3:7070/", - "user" : "datarouter", - "password" : "datarouter", - "use100" : true - }, - "metadataOnly" : false, - "suspend" : false, - "groupid" : 29, - "subscriber" : "sg481n" +"delivery" : + { + "url" : "http://172.100.0.3:7070/", + "user" : "datarouter", + "password" : "datarouter", + "use100" : true + }, +"metadataOnly" : false, +"suspend" : false, +"groupid" : 29, +"subscriber" : "sg481n" } diff --git a/datarouter-docker-compose/src/main/resources/prov_data/provserver.properties b/datarouter-docker-compose/src/main/resources/prov_data/provserver.properties index 7e38f287..21b9bc49 100755 --- a/datarouter-docker-compose/src/main/resources/prov_data/provserver.properties +++ b/datarouter-docker-compose/src/main/resources/prov_data/provserver.properties @@ -43,8 +43,27 @@ org.onap.dmaap.datarouter.provserver.logretention = 30 # relaxation to accommodate OOM kubernetes deploy org.onap.dmaap.datarouter.provserver.isaddressauthenabled = false +#Localhost address config +org.onap.dmaap.datarouter.provserver.localhost = 127.0.0.1 + # Database access org.onap.dmaap.datarouter.db.driver = org.mariadb.jdbc.Driver org.onap.dmaap.datarouter.db.url = jdbc:mariadb://datarouter-mariadb:3306/datarouter org.onap.dmaap.datarouter.db.login = datarouter org.onap.dmaap.datarouter.db.password = datarouter + +# PROV - DEFAULT ENABLED TLS PROTOCOLS +org.onap.dmaap.datarouter.provserver.https.include.protocols = TLSv1.1|TLSv1.2 + +# AAF config +org.onap.dmaap.datarouter.provserver.cadi.enabled = false + +org.onap.dmaap.datarouter.provserver.passwordencryption = PasswordEncryptionKey#@$%^&1234# +org.onap.dmaap.datarouter.provserver.aaf.feed.type = org.onap.dmaap-dr.feed +org.onap.dmaap.datarouter.provserver.aaf.sub.type = org.onap.dmaap-dr.sub +org.onap.dmaap.datarouter.provserver.aaf.instance = legacy +org.onap.dmaap.datarouter.provserver.aaf.action.publish = publish +org.onap.dmaap.datarouter.provserver.aaf.action.subscribe = subscribe + +# AAF URL to connect to AAF server +org.onap.dmaap.datarouter.provserver.cadi.aaf.url = https://aaf-onap-test.osaaf.org:8095 \ No newline at end of file diff --git a/datarouter-node/aaf_certs/org.onap.dmaap-dr.keyfile b/datarouter-node/aaf_certs/org.onap.dmaap-dr.keyfile new file mode 100755 index 00000000..85bfa61f --- /dev/null +++ b/datarouter-node/aaf_certs/org.onap.dmaap-dr.keyfile @@ -0,0 +1,27 @@ +j4IkjDmzOE_ZdHuN_cePYmySXrhmqM4WuGp86_RTiBlJ1TTvUaP_SOSZOqH0fxjk32gRvxJ01_iO +mLtbQ-wZKk-fwCK_o6xrXJcN0G_Y8VGK2OMeqypm98ji25CSMvTdFLaohdPJwiRNMdmwwyF5q1Od +pKviCISBlQ49ytwy3Mv0x7aV3kjkDWSgpx9TiMbWoAKlddcdQMUTEMh0CT0nLGv9uhwmRQ4I8UuE +IzvR1Rit9HayMlXFND6n0IWggYqtAeRV-8wDrI2rAXGOrfLF0RC5-c0Wd0N000BWXvsT_nCYBCM6 +ffA5eAKCJmOVjJFzQTRXJq7Zhwij0CtEPgqqaipKUQhHaft9xeKXW3SPhREIn75F2u2uCcU1sNmd +ytAk7yBPwdEcCQD-KVE9ZB3_57H0WIEr45SpU5ZePJkt2YV85H2Tlc_hGK18gTAcvGqDO3qELmV5 +SBHX5X_ZNL93mOkt37R0SGRdMZVIPJXNTgl4fGAsapvU7Y7sGMYrf2Ea0D-3hctk-aOKuuPEI1Ug +0lqKjghJdvHYRFbm4C_7H-ai7UcBuixBd54Mp-hyBX-gjnFZuMHazFX2toKNe9RgDXIavHzTfF-l +8fjdQpTplc2ECLINf-X6gs7w0zPYv04kLKixwlFff4ZocoxelGDEBlYYGNNxQBZvQtUX_dZetXF1 +VPNnwTB7Sp0fqaXR2aVaZNFSZYeL7VdxkiT0becNRa9QE9s2gU7oO_KTE8JyAiJyO-ojAvSUi-p_ +rq2Ivmab_L4t6GwMpv-EmRcntUQ_PM4s_XvJL2RmmSPWoNvbgCS0IilpYi2CPnEEgxqX37-Unx8m +tYoNkiN-j9rA3Hr4EjEhrbOLf2wAh6RUeULerBpLKnf0Ans6UhjT7XVDaNvzxtAE-GrUCKHQ0ml2 +P_vzDBlGKobaRo-WQzQA-mZKGo1W4Q-qwFdusUflgfJ7iTrvw62jn30f4xGZcaP5Oa-9JvdZJggW +1UvAM-85LdjGTxuI9KXbqRLWZk46B-UF7mDOce6dbRXjY48bZWIHEXcpzPQg6QA02cO10TN5K89V +qXeCnz03ePf0u6YhMAOt5xiUvJpd1y_WI0jh4SH2dT26SegcuRTVLnEG0aL6ClypObwj3FLB1Pek +UESqziiG4mQf_rzBAdPqcjbP8oeM2-mz09VYNyUOQ-7gk6bMAMWVqBx0uDxgIwUzr2UMbahB2Kg6 +9V7yE7obAKZa8x5oMiDGnvgjL9QeHwhUsNbwhhgqTDnB10vj4gh8RkNK8OsxQ53Nofj2PQZfY0GJ +a6It7DCmnAgQ9N51RvCeodmmK9Zh3n_zoxt8gA-eV8zbidXZYQwYWx6ai7ooP7yol2bE_TLDDY9l +_oYO_db73wSmqgTvoAdmrQGO4NI_g2iYN-Gd4XK4V_xgYPKyY5tHNSd4OKr_UuYiSioyNxE4IK1t +zWyJ3tUXAyeq_ZjUDjabsnGnxmgujShRfK-rBh_1AapY3Oh99-aehETtcXihUmFX4lohowniWTA3 +MF1MMlRM5N1phF7xFgkAaZJfkQ-inqgWYvQ9XuW0LfumN4QeO8KnfknukSSgZ86PYTrgJKDIOKWn +UYsxSoE_U02WxQThW8ayrFtKRLGR2x9bMaKzaON0tfltwyQO7ttsKlSyORIWVrGO48CyEDxpDs8U +RDvN_SgFq1gWarCKLL0HDUdLGMfimZP7sPfVEKkprMlDp_gpx7kD7SaB1m7xuNjhBd-6I3gqSR7g +lizTgKmuGalPRGorxX72vlTEYqLtgNWok6e9qjMGhEYCf02li6Ksoxp4ZejN_9S1-FGlcuq3SE9f +Pm0HckGtPJ8u3u2mmLpT1QzzS0RG3XJU5kNJvZcSEG0GOsU7OnWTXoZnleFJvEoQrOuQeZJLyuxn +mnmd49xrTirtxkLB83L8HQdAHvY5Phx8LbR9NJYvkH1MIEbBrrfUUx-x_llROOAYdPxvtpYcMkSt +ApZwRgyvaBiwUirWbnlpmf8QV1MYMlZeBbbqPZIC4eaqcxOSmZa8ox4aR3XQg9zjCxm_jXdE \ No newline at end of file diff --git a/datarouter-node/pom.xml b/datarouter-node/pom.xml index 3e75e88c..9c82ff3a 100755 --- a/datarouter-node/pom.xml +++ b/datarouter-node/pom.xml @@ -219,6 +219,11 @@ commons-lang3 3.0 + + org.onap.aaf.authz + aaf-cadi-aaf + ${aaf-cadi-aaf.version} + diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilter.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilter.java new file mode 100644 index 00000000..b0122596 --- /dev/null +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilter.java @@ -0,0 +1,99 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.node; + +import org.apache.log4j.Logger; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +public class DRNodeCadiFilter extends CadiFilter { + private static Logger logger = Logger.getLogger("org.onap.dmaap.datarouter.node.NodeServlet"); + + DRNodeCadiFilter(boolean init, PropAccess access) throws ServletException { + super(init, access); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + String path = httpRequest.getPathInfo(); + if (!(path.startsWith("/internal"))) { + if (!(httpRequest.getMethod().equalsIgnoreCase("POST"))) { + if (httpRequest.getMethod().equalsIgnoreCase("DELETE") && path.startsWith("/delete")) { + chain.doFilter(request, response); + } else { + String feedId = getFeedId(request, response); + String aafDbInstance = NodeConfigManager.getInstance().getAafInstance(feedId); + if (aafDbInstance != null && !aafDbInstance.equals("") && !aafDbInstance.equalsIgnoreCase("legacy")) { + logger.info("DRNodeCadiFilter - doFilter: FeedId - " + feedId + ":" + "AAF Instance -" + aafDbInstance); + super.doFilter(request, response, chain); + } else { + logger.info("DRNodeCadiFilter - doFilter: FeedId - " + feedId + ":" + "Legacy Feed"); + chain.doFilter(request, response); + } + } + } + } else { + chain.doFilter(request, response); + } + } + + private String getFeedId(ServletRequest request, ServletResponse response) { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + String fileid = req.getPathInfo(); + if (fileid == null) { + logger.info("NODE0105 Rejecting bad URI for PUT " + req.getPathInfo() + " from " + req.getRemoteAddr()); + try { + resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Invalid request URI. Expecting /."); + } catch (IOException e) { + logger.error("NODE0541 DRNodeCadiFilter.getFeedId: ", e); + } + return null; + } + String feedid = ""; + + if (fileid.startsWith("/publish/")) { + fileid = fileid.substring(9); + int i = fileid.indexOf('/'); + if (i == -1 || i == fileid.length() - 1) { + logger.info("NODE0105 Rejecting bad URI for PUT (publish) of " + req.getPathInfo() + " from " + req.getRemoteAddr()); + try { + resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Invalid request URI. Expecting /. Possible missing fileid."); + } catch (IOException e) { + logger.error("NODE0542 DRNodeCadiFilter.getFeedId: ", e); + } + return null; + } + feedid = fileid.substring(0, i); + } + return feedid; + } + +} diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DeliveryTask.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DeliveryTask.java index a3af88fc..b64396bc 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DeliveryTask.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DeliveryTask.java @@ -64,6 +64,7 @@ public class DeliveryTask implements Runnable, Comparable { private String feedid; private String subid; private int attempts; + private boolean followRedirects; private String[][] hdrs; private String newInvocationId; @@ -81,6 +82,7 @@ public class DeliveryTask implements Runnable, Comparable { this.pubid = pubid; destInfo = deliveryTaskHelper.getDestinationInfo(); subid = destInfo.getSubId(); + this.followRedirects = destInfo.isFollowRedirects(); feedid = destInfo.getLogData(); spool = destInfo.getSpool(); String dfn = spool + "/" + pubid; @@ -125,7 +127,7 @@ public class DeliveryTask implements Runnable, Comparable { hdrv.add(new String[]{h, v}); } } catch (Exception e) { - loggerDeliveryTask.error("Exception "+e.getStackTrace(),e); + loggerDeliveryTask.error("Exception "+ Arrays.toString(e.getStackTrace()), e); } hdrs = hdrv.toArray(new String[hdrv.size()][]); url = deliveryTaskHelper.getDestURL(fileid); @@ -245,7 +247,7 @@ public class DeliveryTask implements Runnable, Comparable { } deliveryTaskHelper.reportStatus(this, rc, xpubid, rmsg); } catch (Exception e) { - loggerDeliveryTask.error("Exception " + e.getStackTrace(), e); + loggerDeliveryTask.error("Exception " + Arrays.toString(e.getStackTrace()), e); deliveryTaskHelper.reportException(this, e); } } @@ -324,7 +326,7 @@ public class DeliveryTask implements Runnable, Comparable { } catch (ProtocolException pe) { deliveryTaskHelper.reportDeliveryExtra(this, -1L); // Rcvd error instead of 100-continue - loggerDeliveryTask.error("Exception " + pe.getStackTrace(), pe); + loggerDeliveryTask.error("Exception " + Arrays.toString(pe.getStackTrace()), pe); } return outputStream; } @@ -409,4 +411,11 @@ public class DeliveryTask implements Runnable, Comparable { public String getFeedId() { return (feedid); } + + /** + * Get the followRedirects for this delivery task + */ + public boolean getFollowRedirects() { + return(followRedirects); + } } diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DestInfo.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DestInfo.java index 73753527..8aa339f5 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DestInfo.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/DestInfo.java @@ -39,7 +39,8 @@ public class DestInfo { private boolean use100; private boolean privilegedSubscriber; private boolean decompress; - + private boolean followRedirects; + private String aafInstance; /** * Create a destination information object. * @@ -53,9 +54,10 @@ public class DestInfo { * @param metaonly Is this a metadata only delivery? * @param use100 Should I use expect 100-continue? * @param privilegedSubscriber Can we wait to receive a file processed acknowledgement before deleting file + * @param followRedirects Is follow redirect of destination enabled? * @param decompress To see if the they want there information compressed or decompressed */ - public DestInfo(String name, String spool, String subid, String logdata, String url, String authuser, String authentication, boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean decompress) { + public DestInfo(String name, String spool, String subid, String logdata, String url, String authuser, String authentication, boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirects, boolean decompress) { this.name = name; this.spool = spool; this.subid = subid; @@ -66,6 +68,7 @@ public class DestInfo { this.metaonly = metaonly; this.use100 = use100; this.privilegedSubscriber = privilegedSubscriber; + this.followRedirects = followRedirects; this.decompress = decompress; } @@ -87,6 +90,7 @@ public class DestInfo { this.metaonly = subscription.isMetaDataOnly(); this.use100 = subscription.isUsing100(); this.privilegedSubscriber = subscription.isPrivilegedSubscriber(); + this.followRedirects = subscription.getFollowRedirect(); this.decompress = subscription.isDecompress(); } @@ -185,6 +189,15 @@ public class DestInfo { return (privilegedSubscriber); } + /** + * Should I follow redirects? + * + * @return True if I should. + */ + public boolean isFollowRedirects() { + return (followRedirects); + } + /** * Should i decompress the file before sending it on * diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/IsFrom.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/IsFrom.java index 35ba0951..b8db0309 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/IsFrom.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/IsFrom.java @@ -26,6 +26,7 @@ package org.onap.dmaap.datarouter.node; import org.apache.log4j.Logger; +import java.io.IOException; import java.util.*; import java.net.*; @@ -62,24 +63,37 @@ public class IsFrom { long now = System.currentTimeMillis(); if (now > nextcheck) { nextcheck = now + 10000; - Vector v = new Vector<>(); + ArrayList hostAddrArray = new ArrayList<>(); try { InetAddress[] addrs = InetAddress.getAllByName(fqdn); - for (InetAddress a : addrs) { - v.add(a.getHostAddress()); + for (InetAddress addr : addrs) { + hostAddrArray.add(addr.getHostAddress()); } } catch (UnknownHostException e) { logger.debug("IsFrom: UnknownHostEx: " + e.toString(), e); } - ips = v.toArray(new String[v.size()]); + ips = hostAddrArray.toArray(new String[0]); logger.info("IsFrom: DNS ENTRIES FOR FQDN " + fqdn + " : " + Arrays.toString(ips)); } - for (String s : ips) { - if (s.equals(ip) || s.equals(System.getenv("DMAAP_DR_PROV_SERVICE_HOST"))) { - return (true); + for (String ipAddr : ips) { + if (ipAddr.equals(ip)) { + return true; } } - return (false); + return false; + } + + synchronized boolean isReachable(String ip) { + try { + if (InetAddress.getByName(ip).isReachable(1000)) { + return true; + } + } catch (UnknownHostException e) { + logger.debug("IsFrom: UnknownHostEx: " + e.toString(), e); + } catch (IOException e) { + logger.debug("IsFrom: Failed to parse IP : " + ip + " : " + e.toString(), e); + } + return false; } /** diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/LogManager.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/LogManager.java index 032c6ced..3fa5dc29 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/LogManager.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/LogManager.java @@ -104,8 +104,7 @@ public class LogManager extends TimerTask { public Uploader() { dq = new DeliveryQueue(this, - new DestInfo("LogUpload", uploaddir, null, null, null, config.getMyName(), config.getMyAuth(), false, - false, false, false)); + new DestInfo("LogUpload", uploaddir, null, null, null, config.getMyName(), config.getMyAuth(), false, false, false, false, false)); setDaemon(true); setName("Log Uploader"); start(); diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfig.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfig.java index 5577e52e..791eee12 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfig.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfig.java @@ -25,9 +25,11 @@ package org.onap.dmaap.datarouter.node; import java.io.File; +import java.util.Arrays; import java.util.HashSet; import java.util.Hashtable; import java.util.Vector; +import org.apache.log4j.Logger; /** * Processed configuration for this node. @@ -37,7 +39,7 @@ import java.util.Vector; * discarded. */ public class NodeConfig { - + private static Logger logger = Logger.getLogger("org.onap.dmaap.datarouter.node.NodeConfig"); /** * Raw configuration entry for a data router node */ @@ -104,6 +106,12 @@ public class NodeConfig { private String id; private String logdata; private String status; + private String createdDate; + /* + * AAF changes: TDP EPIC US# 307413 + * Passing aafInstance from to identify legacy/AAF feeds + */ + private String aafInstance; /** * Construct a feed configuration entry. @@ -113,10 +121,27 @@ public class NodeConfig { * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or * null if it is valid. */ - public ProvFeed(String id, String logdata, String status) { + public ProvFeed(String id, String logdata, String status, String createdDate, String aafInstance) { this.id = id; this.logdata = logdata; this.status = status; + this.createdDate = createdDate; + this.aafInstance = aafInstance; + } + + /** + * Get the created date of the data feed. + */ + public String getCreatedDate() + { + return(createdDate); + } + + /** + * Get the aafInstance of the data feed. + */ + public String getAafInstance() { + return aafInstance; } /** @@ -232,6 +257,7 @@ public class NodeConfig { private boolean metaonly; private boolean use100; private boolean privilegedSubscriber; + private boolean followRedirect; private boolean decompress; /** @@ -246,10 +272,10 @@ public class NodeConfig { * @param metaonly Is this a meta data only subscription? * @param use100 Should we send Expect: 100-continue? * @param privilegedSubscriber Can we wait to receive a delete file call before deleting file + * @param followRedirect Is follow redirect of destination enabled? * @param decompress To see if they want their information compressed or decompressed */ - public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, - boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean decompress) { + public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirect, boolean decompress) { this.subid = subid; this.feedid = feedid; this.url = url; @@ -258,6 +284,7 @@ public class NodeConfig { this.metaonly = metaonly; this.use100 = use100; this.privilegedSubscriber = privilegedSubscriber; + this.followRedirect = followRedirect; this.decompress = decompress; } @@ -319,10 +346,18 @@ public class NodeConfig { /** * Should i decompress the file before sending it on - */ + */ public boolean isDecompress() { return (decompress); } + + /** + * New field is added - FOLLOW_REDIRECTS feature iTrack:DATARTR-17 - 1706 + * Get the followRedirect of this destination + */ + boolean getFollowRedirect() { + return(followRedirect); + } } /** @@ -348,7 +383,12 @@ public class NodeConfig { this.feedid = feedid; this.subnet = subnet; this.user = user; - this.nodes = nodes; + //Sonar fix + if(nodes == null) { + this.nodes = new String[0]; + } else { + this.nodes = Arrays.copyOf(nodes, nodes.length); + } } /** @@ -480,6 +520,8 @@ public class NodeConfig { Hashtable authusers = new Hashtable(); Redirection[] redirections; Target[] targets; + String createdDate; + String aafInstance; } private Hashtable params = new Hashtable<>(); @@ -510,24 +552,24 @@ public class NodeConfig { Vector destInfos = new Vector<>(); myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey); for (ProvNode pn : pd.getNodes()) { - String cn = pn.getCName(); - if (nodeinfo.get(cn) != null) { + String cName = pn.getCName(); + if (nodeinfo.get(cName) != null) { continue; } - String auth = NodeUtils.getNodeAuthHdr(cn, nodeauthkey); - DestInfo di = new DestInfo("n:" + cn, spooldir + "/n/" + cn, null, "n2n-" + cn, - "https://" + cn + ":" + port + "/internal/publish", cn, myauth, false, true, false, false); + String auth = NodeUtils.getNodeAuthHdr(cName, nodeauthkey); + DestInfo di = new DestInfo("n:" + cName, spooldir + "/n/" + cName, null, "n2n-" + cName, + "https://" + cName + ":" + port + "/internal/publish", cName, myauth, false, true, false, false, false); (new File(di.getSpool())).mkdirs(); destInfos.add(di); - nodeinfo.put(cn, di); - nodes.put(auth, new IsFrom(cn)); + nodeinfo.put(cName, di); + nodes.put(auth, new IsFrom(cName)); } - PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[nodeinfo.size()]), pd.getHops()); - Hashtable> rdtab = new Hashtable>(); + PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops()); + Hashtable> rdtab = new Hashtable<>(); for (ProvForceIngress pfi : pd.getForceIngress()) { Vector v = rdtab.get(pfi.getFeedId()); if (v == null) { - v = new Vector(); + v = new Vector<>(); rdtab.put(pfi.getFeedId(), v); } Redirection r = new Redirection(); @@ -538,16 +580,16 @@ public class NodeConfig { r.nodes = pfi.getNodes(); v.add(r); } - Hashtable> pfutab = new Hashtable>(); + Hashtable> pfutab = new Hashtable<>(); for (ProvFeedUser pfu : pd.getFeedUsers()) { Hashtable t = pfutab.get(pfu.getFeedId()); if (t == null) { - t = new Hashtable(); + t = new Hashtable<>(); pfutab.put(pfu.getFeedId(), t); } t.put(pfu.getCredentials(), pfu.getUser()); } - Hashtable egrtab = new Hashtable(); + Hashtable egrtab = new Hashtable<>(); for (ProvForceEgress pfe : pd.getForceEgress()) { if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) { continue; @@ -558,7 +600,7 @@ public class NodeConfig { for (ProvFeedSubnet pfs : pd.getFeedSubnets()) { Vector v = pfstab.get(pfs.getFeedId()); if (v == null) { - v = new Vector(); + v = new Vector<>(); pfstab.put(pfs.getFeedId(), v); } v.add(new SubnetMatcher(pfs.getCidr())); @@ -584,6 +626,7 @@ public class NodeConfig { sididx = Integer.parseInt(subId); sididx -= sididx % 100; } catch (Exception e) { + logger.error("NODE0517 Exception NodeConfig: "+e); } String subscriptionDirectory = sididx + "/" + subId; DestInfo destinationInfo = new DestInfo("s:" + subId, @@ -603,7 +646,7 @@ public class NodeConfig { } sb.append(' ').append(subId); } - alldests = destInfos.toArray(new DestInfo[destInfos.size()]); + alldests = destInfos.toArray(new DestInfo[0]); for (ProvFeed pfx : pd.getFeeds()) { String fid = pfx.getId(); Feed f = feeds.get(fid); @@ -612,13 +655,19 @@ public class NodeConfig { } f = new Feed(); feeds.put(fid, f); + f.createdDate = pfx.getCreatedDate(); f.loginfo = pfx.getLogData(); f.status = pfx.getStatus(); + /* + * AAF changes: TDP EPIC US# 307413 + * Passing aafInstance from ProvFeed to identify legacy/AAF feeds + */ + f.aafInstance = pfx.getAafInstance(); Vector v1 = pfstab.get(fid); if (v1 == null) { f.subnets = new SubnetMatcher[0]; } else { - f.subnets = v1.toArray(new SubnetMatcher[v1.size()]); + f.subnets = v1.toArray(new SubnetMatcher[0]); } Hashtable h1 = pfutab.get(fid); if (h1 == null) { @@ -629,7 +678,7 @@ public class NodeConfig { if (v2 == null) { f.redirections = new Redirection[0]; } else { - f.redirections = v2.toArray(new Redirection[v2.size()]); + f.redirections = v2.toArray(new Redirection[0]); } StringBuffer sb = feedTargets.get(fid); if (sb == null) { @@ -687,7 +736,7 @@ public class NodeConfig { } } } - return (tv.toArray(new Target[tv.size()])); + return (tv.toArray(new Target[0])); } /** @@ -743,6 +792,32 @@ public class NodeConfig { return provSubscription.isPrivilegedSubscriber(); } + /** + * Check whether publication is allowed for AAF Feed. + * @param feedid The ID of the feed being requested. + * @param ip The requesting IP address + */ + public String isPublishPermitted(String feedid, String ip) { + Feed f = feeds.get(feedid); + String nf = "Feed does not exist"; + if (f != null) { + nf = f.status; + } + if (nf != null) { + return(nf); + } + if (f.subnets.length == 0) { + return(null); + } + byte[] addr = NodeUtils.getInetAddress(ip); + for (SubnetMatcher snm: f.subnets) { + if (snm.matches(addr)) { + return(null); + } + } + return("Publisher not permitted for this feed"); + } + /** * Get authenticated user */ @@ -750,6 +825,16 @@ public class NodeConfig { return (feeds.get(feedid).authusers.get(credentials)); } + /** + * AAF changes: TDP EPIC US# 307413 + * Check AAF_instance for feed ID + * @param feedid The ID of the feed specified + */ + public String getAafInstance(String feedid) { + Feed f = feeds.get(feedid); + return f.aafInstance; + } + /** * Check if the request should be redirected to a different ingress node */ @@ -810,6 +895,16 @@ public class NodeConfig { return (f.targets); } + /** + * Get the creation date for a feed + * @param feedid The feed ID + * @return the timestamp of creation date of feed id passed + */ + public String getCreatedDate(String feedid) { + Feed f = feeds.get(feedid); + return(f.createdDate); + } + /** * Get the feed ID for a subscription * diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java index d98c47ae..8011c632 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeConfigManager.java @@ -26,6 +26,10 @@ package org.onap.dmaap.datarouter.node; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; +import org.apache.log4j.Logger; +import org.onap.aaf.cadi.PropAccess; +import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; + import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; @@ -33,8 +37,6 @@ import java.io.Reader; import java.net.URL; import java.util.Properties; import java.util.Timer; -import org.apache.log4j.Logger; -import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; /** @@ -95,32 +97,54 @@ public class NodeConfigManager implements DeliveryQueueHelper { private String eventlogsuffix; private String eventloginterval; private boolean followredirects; + private String [] enabledprotocols; + private String aafType; + private String aafInstance; + private String aafAction; + private String aafURL; + private boolean cadiEnabled; /** * Get the default node configuration manager */ public static NodeConfigManager getInstance() { - return (base); + return base; } /** * Initialize the configuration of a Data Router node */ private NodeConfigManager() { - Properties p = new Properties(); + + Properties drNodeProperties = new Properties(); try { - p.load(new FileInputStream(System + logger.info("NODE0301 Loading local config file node.properties"); + drNodeProperties.load(new FileInputStream(System .getProperty("org.onap.dmaap.datarouter.node.properties", "/opt/app/datartr/etc/node.properties"))); } catch (Exception e) { - NodeUtils.setIpAndFqdnForEelf("NodeConfigManager"); eelflogger.error(EelfMsgs.MESSAGE_PROPERTIES_LOAD_ERROR); logger.error("NODE0301 Unable to load local configuration file " + System - .getProperty("org.onap.dmaap.datarouter.node.properties", "/opt/app/datartr/etc/node.properties"), - e); + .getProperty("org.onap.dmaap.datarouter.node.properties", "/opt/app/datartr/etc/node.properties"), e); } - provurl = p.getProperty("ProvisioningURL", "https://feeds-drtr.web.att.com/internal/prov"); + provurl = drNodeProperties.getProperty("ProvisioningURL", "https://dmaap-dr-prov:8443/internal/prov"); + /* + * START - AAF changes: TDP EPIC US# 307413 + * Pull AAF settings from node.properties + */ + aafType = drNodeProperties.getProperty("AAFType", "org.onap.dmaap-dr.feed"); + aafInstance = drNodeProperties.getProperty("AAFInstance", "legacy"); + aafAction = drNodeProperties.getProperty("AAFAction", "publish"); + aafURL = drNodeProperties.getProperty("AafUrl", "https://aaf-onap-test.osaaf.org:8095"); + cadiEnabled = Boolean.parseBoolean(drNodeProperties.getProperty("CadiEnabled", "false")); + /* + * END - AAF changes: TDP EPIC US# 307413 + * Pull AAF settings from node.properties + */ + //Disable and enable protocols*/ + enabledprotocols = ((drNodeProperties.getProperty("NodeHttpsProtocols")).trim()).split("\\|"); + try { provhost = (new URL(provurl)).getHost(); } catch (Exception e) { @@ -130,14 +154,14 @@ public class NodeConfigManager implements DeliveryQueueHelper { System.exit(1); } logger.info("NODE0303 Provisioning server is " + provhost); - eventlogurl = p.getProperty("LogUploadURL", "https://feeds-drtr.web.att.com/internal/logs"); + eventlogurl = drNodeProperties.getProperty("LogUploadURL", "https://feeds-drtr.web.att.com/internal/logs"); provcheck = new IsFrom(provhost); - gfport = Integer.parseInt(p.getProperty("IntHttpPort", "8080")); - svcport = Integer.parseInt(p.getProperty("IntHttpsPort", "8443")); - port = Integer.parseInt(p.getProperty("ExtHttpsPort", "443")); - long minpfinterval = Long.parseLong(p.getProperty("MinProvFetchInterval", "10000")); - long minrsinterval = Long.parseLong(p.getProperty("MinRedirSaveInterval", "10000")); - spooldir = p.getProperty("SpoolDir", "spool"); + gfport = Integer.parseInt(drNodeProperties.getProperty("IntHttpPort", "8080")); + svcport = Integer.parseInt(drNodeProperties.getProperty("IntHttpsPort", "8443")); + port = Integer.parseInt(drNodeProperties.getProperty("ExtHttpsPort", "443")); + long minpfinterval = Long.parseLong(drNodeProperties.getProperty("MinProvFetchInterval", "10000")); + long minrsinterval = Long.parseLong(drNodeProperties.getProperty("MinRedirSaveInterval", "10000")); + spooldir = drNodeProperties.getProperty("SpoolDir", "spool"); File fdir = new File(spooldir + "/f"); fdir.mkdirs(); for (File junk : fdir.listFiles()) { @@ -145,26 +169,26 @@ public class NodeConfigManager implements DeliveryQueueHelper { junk.delete(); } } - logdir = p.getProperty("LogDir", "logs"); + logdir = drNodeProperties.getProperty("LogDir", "logs"); (new File(logdir)).mkdirs(); - logretention = Long.parseLong(p.getProperty("LogRetention", "30")) * 86400000L; + logretention = Long.parseLong(drNodeProperties.getProperty("LogRetention", "30")) * 86400000L; eventlogprefix = logdir + "/events"; eventlogsuffix = ".log"; - String redirfile = p.getProperty("RedirectionFile", "etc/redirections.dat"); - kstype = p.getProperty("KeyStoreType", "jks"); - ksfile = p.getProperty("KeyStoreFile", "etc/keystore"); - kspass = p.getProperty("KeyStorePassword", "changeme"); - kpass = p.getProperty("KeyPassword", "changeme"); - tstype = p.getProperty("TrustStoreType", "jks"); - tsfile = p.getProperty("TrustStoreFile"); - tspass = p.getProperty("TrustStorePassword", "changeme"); + String redirfile = drNodeProperties.getProperty("RedirectionFile", "etc/redirections.dat"); + kstype = drNodeProperties.getProperty("KeyStoreType", "jks"); + ksfile = drNodeProperties.getProperty("KeyStoreFile", "etc/keystore"); + kspass = drNodeProperties.getProperty("KeyStorePassword", "changeme"); + kpass = drNodeProperties.getProperty("KeyPassword", "changeme"); + tstype = drNodeProperties.getProperty("TrustStoreType", "jks"); + tsfile = drNodeProperties.getProperty("TrustStoreFile"); + tspass = drNodeProperties.getProperty("TrustStorePassword", "changeme"); if (tsfile != null && tsfile.length() > 0) { System.setProperty("javax.net.ssl.trustStoreType", tstype); System.setProperty("javax.net.ssl.trustStore", tsfile); System.setProperty("javax.net.ssl.trustStorePassword", tspass); } - nak = p.getProperty("NodeAuthKey", "Node123!"); - quiesce = new File(p.getProperty("QuiesceFile", "etc/SHUTDOWN")); + nak = drNodeProperties.getProperty("NodeAuthKey", "Node123!"); + quiesce = new File(drNodeProperties.getProperty("QuiesceFile", "etc/SHUTDOWN")); myname = NodeUtils.getCanonicalName(kstype, ksfile, kspass); if (myname == null) { NodeUtils.setIpAndFqdnForEelf("NodeConfigManager"); @@ -253,7 +277,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { private void fetchconfig() { try { - System.out.println("provurl:: " + provurl); + logger.info("NodeConfigMan.fetchConfig: provurl:: " + provurl); Reader r = new InputStreamReader((new URL(provurl)).openStream()); config = new NodeConfig(new ProvData(r), myname, spooldir, port, nak); localconfig(); @@ -263,6 +287,7 @@ public class NodeConfigManager implements DeliveryQueueHelper { try { rr.run(); } catch (Exception e) { + logger.error("NODE0518 Exception fetchconfig: " + e); } } } catch (Exception e) { @@ -278,12 +303,12 @@ public class NodeConfigManager implements DeliveryQueueHelper { * fetch the provisioning data, ignore the request. If the data has been fetched very recently (default 10 * seconds), wait a while before fetching again. */ - public synchronized void gofetch(String remoteaddr) { - if (provcheck.isFrom(remoteaddr)) { - logger.info("NODE0307 Received configuration fetch request from provisioning server " + remoteaddr); + public synchronized void gofetch(String remoteAddr) { + if (provcheck.isReachable(remoteAddr)) { + logger.info("NODE0307 Received configuration fetch request from provisioning server " + remoteAddr); pfetcher.request(); } else { - logger.info("NODE0308 Received configuration fetch request from unexpected server " + remoteaddr); + logger.info("NODE0308 Received configuration fetch request from unexpected server " + remoteAddr); } } @@ -344,6 +369,17 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (config.isDeletePermitted(subId)); } + /** + * Check whether publication is allowed for AAF Feed. + * + * @param feedid The ID of the feed being requested + * @param ip The requesting IP address + * @return True if the IP and credentials are valid for the specified feed. + */ + public String isPublishPermitted(String feedid, String ip) { + return(config.isPublishPermitted(feedid, ip)); + } + /** * Check who the user is given the feed ID and the offered credentials. * @@ -355,6 +391,15 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (config.getAuthUser(feedid, credentials)); } + /** + * AAF changes: TDP EPIC US# 307413 + * Check AAF_instance for feed ID in NodeConfig + * @param feedid The ID of the feed specified + */ + public String getAafInstance(String feedid) { + return(config.getAafInstance(feedid)); + } + /** * Check if the publish request should be sent to another node based on the feedid, user, and source IP address. * @@ -460,6 +505,23 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (false); } + /** + * Set up redirection on receipt of a 3XX from a target URL + */ + public boolean handleRedirectionSubLevel(DeliveryTask task, DestInfo destinfo, String redirto, String fileid) { + fileid = "/" + fileid; + String subid = destinfo.getSubId(); + String purl = destinfo.getURL(); + if (task.getFollowRedirects() && subid != null && redirto.endsWith(fileid)) { + redirto = redirto.substring(0, redirto.length() - fileid.length()); + if (!redirto.equals(purl)) { + rdmgr.redirect(subid, purl, redirto); + return true; + } + } + return false; + } + /** * Handle unreachable target URL */ @@ -529,6 +591,15 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (config.getTargets(feedid)); } + /** + * Get the creation date for a feed + * @param feedid The feed ID + * @return the timestamp of creation date of feed id passed + */ + public String getCreatedDate(String feedid) { + return(config.getCreatedDate(feedid)); + } + /** * Get the spool directory for temporary files */ @@ -697,6 +768,16 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (fdpstop); } + /** + * Disable and enable protocols + * */ + public String[] getEnabledprotocols() { + return enabledprotocols; + } + public void setEnabledprotocols(String[] enabledprotocols) { + this.enabledprotocols = enabledprotocols.clone(); + } + /** * Get the spool directory for a subscription */ @@ -716,4 +797,59 @@ public class NodeConfigManager implements DeliveryQueueHelper { return (null); } } + + public String getAafType() { + return aafType; + } + public void setAafType(String aafType) { + this.aafType = aafType; + } + public String getAafInstance() { + return aafInstance; + } + public void setAafInstance(String aafInstance) { + this.aafInstance = aafInstance; + } + public String getAafAction() { + return aafAction; + } + public void setAafAction(String aafAction) { + this.aafAction = aafAction; + } + /* + * Get aafURL from SWM variable + * */ + public String getAafURL() { + return aafURL; + } + public void setAafURL(String aafURL) { + this.aafURL = aafURL; + } + + public boolean getCadiEnabeld() { + return cadiEnabled; + } + public void setCadiEnabled(boolean cadiEnabled) { + this.cadiEnabled = cadiEnabled; + } + + /** + * Builds the permissions string to be verified + * + * @param aafInstance The aaf instance + * @return The permissions + */ + protected String getPermission(String aafInstance) { + try { + String type = getAafType(); + String action = getAafAction(); + if (aafInstance == null || aafInstance.equals("")) { + aafInstance = getAafInstance(); + } + return type + "|" + aafInstance + "|" + action; + } catch (Exception e) { + logger.error("NODE0543 NodeConfigManager.getPermission: ", e); + } + return null; + } } diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeMain.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeMain.java index d25531a7..7ff33ff9 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeMain.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeMain.java @@ -23,19 +23,20 @@ package org.onap.dmaap.datarouter.node; -import java.util.Arrays; import org.apache.log4j.Logger; import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.*; +import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.onap.aaf.cadi.PropAccess; + +import javax.servlet.DispatcherType; +import java.io.IOException; +import java.io.InputStream; +import java.util.EnumSet; +import java.util.Properties; /** * The main starting point for the Data Router node @@ -47,6 +48,18 @@ public class NodeMain { private static Logger nodeMainLogger = Logger.getLogger("org.onap.dmaap.datarouter.node.NodeMain"); + class Inner { + InputStream getCadiProps() { + InputStream in = null; + try { + in = getClass().getClassLoader().getResourceAsStream("drNodeCadi.properties"); + } catch (Exception e) { + nodeMainLogger.error("Exception in Inner.getCadiProps() method " + e.getMessage()); + } + return in; + } + } + private static class WaitForConfig implements Runnable { private NodeConfigManager localNodeConfigManager; @@ -67,8 +80,8 @@ public class NodeMain { wait(); } catch (Exception exception) { nodeMainLogger - .debug("NodeMain: waitForConfig exception. Exception Message:- " + exception.toString(), - exception); + .debug("NodeMain: waitForConfig exception. Exception Message:- " + exception.toString(), + exception); } } localNodeConfigManager.deregisterConfigTask(this); @@ -89,8 +102,8 @@ public class NodeMain { /** * Start the data router. *

- * The location of the node configuration file can be set using the org.onap.dmaap.datarouter.node.ConfigFile system - * property. By default, it is "etc/node.properties". + * The location of the node configuration file can be set using the org.onap.dmaap.datarouter.node.properties system + * property. By default, it is "/opt/app/datartr/etc/node.properties". */ public static void main(String[] args) throws Exception { nodeMainLogger.info("NODE0001 Data Router Node Starting"); @@ -100,15 +113,15 @@ public class NodeMain { (new WaitForConfig(nodeConfigManager)).waitForConfig(); delivery = new Delivery(nodeConfigManager); new LogManager(nodeConfigManager); + Server server = new Server(); + // HTTP configuration HttpConfiguration httpConfiguration = new HttpConfiguration(); httpConfiguration.setRequestHeaderSize(2048); // HTTP connector - ServletContextHandler ctxt; - try (ServerConnector httpServerConnector = new ServerConnector(server, - new HttpConnectionFactory(httpConfiguration))) { + try (ServerConnector httpServerConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration))) { httpServerConnector.setPort(nodeConfigManager.getHttpPort()); httpServerConnector.setIdleTimeout(2000); @@ -118,10 +131,23 @@ public class NodeMain { sslContextFactory.setKeyStorePath(nodeConfigManager.getKSFile()); sslContextFactory.setKeyStorePassword(nodeConfigManager.getKSPass()); sslContextFactory.setKeyManagerPassword(nodeConfigManager.getKPass()); - /* Skip SSLv3 Fixes */ + + //SP-6 : Fixes for SDV scan to exclude/remove DES/3DES ciphers are taken care by upgrading jdk in descriptor.xml + sslContextFactory.setExcludeCipherSuites( + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" + ); + sslContextFactory.addExcludeProtocols("SSLv3"); - nodeMainLogger.info("Excluded protocols node-" + Arrays.toString(sslContextFactory.getExcludeProtocols())); - /* End of SSLv3 Fixes */ + sslContextFactory.setIncludeProtocols(nodeConfigManager.getEnabledprotocols()); + nodeMainLogger.info("NODE00004 Unsupported protocols node server:-" + String.join(",", sslContextFactory.getExcludeProtocols())); + nodeMainLogger.info("NODE00004 Supported protocols node server:-" + String.join(",", sslContextFactory.getIncludeProtocols())); + nodeMainLogger.info("NODE00004 Unsupported ciphers node server:-" + String.join(",", sslContextFactory.getExcludeCipherSuites())); HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration); httpsConfiguration.setRequestHeaderSize(8192); @@ -133,21 +159,47 @@ public class NodeMain { // HTTPS connector try (ServerConnector httpsServerConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(httpsConfiguration))) { + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfiguration))) { + httpsServerConnector.setPort(nodeConfigManager.getHttpsPort()); - httpsServerConnector.setIdleTimeout(500000); + httpsServerConnector.setIdleTimeout(3600000); httpsServerConnector.setAcceptQueueSize(2); + //Context Handler + ServletContextHandler servletContextHandler = new ServletContextHandler(0); + servletContextHandler.setContextPath("/"); + servletContextHandler.addServlet(new ServletHolder(new NodeServlet(delivery)), "/*"); + + //CADI Filter activation check + if (nodeConfigManager.getCadiEnabeld()) { + Properties cadiProperties = new Properties(); + try { + Inner obj = new NodeMain().new Inner(); + InputStream in = obj.getCadiProps(); + cadiProperties.load(in); + } catch (IOException e1) { + nodeMainLogger.error("NODE00005 Exception in NodeMain.Main() loading CADI properties " + e1.getMessage()); + } + cadiProperties.setProperty("aaf_locate_url", nodeConfigManager.getAafURL()); + nodeMainLogger.info("NODE00005 aaf_url set to - " + cadiProperties.getProperty("aaf_url")); + + PropAccess access = new PropAccess(cadiProperties); + servletContextHandler.addFilter(new FilterHolder(new DRNodeCadiFilter(true, access)), "/*", EnumSet.of(DispatcherType.REQUEST)); + } + + server.setHandler(servletContextHandler); server.setConnectors(new Connector[]{httpServerConnector, httpsServerConnector}); } } - ctxt = new ServletContextHandler(0); - ctxt.setContextPath("/"); - server.setHandler(ctxt); - ctxt.addServlet(new ServletHolder(new NodeServlet(delivery)), "/*"); - nodeMainLogger.info("NODE0005 Data Router Node Activating Service"); - server.start(); + + try { + server.start(); + nodeMainLogger.info("NODE00006 Node Server started-" + server.getState()); + } catch (Exception e) { + nodeMainLogger.info("NODE00006 Jetty failed to start. Reporting will we unavailable", e); + } server.join(); + nodeMainLogger.info("NODE00007 Node Server joined - " + server.getState()); } } diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeServlet.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeServlet.java index 79888795..93e901f9 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeServlet.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/NodeServlet.java @@ -26,25 +26,24 @@ package org.onap.dmaap.datarouter.node; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Writer; +import org.apache.log4j.Logger; +import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; +import org.slf4j.MDC; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; import java.util.regex.Pattern; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.log4j.Logger; + +import static org.onap.dmaap.datarouter.node.NodeUtils.sendResponseError; + import org.jetbrains.annotations.Nullable; -import org.onap.dmaap.datarouter.node.eelf.EelfMsgs; -import org.slf4j.MDC; import static org.onap.dmaap.datarouter.node.NodeUtils.*; @@ -64,9 +63,8 @@ public class NodeServlet extends HttpServlet { private static Logger logger = Logger.getLogger("org.onap.dmaap.datarouter.node.NodeServlet"); private static NodeConfigManager config; private static Pattern MetaDataPattern; - //Adding EELF Logger Rally:US664892 - private static EELFLogger eelflogger = EELFManager.getInstance() - .getLogger(NodeServlet.class); + private static EELFLogger eelflogger = EELFManager.getInstance().getLogger(NodeServlet.class); + private boolean isAAFFeed = false; private final Delivery delivery; static { @@ -88,6 +86,7 @@ public class NodeServlet extends HttpServlet { /** * Get the NodeConfigurationManager */ + @Override public void init() { config = NodeConfigManager.getInstance(); logger.info("NODE0101 Node Servlet Configured"); @@ -97,14 +96,15 @@ public class NodeServlet extends HttpServlet { if (config.isShutdown() || !config.isConfigured()) { sendResponseError(resp, HttpServletResponse.SC_SERVICE_UNAVAILABLE, logger); logger.info("NODE0102 Rejecting request: Service is being quiesced"); - return (true); + return true; } - return (false); + return false; } /** * Handle a GET for /internal/fetchProv */ + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) { NodeUtils.setIpAndFqdnForEelf("doGet"); NodeUtils.setRequestIdAndInvocationId(req); @@ -149,12 +149,13 @@ public class NodeServlet extends HttpServlet { /** * Handle all PUT requests */ + @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) { NodeUtils.setIpAndFqdnForEelf("doPut"); NodeUtils.setRequestIdAndInvocationId(req); eelflogger.info(EelfMsgs.ENTRY); eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_FEEDID, req.getHeader("X-DMAAP-DR-ON-BEHALF-OF"), - getIdFromPath(req) + ""); + getIdFromPath(req) + ""); try { common(req, resp, true); } catch (IOException ioe) { @@ -166,6 +167,7 @@ public class NodeServlet extends HttpServlet { /** * Handle all DELETE requests */ + @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) { NodeUtils.setIpAndFqdnForEelf("doDelete"); NodeUtils.setRequestIdAndInvocationId(req); @@ -215,6 +217,27 @@ public class NodeServlet extends HttpServlet { return; } feedid = fileid.substring(0, i); + + if (config.getCadiEnabeld()) { + String path = req.getPathInfo(); + if (!path.startsWith("/internal") && feedid != null) { + String aafInstance = config.getAafInstance(feedid); + if (!(aafInstance.equalsIgnoreCase("legacy"))) { + isAAFFeed = true; + String permission = config.getPermission(aafInstance); + logger.info("NodeServlet.common() permission string - " + permission); + //Check in CADI Framework API if user has AAF permission or not + if (!req.isUserInRole(permission)) { + String message = "AAF disallows access to permission string - " + permission; + logger.info("NODE0106 Rejecting unauthenticated PUT or DELETE of " + req.getPathInfo() + " from " + req.getRemoteAddr()); + resp.sendError(HttpServletResponse.SC_FORBIDDEN, message); + eelflogger.info(EelfMsgs.EXIT); + return; + } + } + } + } + fileid = fileid.substring(i + 1); pubid = config.getPublishId(); xpubid = req.getHeader("X-DMAAP-DR-PUBLISH-ID"); @@ -228,6 +251,7 @@ public class NodeServlet extends HttpServlet { } fileid = fileid.substring(18); pubid = req.getHeader("X-DMAAP-DR-PUBLISH-ID"); + user = "datartr"; // SP6 : Added usr as datartr to avoid null entries for internal routing targets = config.parseRouting(req.getHeader("X-DMAAP-DR-ROUTING")); } else { logger.info("NODE0105 Rejecting bad URI for PUT or DELETE of " + req.getPathInfo() + " from " + req @@ -257,17 +281,34 @@ public class NodeServlet extends HttpServlet { String logurl = "https://" + hp + "/internal/publish/" + fileid; if (feedid != null) { logurl = "https://" + hp + "/publish/" + feedid + "/" + fileid; - String reason = config.isPublishPermitted(feedid, credentials, ip); - if (reason != null) { - logger.info( - "NODE0111 Rejecting unauthorized publish attempt to feed " + feedid + " fileid " + fileid - + " from " - + ip + " reason " + reason); - resp.sendError(HttpServletResponse.SC_FORBIDDEN, reason); - eelflogger.info(EelfMsgs.EXIT); - return; + //Cadi code starts + if (!isAAFFeed) { + String reason = config.isPublishPermitted(feedid, credentials, ip); + if (reason != null) { + logger.info("NODE0111 Rejecting unauthorized publish attempt to feed " + PathUtil.cleanString(feedid) + " fileid " + PathUtil.cleanString(fileid) + " from " + PathUtil.cleanString(ip) + " reason " + PathUtil.cleanString(reason)); + resp.sendError(HttpServletResponse.SC_FORBIDDEN, reason); + eelflogger.info(EelfMsgs.EXIT); + return; + } + user = config.getAuthUser(feedid, credentials); + } else { + String reason = config.isPublishPermitted(feedid, ip); + if (reason != null) { + logger.info("NODE0111 Rejecting unauthorized publish attempt to feed " + PathUtil.cleanString(feedid) + " fileid " + PathUtil.cleanString(fileid) + " from " + PathUtil.cleanString(ip) + " reason Invalid AAF user- " + PathUtil.cleanString(reason)); + String message = "Invalid AAF user- " + PathUtil.cleanString(reason); + logger.info("NODE0106 Rejecting unauthenticated PUT or DELETE of " + PathUtil.cleanString(req.getPathInfo()) + " from " + PathUtil.cleanString(req.getRemoteAddr())); + resp.sendError(HttpServletResponse.SC_FORBIDDEN, message); + return; + } + if ((req.getUserPrincipal() != null) && (req.getUserPrincipal().getName() != null)) { + String userName = req.getUserPrincipal().getName(); + String[] attid = userName.split("@"); + user = attid[0]; + } else { + user = "AAFUser"; + } } - user = config.getAuthUser(feedid, credentials); + //Cadi code Ends String newnode = config.getIngressNode(feedid, user, ip); if (newnode != null) { String port = ""; @@ -276,17 +317,17 @@ public class NodeServlet extends HttpServlet { port = ":" + iport; } String redirto = "https://" + newnode + port + "/publish/" + feedid + "/" + fileid; - logger.info( - "NODE0108 Redirecting publish attempt for feed " + feedid + " user " + user + " ip " + ip - + " to " - + redirto); - resp.sendRedirect(redirto); + logger.info("NODE0108 Redirecting publish attempt for feed " + PathUtil.cleanString(feedid) + " user " + PathUtil.cleanString(user) + " ip " + PathUtil.cleanString(ip) + " to " + PathUtil.cleanString(redirto)); //Fortify scan fixes - log forging + resp.sendRedirect(PathUtil.cleanString(redirto)); //Fortify scan fixes-open redirect - 2 issues eelflogger.info(EelfMsgs.EXIT); return; } resp.setHeader("X-DMAAP-DR-PUBLISH-ID", pubid); } - String fbase = config.getSpoolDir() + "/" + pubid; + if (req.getPathInfo().startsWith("/internal/publish/")) { + feedid = req.getHeader("X-DMAAP-DR-FEED-ID"); + } + String fbase = PathUtil.cleanString(config.getSpoolDir() + "/" + pubid); //Fortify scan fixes-Path manipulation File data = new File(fbase); File meta = new File(fbase + ".M"); OutputStream dos = null; @@ -323,17 +364,13 @@ public class NodeServlet extends HttpServlet { } if ("x-dmaap-dr-meta".equals(hnlc)) { if (hv.length() > 4096) { - logger.info( - "NODE0109 Rejecting publish attempt with metadata too long for feed " + feedid - + " user " + user + " ip " + ip); + logger.info("NODE0109 Rejecting publish attempt with metadata too long for feed " + PathUtil.cleanString(feedid) + " user " + PathUtil.cleanString(user) + " ip " + PathUtil.cleanString(ip)); //Fortify scan fixes - log forging resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Metadata too long"); eelflogger.info(EelfMsgs.EXIT); return; } if (!MetaDataPattern.matcher(hv.replaceAll("\\\\.", "X")).matches()) { - logger.info( - "NODE0109 Rejecting publish attempt with malformed metadata for feed " + feedid - + " user " + user + " ip " + ip); + logger.info("NODE0109 Rejecting publish attempt with malformed metadata for feed " + PathUtil.cleanString(feedid) + " user " + PathUtil.cleanString(user) + " ip " + PathUtil.cleanString(ip)); //Fortify scan fixes - log forging resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Malformed metadata"); eelflogger.info(EelfMsgs.EXIT); return; @@ -343,10 +380,10 @@ public class NodeServlet extends HttpServlet { } } } - if(!hasRequestIdHeader){ + if (!hasRequestIdHeader) { mx.append("X-ONAP-RequestID\t").append(MDC.get("RequestId")).append('\n'); } - if(!hasInvocationIdHeader){ + if (!hasInvocationIdHeader) { mx.append("X-InvocationID\t").append(MDC.get("InvocationId")).append('\n'); } mx.append("X-DMAAP-DR-RECEIVED\t").append(rcvd).append('\n'); @@ -368,9 +405,9 @@ public class NodeServlet extends HttpServlet { try { exlen = Long.parseLong(req.getHeader("Content-Length")); } catch (Exception e) { + logger.error("NODE0529 Exception common: " + e); } - StatusLog.logPubFail(pubid, feedid, logurl, req.getMethod(), ctype, exlen, data.length(), ip, user, - ioe.getMessage()); + StatusLog.logPubFail(pubid, feedid, logurl, req.getMethod(), ctype, exlen, data.length(), ip, user, ioe.getMessage()); eelflogger.info(EelfMsgs.EXIT); throw ioe; } @@ -381,7 +418,7 @@ public class NodeServlet extends HttpServlet { // TODO: unknown destination continue; } - String dbase = di.getSpool() + "/" + pubid; + String dbase = PathUtil.cleanString(di.getSpool() + "/" + pubid); //Fortify scan fixes-Path Manipulation Files.createLink(Paths.get(dbase), dpath); mw = new FileWriter(meta); mw.write(metadata); @@ -393,13 +430,25 @@ public class NodeServlet extends HttpServlet { } resp.setStatus(HttpServletResponse.SC_NO_CONTENT); - resp.getOutputStream().close(); - StatusLog.logPub(pubid, feedid, logurl, req.getMethod(), ctype, data.length(), ip, user, - HttpServletResponse.SC_NO_CONTENT); + try { + resp.getOutputStream().close(); + } catch (IOException ioe) { + long exlen = -1; + try { + exlen = Long.parseLong(req.getHeader("Content-Length")); + } catch (Exception e) { + logger.debug("NODE00000 Exception common: " + e); + } + StatusLog.logPubFail(pubid, feedid, logurl, req.getMethod(), ctype, exlen, data.length(), ip, user, ioe.getMessage()); + //Fortify scan fixes - log forging + logger.info("NODE0110 IO Exception while closing IO stream " + PathUtil.cleanString(feedid) + " user " + PathUtil.cleanString(user) + " ip " + PathUtil.cleanString(ip) + " " + ioe.toString(), ioe); + + throw ioe; + } + + StatusLog.logPub(pubid, feedid, logurl, req.getMethod(), ctype, data.length(), ip, user, HttpServletResponse.SC_NO_CONTENT); } catch (IOException ioe) { - logger.info( - "NODE0110 IO Exception receiving publish attempt for feed " + feedid + " user " + user + " ip " + ip - + " " + ioe.toString(), ioe); + logger.info("NODE0110 IO Exception receiving publish attempt for feed " + feedid + " user " + user + " ip " + ip + " " + ioe.toString(), ioe); eelflogger.info(EelfMsgs.EXIT); throw ioe; } finally { @@ -407,27 +456,32 @@ public class NodeServlet extends HttpServlet { try { is.close(); } catch (Exception e) { + logger.error("NODE0530 Exception common: " + e); } } if (dos != null) { try { dos.close(); } catch (Exception e) { + logger.error("NODE0531 Exception common: " + e); } } if (mw != null) { try { mw.close(); } catch (Exception e) { + logger.error("NODE0532 Exception common: " + e); } } try { data.delete(); } catch (Exception e) { + logger.error("NODE0533 Exception common: " + e); } try { meta.delete(); } catch (Exception e) { + logger.error("NODE0534 Exception common: " + e); } } } @@ -448,7 +502,7 @@ public class NodeServlet extends HttpServlet { int subId = Integer.parseInt(subscriptionId); pubid = fileid.substring(i + 1); String errorMessage = "Unable to delete files (" + pubid + ", " + pubid + ".M) from DR Node: " - + config.getMyName() + "."; + + config.getMyName() + "."; int subIdDir = subId - (subId % 100); if (!isAuthorizedToDelete(resp, subscriptionId, errorMessage)) { return; diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/PathUtil.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/PathUtil.java new file mode 100644 index 00000000..a4034410 --- /dev/null +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/PathUtil.java @@ -0,0 +1,88 @@ +/** + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.node; + +/** + * FORTIFY SCAN FIXES + *

This Utility is used for Fortify fixes. It Validates the path url formed from + * the string passed in the request parameters.

+ * + */ +class PathUtil { + + /** + * This method takes String as the parameter and return the filtered path string. + * @param aString String to clean + * @return A cleaned String + */ + static String cleanString(String aString) { + if (aString == null) return null; + String cleanString = ""; + for (int i = 0; i < aString.length(); ++i) { + cleanString += cleanChar(aString.charAt(i)); + } + return cleanString; + } + + /** + * This method filters the valid special characters in path string. + * @param aChar The char to be cleaned + * @return The cleaned char + */ + private static char cleanChar(char aChar) { + // 0 - 9 + for (int i = 48; i < 58; ++i) { + if (aChar == i) return (char) i; + } + // 'A' - 'Z' + for (int i = 65; i < 91; ++i) { + if (aChar == i) return (char) i; + } + // 'a' - 'z' + for (int i = 97; i < 123; ++i) { + if (aChar == i) return (char) i; + } + // other valid characters + switch (aChar) { + case '/': + return '/'; + case '.': + return '.'; + case '-': + return '-'; + case ':': + return ':'; + case '?': + return '?'; + case '&': + return '&'; + case '=': + return '='; + case '#': + return '#'; + case '_': + return '_'; + case ' ': + return ' '; + } + return '%'; + } +} diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/ProvData.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/ProvData.java index 77c5e996..a9c5c6fe 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/ProvData.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/ProvData.java @@ -135,7 +135,17 @@ public class ProvData { String fid = gvas(jfeed, "feedid"); String fname = gvas(jfeed, "name"); String fver = gvas(jfeed, "version"); - pfv.add(new NodeConfig.ProvFeed(fid, fname + "//" + fver, stat)); + String createdDate = gvas(jfeed, "created_date"); + /* + * START - AAF changes + * TDP EPIC US# 307413 + * Passing aafInstance to ProvFeed from feeds json passed by prov to identify legacy/AAF feeds + */ + String aafInstance = gvas(jfeed, "aaf_instance"); + pfv.add(new NodeConfig.ProvFeed(fid, fname + "//" + fver, stat,createdDate, aafInstance)); + /* + * END - AAF changes + */ JSONObject jauth = jfeed.optJSONObject("authorization"); if (jauth == null) { continue; @@ -175,7 +185,8 @@ public class ProvData { boolean use100 = jdel.getBoolean("use100"); boolean privilegedSubscriber = jsub.getBoolean("privilegedSubscriber"); boolean decompress = jsub.getBoolean("decompress"); - psv.add(new NodeConfig.ProvSubscription(sid, fid, delurl, id, NodeUtils.getAuthHdr(id, password), monly, use100, privilegedSubscriber, decompress)); + boolean followRedirect = jsub.getBoolean("follow_redirect"); + psv.add(new NodeConfig.ProvSubscription(sid, fid, delurl, id, NodeUtils.getAuthHdr(id, password), monly, use100, privilegedSubscriber, followRedirect, decompress)); } } JSONObject jparams = jcfg.optJSONObject("parameters"); diff --git a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/SubnetMatcher.java b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/SubnetMatcher.java index 2e83e222..6f74df48 100644 --- a/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/SubnetMatcher.java +++ b/datarouter-node/src/main/java/org/onap/dmaap/datarouter/node/SubnetMatcher.java @@ -24,8 +24,6 @@ package org.onap.dmaap.datarouter.node; -import java.net.*; - /** * Compare IP addresses as byte arrays to a subnet specified as a CIDR */ diff --git a/datarouter-node/src/main/resources/drNodeCadi.properties b/datarouter-node/src/main/resources/drNodeCadi.properties new file mode 100644 index 00000000..8dfcab1c --- /dev/null +++ b/datarouter-node/src/main/resources/drNodeCadi.properties @@ -0,0 +1,23 @@ +cadi_x509_issuers=CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US +cadi_keyfile=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.keyfile +cadi_keystore=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks +cadi_keystore_password=]3V)($O&.Mv]W{f8^]6SxGNL +cadi_key_password=]3V)($O&.Mv]W{f8^]6SxGNL +cadi_alias=dmaap-dr-node@dmaap-dr.onap.org +cadi_truststore=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks +cadi_truststore_password=(Rd,&{]%ePdp}4JZjqoJ2G+g + +aaf_env=DEV +aaf_locate_url=https://aaf-onap-test.osaaf.org:8095 +aaf_oauth2_introspect_url=https://AAF_LOCATE_URL/AAF_NS.introspect:2.1/introspect +aaf_oauth2_token_url=https://AAF_LOCATE_URL/AAF_NS.token:2.1/token +aaf_url=https://AAF_LOCATE_URL/AAF_NS.service:2.1 +cadi_protocols=TLSv1.1,TLSv1.2 +cm_url=https://AAF_LOCATE_URL/AAF_NS.cm:2.1 +fs_url=https://AAF_LOCATE_URL/AAF_NS.fs.2.1 +gui_url=https://AAF_LOCATE_URL/AAF_NS.gui.2.1 + +cadi_latitude=53.423 +cadi_longitude=7.940 + +cadi_loglevel=DEBUG \ No newline at end of file diff --git a/datarouter-node/src/main/resources/node.properties b/datarouter-node/src/main/resources/node.properties index 8b5568bc..27e91c90 100644 --- a/datarouter-node/src/main/resources/node.properties +++ b/datarouter-node/src/main/resources/node.properties @@ -21,91 +21,83 @@ # * #------------------------------------------------------------------------------- # -# Configuration parameters fixed at startup for the DataRouter node +# Configuration parameters set at startup for the DataRouter node # # URL to retrieve dynamic configuration -# -#ProvisioningURL: ${DRTR_PROV_INTURL} -ProvisioningURL=https://dmaap-dr-prov:8443/internal/prov - +ProvisioningURL = https://dmaap-dr-prov:8443/internal/prov # # URL to upload PUB/DEL/EXP logs -# -#LogUploadURL: ${DRTR_LOG_URL} -LogUploadURL=https://dmaap-dr-prov:8443/internal/logs - +LogUploadURL = https://dmaap-dr-prov:8443/internal/logs # # The port number for http as seen within the server -# -#IntHttpPort: ${DRTR_NODE_INTHTTPPORT:-8080} -IntHttpPort=8080 +IntHttpPort = 8080 # # The port number for https as seen within the server -# -IntHttpsPort=8443 +IntHttpsPort = 8443 # # The external port number for https taking port mapping into account +ExtHttpsPort = 443 # -ExtHttpsPort=443 -# -# The minimum interval between fetches of the dynamic configuration -# from the provisioning server -# -MinProvFetchInterval=10000 +# The minimum interval between fetches of the dynamic configuration from the provisioning server +MinProvFetchInterval = 10000 # # The minimum interval between saves of the redirection data file -# -MinRedirSaveInterval=10000 +MinRedirSaveInterval = 10000 # # The path to the directory where log files are stored -# -LogDir=/opt/app/datartr/logs +LogDir = /opt/app/datartr/logs # # The retention interval (in days) for log files -# -LogRetention=30 +LogRetention = 30 # # The path to the directories where data and meta data files are stored -# -SpoolDir=/opt/app/datartr/spool +SpoolDir = /opt/app/datartr/spool # # The path to the redirection data file -# -#RedirectionFile: etc/redirections.dat +RedirectionFile = etc/redirections.dat # # The type of keystore for https -KeyStoreType: jks +KeyStoreType = jks # # The path to the keystore for https -# -KeyStoreFile:/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks +KeyStoreFile = /opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks # # The password for the https keystore -# KeyStorePassword=]3V)($O&.Mv]W{f8^]6SxGNL # # The password for the private key in the https keystore -# KeyPassword=]3V)($O&.Mv]W{f8^]6SxGNL # # The type of truststore for https -# -TrustStoreType=jks +TrustStoreType = jks # # The path to the truststore for https -# -#TrustStoreFile=/usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts -TrustStoreFile=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks +TrustStoreFile = /opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks # # The password for the https truststore -# TrustStorePassword=(Rd,&{]%ePdp}4JZjqoJ2G+g # # The path to the file used to trigger an orderly shutdown -# -QuiesceFile=etc/SHUTDOWN +QuiesceFile = etc/SHUTDOWN # # The key used to generate passwords for node to node transfers +NodeAuthKey = Node123! +# +# DR_NODE DEFAULT ENABLED TLS PROTOCOLS +NodeHttpsProtocols = TLSv1.1|TLSv1.2 +# +# AAF type to generate permission string +AAFType = org.onap.dmaap-dr.feed +# +# AAF default instance to generate permission string - default should be legacy +AAFInstance = legacy +# +# AAF action to generate permission string - default should be publish +AAFAction = publish +# +# AAF URL to connect to AAF server +AafUrl = https://aaf-onap-test.osaaf.org:8095 # -NodeAuthKey=Node123! +# AAF CADI enabled flag +CadiEnabled = false diff --git a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilterTest.java b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilterTest.java new file mode 100644 index 00000000..f6737b1e --- /dev/null +++ b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DRNodeCadiFilterTest.java @@ -0,0 +1,121 @@ +/**- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.node; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.api.support.membermodification.MemberMatcher; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static org.mockito.Mockito.*; + +@SuppressStaticInitializationFor("org.onap.dmaap.datarouter.node.NodeConfigManager") +@PrepareForTest({CadiFilter.class}) +@RunWith(PowerMockRunner.class) +public class DRNodeCadiFilterTest +{ + + @Mock + private PropAccess access; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain chain; + + private DRNodeCadiFilter cadiFilter; + + + @Before + public void setUp() throws ServletException { + cadiFilter = new DRNodeCadiFilter(false, access); + } + + @Test + public void Given_doFilter_Called_And_Method_Is_GET_And_AAF_DB_Instance_Is_NULL_Then_Chain_doFilter_Called() throws Exception { + PowerMockito.mockStatic(NodeConfigManager.class); + NodeConfigManager config = mock(NodeConfigManager.class); + + PowerMockito.when(NodeConfigManager.getInstance()).thenReturn(config); + PowerMockito.when(config.getAafInstance("/other/5")).thenReturn("legacy"); + when(request.getPathInfo()).thenReturn("/publish/5"); + when(request.getMethod()).thenReturn("GET"); + cadiFilter.doFilter(request,response,chain); + verify(chain, times(1)).doFilter(request, response); + } + + @Test + public void Given_doFilter_Called_And_Method_Is_GET_And_Path_Includes_Internal_Then_Chain_doFilter_Called() throws Exception { + PowerMockito.mockStatic(NodeConfigManager.class); + NodeConfigManager config = mock(NodeConfigManager.class); + + PowerMockito.when(NodeConfigManager.getInstance()).thenReturn(config); + PowerMockito.when(config.getAafInstance("/other/5")).thenReturn("legacy"); + when(request.getPathInfo()).thenReturn("/internal/5"); + when(request.getMethod()).thenReturn("GET"); + cadiFilter.doFilter(request,response,chain); + verify(chain, times(1)).doFilter(request, response); + } + + @Test + public void Given_doFilter_Called_And_Method_Is_GET_And_AAF_DB_Is_Not_Null_Then_Super_doFilter_Called() throws Exception { + PowerMockito.mockStatic(NodeConfigManager.class); + NodeConfigManager config = mock(NodeConfigManager.class); + + PowerMockito.when(NodeConfigManager.getInstance()).thenReturn(config); + PowerMockito.when(config.getAafInstance("5")).thenReturn("EXISTS"); + when(request.getPathInfo()).thenReturn("/publish/5/fileId"); + when(request.getMethod()).thenReturn("GET"); + PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(CadiFilter.class)); + cadiFilter.doFilter(request,response,chain); + verify(chain, times(0)).doFilter(request, response); + } + + @Test + public void Given_getFileid_Called_And_SendError_Fails_Then_Throw_IOException_And_Call_chain_doFilter() throws Exception { + PowerMockito.mockStatic(NodeConfigManager.class); + NodeConfigManager config = mock(NodeConfigManager.class); + + PowerMockito.when(NodeConfigManager.getInstance()).thenReturn(config); + when(request.getPathInfo()).thenReturn("/publish/5"); + when(request.getMethod()).thenReturn("DELETE"); + doThrow(new IOException()).when(response).sendError(HttpServletResponse.SC_NOT_FOUND, "Invalid request URI. Expecting /. Possible missing fileid."); + cadiFilter.doFilter(request,response,chain); + verify(chain, times(1)).doFilter(request, response); + } +} diff --git a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryQueueTest.java b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryQueueTest.java index 97904a5e..9a3d82e5 100644 --- a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryQueueTest.java +++ b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryQueueTest.java @@ -22,6 +22,7 @@ ******************************************************************************/ package org.onap.dmaap.datarouter.node; + import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.Before; import org.junit.Test; @@ -29,12 +30,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.modules.junit4.PowerMockRunner; -import static org.junit.Assert.*; import java.io.File; - - -import static org.mockito.Mockito.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) public class DeliveryQueueTest { @@ -55,7 +54,7 @@ public class DeliveryQueueTest { } @Test - public void Given_New_DeliveryQueue_Directory_Is_Created_As_Defined_By_DestInfo() throws Exception { + public void Given_New_DeliveryQueue_Directory_Is_Created_As_Defined_By_DestInfo() { when(destInfo.getSpool()).thenReturn("tmp"); File file = new File("tmp"); assertTrue(file.exists()); @@ -63,14 +62,14 @@ public class DeliveryQueueTest { } @Test - public void Given_Delivery_Task_Failed_And_Resume_Time_Not_Reached_Return_Null() throws Exception{ + public void Given_Delivery_Task_Failed_And_Resume_Time_Not_Reached_Return_Null() throws Exception { FieldUtils.writeField(deliveryQueue,"failed",true,true); FieldUtils.writeField(deliveryQueue,"resumetime",System.currentTimeMillis()*2,true); assertNull(deliveryQueue.peekNext()); } @Test - public void Given_Delivery_Task_Return_Next_Delivery_Task_Id() throws Exception{ + public void Given_Delivery_Task_Return_Next_Delivery_Task_Id() throws Exception { prepareFiles(); when(destInfo.getSpool()).thenReturn(dirPath); deliveryQueue = new DeliveryQueue(deliveryQueueHelper, destInfo); @@ -81,19 +80,19 @@ public class DeliveryQueueTest { } @Test - public void Given_Delivery_Task_Cancel_And_FileId_Is_Null_Return_Zero() throws Exception{ + public void Given_Delivery_Task_Cancel_And_FileId_Is_Null_Return_Zero() { long rc = deliveryQueue.cancelTask("123.node.datarouternew.com"); assertEquals(0, rc); } - private void prepareFiles() throws Exception{ + private void prepareFiles() throws Exception { createFolder(dirPath); createFile(FileName1, dirPath); String[] files = new String[2]; files[0] = dirPath + FileName1; } - private void createFolder(String dirName) throws Exception{ + private void createFolder(String dirName) throws Exception { String dirPath = dirName; File newDirectory = new File(dirPath); @@ -101,13 +100,13 @@ public class DeliveryQueueTest { if (isCreated) { System.out.println("1. Successfully created directories, path: " + newDirectory.getCanonicalPath()); } else if (newDirectory.exists()) { - System.out.printf("1. Directory path already exist, path: " + newDirectory.getCanonicalPath()); + System.out.print("1. Directory path already exist, path: " + newDirectory.getCanonicalPath()); } else { System.out.println("1. Unable to create directory"); } } - private void createFile( String file, String dir) throws Exception{ + private void createFile(String file, String dir) throws Exception { String FileName = file; String dirPath = dir; diff --git a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryTest.java b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryTest.java index 4ca907f7..efa43e11 100644 --- a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryTest.java +++ b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/DeliveryTest.java @@ -97,7 +97,7 @@ public class DeliveryTest { private DestInfo[] createDestInfoObjects() { DestInfo[] destInfos = new DestInfo[1]; - DestInfo destInfo = new DestInfo("node.datarouternew.com", "spool/s/0/1", "1", "logs/", "/subs/1", "user1", "Basic dXNlcjE6cGFzc3dvcmQx", false, true, false, false); + DestInfo destInfo = new DestInfo("node.datarouternew.com", "spool/s/0/1", "1", "logs/", "/subs/1", "user1", "Basic dXNlcjE6cGFzc3dvcmQx", false, true, false, false, false); destInfos[0] = destInfo; return destInfos; } diff --git a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeConfigTest.java b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeConfigTest.java index 4b614d56..7dddd67a 100644 --- a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeConfigTest.java +++ b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeConfigTest.java @@ -193,6 +193,7 @@ public class NodeConfigTest { endpointAddrs.put("172.0.0.1"); auth.put("endpoint_addrs", endpointAddrs); feed.put("authorization", auth); + feed.put("aaf_instance", "legacy"); feeds.put(feed); provData.put("feeds", feeds); } @@ -211,6 +212,7 @@ public class NodeConfigTest { delivery.put("use100", true); subscription.put("delivery", delivery); subscription.put("privilegedSubscriber", false); + subscription.put("follow_redirect", false); subscription.put("decompress", false); subscriptions.put(subscription); provData.put("subscriptions", subscriptions); diff --git a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeServletTest.java b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeServletTest.java index 065565d3..99e34c6f 100644 --- a/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeServletTest.java +++ b/datarouter-node/src/test/java/org/onap/dmaap/datarouter/node/NodeServletTest.java @@ -59,7 +59,9 @@ public class NodeServletTest { @Mock private HttpServletResponse response; - ListAppender listAppender; + private ListAppender listAppender; + + private NodeConfigManager config = mock(NodeConfigManager.class); @Before public void setUp() throws Exception { @@ -215,6 +217,17 @@ public class NodeServletTest { verifyEnteringExitCalled(listAppender); } + @Test + public void Given_Request_Is_HTTP_PUT_On_Publish_On_AAF_Feed_And_Cadi_Enabled_And_No_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(config.getCadiEnabeld()).thenReturn(true); + when(config.getAafInstance("1")).thenReturn("*"); + when(request.getPathInfo()).thenReturn("/publish/1/fileName"); + setHeadersForValidRequest(true); + nodeServlet.doPut(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); + verifyEnteringExitCalled(listAppender); + } + @Test public void Given_Request_Is_HTTP_DELETE_On_Publish_With_Meta_Data_Malformed_Then_Bad_Request_Response_Is_Generated() throws Exception { when(request.getPathInfo()).thenReturn("/publish/1/fileName"); @@ -286,7 +299,6 @@ public class NodeServletTest { } private void setUpConfig() throws IllegalAccessException { - NodeConfigManager config = mock(NodeConfigManager.class); PowerMockito.mockStatic(NodeConfigManager.class); when(config.isShutdown()).thenReturn(false); when(config.isConfigured()).thenReturn(true); diff --git a/datarouter-prov/aaf_certs/org.onap.dmaap-dr.keyfile b/datarouter-prov/aaf_certs/org.onap.dmaap-dr.keyfile new file mode 100755 index 00000000..a586a72e --- /dev/null +++ b/datarouter-prov/aaf_certs/org.onap.dmaap-dr.keyfile @@ -0,0 +1,27 @@ +VDu7g5rP2-JMemc6RwP0HqM4ILJnuja8R_bzdCG1u0_Z2EQJN_7ZNPDb28V6JCDF-59sX10_i9vT +-nw77ViAuwJO7ffSut8ipVhESeQxTokZsErzMFpeJZDhMM16W5LLtxwUs_tgh_EQIJSc-WcFUNYS +NagugzjmNE5-hUosLgnt7mZ1nX4zFER9Nq1ce0EQS--kAB9rxcRmoywPlBlHvPmP_caiwpa1SzJp +gbFF6smyLEWhjDhJkgvM_4FwaQCbJBVGcy2a3Lc9orHsz9S1RJTZ9CExhasM0qEp3kk0fMEFE9k6 +TomOpUBGizLfHPpg18KtXyM8zErj8qdS0KMwaCKtwGzCWw08MF5rVZrMYWLKDMOs8U2ESU7x28nV +KSrAsR11QD7vX4PTVTfjEpcHSGe-9nPD7TckY8_O-9l67v_OUW1Fw4MSESCN0RtT7ZlNYwDV0syA +X94rv1Y45N41tfX76jz8PDB9G-PF36BtkICJWK24zwuQDgpkURhCLPYzvBhPmCPyQil810X9s_bX +icmV2cSN3oYQRz5dNSjUYH1CDt9edAJt4p2PQhM3A2xXyw1FVvbAIYA7iF-3qYG9csroBzsCcS5C +hX8929jZHQWU5pygtpedEWhX__tnSrd-xIpxPnhOxrb-lNLva5JGKauU2DrGoLd_7RTwbuRdCiQo +uGFtYOtjLciPz81oEEpXQTReeSnvGyGiZNxRrKWMEmq-biyQd4DuRVmTDuLAG4rd92QWS6qUz0uf +9TtJiYlN3mNkxz3ahEGWLKR79rH9juJ3xqpcF-Rb7Y1bmiCDBv3DVVFiYIpwQuto1iSIYabL34Ql +QqX65E1c3uvPksN6Nl1nvAVxSKM94wAFsMiA9Rp8AN9pDSxtj7D3kZCG8I0YaIxF_s-OeJtr1RPx +ifv8vrwN23GUQCmpGBbyNXNe6zz-hz_HJdAsBr6WjLny9LQkeYszHGF-OL5ps6K5gHBRV0Ui1C7H +Gj7egsjnV_Lu5MpBxhTrquDrZKK3t38kf0zrV-zfSGzJlGbLS91h8bR-7FAZiNEzgXPWYi26w81i +W3Csx4oqsfKswp0pO80rggkFf9LL9pjCkSUTTVyF-toa9kY2h7JsVtqntP4Mjagp4Tnj01988kne +Mj8SLm2mJySTLdH5Hi4arKW943iCqYjEaZ7wXFNJSZ6vvBm3KC1XX6C0DjRrgQoKIHw_4JcGhvOU +P5LdpBT1AOcE8lIKrGGq8hyfJKLVUMec-NkzAT2aIl0YJoUcJv4fs-lKccGL4FDrq5y_yvD3xQ6v +xt7KTanFxntqLYmM72Y2eFwJGlDEHhm0SejAV64-odksA_zMLLuYwkq_KSj0If9AVpRXz7KzIj9P +9y-WMfAWKFfIyqGWXt5sYdMTQPG4qKCcFQBx3T0E6kiQMBuOZz0dR032eFPMexrymEowjosr2jt3 +ib8rFxmPMyyUWoV1iBafFMLf5PN2oapTq76gqeQQGGwpmYJB8cWlS1Eq_ZbzZpK2PSwX-fC6NSf3 +KtOV_r2VI3e_V6csnWTY8nxCJj9FlQCvLOzp964DNsBeUwDpsD7T_pgQy0THgAnq32ZtDvQfgeUE +TUJC7oQeOEY7QBWjbZkumds51j7oTlsp2dPForlHwBk_2Nd5VCwVRNa1QMS8WcghLYbUCX5zeplc +u2bopHn9GD614gt7f7wysDgTGegOCAuMoL7wA9TXN4BSfAF9mwpdtRFE4lT3N1xmfhKt9rM6Lu8T +RGvBOmTOTT5IwJrrE5mpvmESw05sHUcCZ9ENv-VhoeC3Ffk9uXqrDggQgaDs9XcXqzEPBp9wDPTt +UJpbtBGECSSTuXAZyUh3I0WFz96kVuHmQpDYVTpy1sxPjmgjgKyhu_6jLGSsYpVBH063n7KSKVdF +ROKojZN4-FsBlPhoOhNEd7x1OBfgCG79HKGk33jhESObZkPIrcTc17jiE-ud2D1B1_Fl-OJNR7Vh +GIk4WMZrH9NeVwDuIgBxF74plqg6tSl0Cdd4m7e3Drsq-wRfsU2gNTo5oL-2SgbsO5n3ubQf \ No newline at end of file diff --git a/datarouter-prov/pom.xml b/datarouter-prov/pom.xml index 44f70f5f..284a8cac 100755 --- a/datarouter-prov/pom.xml +++ b/datarouter-prov/pom.xml @@ -259,6 +259,11 @@ + + org.onap.aaf.authz + aaf-cadi-aaf + ${aaf-cadi-aaf.version} + diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/BaseServlet.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/BaseServlet.java index 2d4f85f6..50ec1b45 100755 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/BaseServlet.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/BaseServlet.java @@ -24,68 +24,42 @@ package org.onap.dmaap.datarouter.provisioning; -import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN; - -import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS; -import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; -import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID; - - - -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.cert.X509Certificate; -import java.sql.Connection; -import java.sql.SQLException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; - import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; +import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import org.onap.dmaap.datarouter.authz.Authorizer; import org.onap.dmaap.datarouter.authz.impl.ProvAuthorizer; import org.onap.dmaap.datarouter.authz.impl.ProvDataProvider; -import org.onap.dmaap.datarouter.provisioning.beans.Deleteable; -import org.onap.dmaap.datarouter.provisioning.beans.Feed; -import org.onap.dmaap.datarouter.provisioning.beans.Group; -import org.onap.dmaap.datarouter.provisioning.beans.Insertable; -import org.onap.dmaap.datarouter.provisioning.beans.NodeClass; -import org.onap.dmaap.datarouter.provisioning.beans.Parameters; -import org.onap.dmaap.datarouter.provisioning.beans.Subscription; -import org.onap.dmaap.datarouter.provisioning.beans.Updateable; +import org.onap.dmaap.datarouter.provisioning.beans.*; import org.onap.dmaap.datarouter.provisioning.utils.DB; +import org.onap.dmaap.datarouter.provisioning.utils.PasswordProcessor; import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter; -import org.json.JSONException; import org.slf4j.MDC; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; - -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.List; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.UUID; -import java.util.regex.Pattern; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Multipart; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.AddressException; + +import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.GeneralSecurityException; +import java.security.cert.X509Certificate; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.*; +import java.util.regex.Pattern; + +import static com.att.eelf.configuration.Configuration.*; /** * This is the base class for all Servlets in the provisioning code. It provides standard constants and some common @@ -98,6 +72,24 @@ import javax.mail.internet.MimeMultipart; public class BaseServlet extends HttpServlet implements ProvDataProvider { public static final String BEHALF_HEADER = "X-DMAAP-DR-ON-BEHALF-OF"; + + public static final String EXCLUDE_AAF_HEADER = "X-EXCLUDE-AAF"; + + private static final String AAF_CADI_FEED_TYPE = "org.onap.dmaap.datarouter.provserver.aaf.feed.type"; + private static final String AAF_CADI_SUB_TYPE = "org.onap.dmaap.datarouter.provserver.aaf.sub.type"; + private static final String AAF_INSTANCE = "org.onap.dmaap.datarouter.provserver.aaf.instance"; + private static final String AAF_CADI_FEED = "org.onap.dmaap-dr.feed"; + private static final String AAF_CADI_SUB = "org.onap.dmaap-dr.sub"; + + static final String CREATE_PERMISSION = "create"; + static final String EDIT_PERMISSION = "edit"; + static final String DELETE_PERMISSION = "delete"; + static final String PUBLISH_PERMISSION = "publish"; + static final String SUSPEND_PERMISSION = "suspend"; + static final String RESTORE_PERMISSION = "restore"; + static final String SUBSCRIBE_PERMISSION = "subscribe"; + static final String APPROVE_SUB_PERMISSION = "approveSub"; + static final String FEED_BASECONTENT_TYPE = "application/vnd.dmaap-dr.feed"; public static final String FEED_CONTENT_TYPE = "application/vnd.dmaap-dr.feed; version=2.0"; public static final String FEEDFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.feed-full; version=2.0"; @@ -110,7 +102,9 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { //Adding groups functionality, ...1610 static final String GROUP_BASECONTENT_TYPE = "application/vnd.dmaap-dr.group"; - static final String GROUPFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.group-full; version=2.0"; + static final String GROUP_CONTENT_TYPE = "application/vnd.dmaap-dr.group; version=2.0"; + public static final String GROUPFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.group-full; version=2.0"; + public static final String GROUPLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.fegrouped-list; version=1.0"; public static final String LOGLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.log-list; version=1.0"; @@ -172,6 +166,10 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { * Array of nodes names and/or FQDNs */ private static String[] nodes = new String[0]; + /** + * [DATARTR-27] Poke all the DR nodes : Array of nodes names and/or FQDNs + */ + private static String[] drnodes = new String[0]; /** * Array of node IP addresses */ @@ -196,10 +194,12 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { * The current number of subscriptions in the system */ static int activeSubs = 0; + /** * The domain used to generate a FQDN from the "bare" node names */ private static String provDomain = "web.att.com"; + /** * The standard FQDN of the provisioning server in this Data Router ecosystem */ @@ -210,7 +210,8 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { */ private static String activeProvName = "feeds-drtr.web.att.com"; - private static String staticRoutingNodes = STATIC_ROUTING_NODES; //Adding new param for static Routing - Rally:US664862-1610 + //Adding new param for static Routing - Rally:US664862-1610 + private static String staticRoutingNodes = STATIC_ROUTING_NODES; /** * This logger is used to log provisioning events @@ -239,7 +240,10 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { //DMAAP-597 (Tech Dept) REST request source IP auth relaxation to accommodate OOM kubernetes deploy private static String isAddressAuthEnabled = (new DB()).getProperties() - .getProperty("org.onap.dmaap.datarouter.provserver.isaddressauthenabled", "false"); + .getProperty("org.onap.dmaap.datarouter.provserver.isaddressauthenabled", "false"); + + static String isCadiEnabled = (new DB()).getProperties() + .getProperty("org.onap.dmaap.datarouter.provserver.cadi.enabled", "false"); /** * Initialize data common to all the provisioning server servlets. @@ -277,7 +281,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { } } - int getIdFromPath(HttpServletRequest req) { + public static int getIdFromPath(HttpServletRequest req) { String path = req.getPathInfo(); if (path == null || path.length() < 2) { return -1; @@ -308,6 +312,36 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { return jo; } + /** + * This method encrypt/decrypt the key in the JSON passed by user request inside the authorisation header object in request before logging the JSON. + * + * @param jo- the JSON passed in http request. + * @param maskKey- the key to be masked in the JSON passed. + * @param action- whether to mask the key or unmask it in a JSON passed. + * @return the JSONObject, or null if the stream cannot be parsed. + */ + public static JSONObject maskJSON(JSONObject jo, String maskKey, boolean action) { + if (!jo.isNull("authorization")) { + JSONObject j2 = jo.getJSONObject("authorization"); + JSONArray ja = j2.getJSONArray("endpoint_ids"); + for (int i = 0; i < ja.length(); i++) { + if ((!ja.getJSONObject(i).isNull(maskKey))) { + String password = ja.getJSONObject(i).get(maskKey).toString(); + try { + if (action) { + ja.getJSONObject(i).put(maskKey, PasswordProcessor.encrypt(password)); + } else { + ja.getJSONObject(i).put(maskKey, PasswordProcessor.decrypt(password)); + } + } catch (JSONException | GeneralSecurityException e) { + intlogger.info("Error reading JSON while masking: " + e); + } + } + } + } + return jo; + } + /** * Check if the remote host is authorized to perform provisioning. Is the request secure? Is it coming from an * authorized IP address or network (configured via PROV_AUTH_ADDRESSES)? Does it have a valid client certificate @@ -324,7 +358,6 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { if (requireSecure && !request.isSecure()) { return "Request must be made over an HTTPS connection."; } - // Is remote IP authorized? String remote = request.getRemoteAddr(); try { @@ -337,12 +370,12 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { return "Unauthorized address: " + remote; } } catch (UnknownHostException e) { + intlogger.error("PROV0051 BaseServlet.isAuthorizedForProvisioning: ", e); return "Unauthorized address: " + remote; } - // Does remote have a valid certificate? if (requireCert) { - X509Certificate certs[] = (X509Certificate[]) request.getAttribute(CERT_ATTRIBUTE); + X509Certificate[] certs = (X509Certificate[]) request.getAttribute(CERT_ATTRIBUTE); if (certs == null || certs.length == 0) { return "Client certificate is missing."; } @@ -353,7 +386,6 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { return "No authorized certificate found."; } } - // No problems! return null; } @@ -365,7 +397,6 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { * @return true iff authorized */ boolean isAuthorizedForInternal(HttpServletRequest request) { - try { if (!Boolean.parseBoolean(isAddressAuthEnabled)) { return true; @@ -388,7 +419,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { return true; } } catch (UnknownHostException e) { - // ignore + intlogger.error("PROV0052 BaseServlet.isAuthorizedForInternal: ", e); } return false; } @@ -397,7 +428,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { * Check if an IP address matches a network address. * * @param ip the IP address - * @param s the network address; a bare IP address may be matched also + * @param s the network address; a bare IP address may be matched also * @return true if they intersect */ private static boolean addressMatchesNetwork(InetAddress ip, String s) { @@ -416,8 +447,8 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { } if (mlen > 0) { byte[] masks = { - (byte) 0x00, (byte) 0x80, (byte) 0xC0, (byte) 0xE0, - (byte) 0xF0, (byte) 0xF8, (byte) 0xFC, (byte) 0xFE + (byte) 0x00, (byte) 0x80, (byte) 0xC0, (byte) 0xE0, + (byte) 0xF0, (byte) 0xF8, (byte) 0xFC, (byte) 0xFE }; byte mask = masks[mlen % 8]; for (n = mlen / 8; n < b1.length; n++) { @@ -432,6 +463,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { } } } catch (UnknownHostException e) { + intlogger.error("PROV0053 BaseServlet.addressMatchesNetwork: ", e); return false; } return true; @@ -441,7 +473,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { * Something has changed in the provisioning data. Start the timers that will cause the pre-packaged JSON string to * be regenerated, and cause nodes and the other provisioning server to be notified. */ - public static void provisioningDataChanged() { + static void provisioningDataChanged() { long now = System.currentTimeMillis(); Poker p = Poker.getPoker(); p.setTimers(now + (pokeTimer1 * 1000L), now + (pokeTimer2 * 1000L)); @@ -450,7 +482,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { /** * Something in the parameters has changed, reload all parameters from the DB. */ - public static void provisioningParametersChanged() { + static void provisioningParametersChanged() { Map map = Parameters.getParameters(); requireSecure = getBoolean(map, Parameters.PROV_REQUIRE_SECURE); requireCert = getBoolean(map, Parameters.PROV_REQUIRE_CERT); @@ -461,15 +493,16 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { maxSubs = getInt(map, Parameters.PROV_MAXSUB_COUNT, DEFAULT_MAX_SUBS); pokeTimer1 = getInt(map, Parameters.PROV_POKETIMER1, DEFAULT_POKETIMER1); pokeTimer2 = getInt(map, Parameters.PROV_POKETIMER2, DEFAULT_POKETIMER2); + /** + * The domain used to generate a FQDN from the "bare" node names + */ provDomain = getString(map, Parameters.PROV_DOMAIN, DEFAULT_DOMAIN); provName = getString(map, Parameters.PROV_NAME, DEFAULT_PROVSRVR_NAME); activeProvName = getString(map, Parameters.PROV_ACTIVE_NAME, provName); - staticRoutingNodes = getString(map, Parameters.STATIC_ROUTING_NODES, - ""); //Adding new param for static Routing - Rally:US664862-1610 initialActivePod = getString(map, Parameters.ACTIVE_POD, ""); initialStandbyPod = getString(map, Parameters.STANDBY_POD, ""); staticRoutingNodes = getString(map, Parameters.STATIC_ROUTING_NODES, - ""); //Adding new param for static Routing - Rally:US664862-1610 + ""); //Adding new param for static Routing - Rally:US664862-1610 activeFeeds = Feed.countActiveFeeds(); activeSubs = Subscription.countActiveSubscriptions(); try { @@ -491,6 +524,9 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { } } + //[DATARTR-27] Poke all the DR nodes: assigning DR Nodes + drnodes = nodes.clone(); + //Reset Nodes arr after - removing static routing Nodes, Rally Userstory - US664862 . List filterNodes = new ArrayList<>(); for (String node : nodes) { @@ -498,7 +534,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { filterNodes.add(node); } } - nodes = filterNodes.toArray(new String[filterNodes.size()]); + nodes = filterNodes.toArray(new String[0]); nodeAddresses = na; NodeClass.setNodes(nodes); // update NODES table @@ -535,17 +571,11 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { private void loadMailProperties() { if (mailprops == null) { mailprops = new Properties(); - InputStream inStream = getClass().getClassLoader().getResourceAsStream(MAILCONFIG_FILE); - try { + try (InputStream inStream = getClass().getClassLoader().getResourceAsStream(MAILCONFIG_FILE)) { mailprops.load(inStream); } catch (IOException e) { intlogger.fatal("PROV9003 Opening properties: " + e.getMessage()); System.exit(1); - } finally { - try { - inStream.close(); - } catch (IOException e) { - } } } } @@ -602,18 +632,16 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { msg.addRecipients(Message.RecipientType.TO, addressTo); msg.setSubject(mailprops.get("com.att.dmaap.datarouter.mail.subject").toString()); htmlPart.setContent(mailprops.get("com.att.dmaap.datarouter.mail.body").toString() - .replace("[SERVER]", InetAddress.getLocalHost().getHostName()), "text/html"); + .replace("[SERVER]", InetAddress.getLocalHost().getHostName()), "text/html"); mp.addBodyPart(htmlPart); msg.setContent(mp); System.out.println(mailprops.get("com.att.dmaap.datarouter.mail.body").toString() - .replace("[SERVER]", InetAddress.getLocalHost().getHostName())); + .replace("[SERVER]", InetAddress.getLocalHost().getHostName())); Transport.send(msg); intlogger.info("HTTPS relaxation mail is sent to - : " + email); - } catch (AddressException e) { - intlogger.error("Invalid email address, unable to send https relaxation mail to - : " + email); } catch (MessagingException e) { intlogger.error("Invalid email address, unable to send https relaxation mail to - : " + email); } @@ -636,6 +664,16 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { return nodes; } + /** + * [DATARTR-27] Poke all the DR nodes + * Get an array of all node names in the DR network. + * + * @return an array of Strings + */ + public static String[] getDRNodes() { + return drnodes; + } + /** * Get an array of all node InetAddresses in the DR network. * @@ -981,7 +1019,7 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { setMDC(req, "X-InvocationID", "InvocationId"); } - void setMDC(HttpServletRequest req, String headerName, String keyName) { + private void setMDC(HttpServletRequest req, String headerName, String keyName) { String mdcId = req.getHeader(headerName); if (StringUtils.isBlank(mdcId)) { mdcId = UUID.randomUUID().toString(); @@ -1004,4 +1042,95 @@ public class BaseServlet extends HttpServlet implements ProvDataProvider { } } + + /* + * AAF changes: TDP EPIC US# 307413 + * @Method - getFeedPermission - Forming permission string for feed part to check AAF access in CADI Framework + * @Params - aafInstance Passing aafInstance as it's used in permission string + * @Params - userAction Passing CONST values to set different actions in permission string + */ + String getFeedPermission(String aafInstance, String userAction) { + try { + Properties props = (new DB()).getProperties(); + String type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED); + String action; + switch (userAction) { + case CREATE_PERMISSION: + action = CREATE_PERMISSION; + break; + case EDIT_PERMISSION: + action = EDIT_PERMISSION; + break; + case DELETE_PERMISSION: + action = DELETE_PERMISSION; + break; + case PUBLISH_PERMISSION: + action = PUBLISH_PERMISSION; + break; + case SUSPEND_PERMISSION: + action = SUSPEND_PERMISSION; + break; + case RESTORE_PERMISSION: + action = RESTORE_PERMISSION; + break; + default: + action = "*"; + } + if (aafInstance == null || aafInstance.equals("")) { + aafInstance = props.getProperty(AAF_INSTANCE, "org.onap.dmaap-dr.NoInstanceDefined"); + } + return type + "|" + aafInstance + "|" + action; + } catch (Exception e) { + intlogger.error("PROV7005 BaseServlet.getFeedPermission: ", e); + } + return null; + } + + /* + * AAF changes: TDP EPIC US# 307413 + * @Method - getSubscriberPermission - Forming permission string for subscription part to check AAF access in CADI Framework + * @Params - aafInstance Passing aafInstance as it's used in permission string + * @Params - userAction Passing CONST values to set different actions in permission string + */ + String getSubscriberPermission(String aafInstance, String userAction) { + try { + Properties props = (new DB()).getProperties(); + String type = props.getProperty(AAF_CADI_SUB_TYPE, AAF_CADI_SUB); + String action; + switch (userAction) { + case SUBSCRIBE_PERMISSION: + action = SUBSCRIBE_PERMISSION; + type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED); + break; + case EDIT_PERMISSION: + action = EDIT_PERMISSION; + break; + case DELETE_PERMISSION: + action = DELETE_PERMISSION; + break; + case RESTORE_PERMISSION: + action = RESTORE_PERMISSION; + break; + case SUSPEND_PERMISSION: + action = SUSPEND_PERMISSION; + break; + case PUBLISH_PERMISSION: + action = PUBLISH_PERMISSION; + break; + case APPROVE_SUB_PERMISSION: + action = APPROVE_SUB_PERMISSION; + type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED); + break; + default: + action = "*"; + } + if (aafInstance == null || aafInstance.equals("")) { + aafInstance = props.getProperty(AAF_INSTANCE, "org.onap.dmaap-dr.NoInstanceDefined"); + } + return type + "|" + aafInstance + "|" + action; + } catch (Exception e) { + intlogger.error("PROV7005 BaseServlet.getSubscriberPermission: ", e); + } + return null; + } } diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServlet.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServlet.java index 895eba08..9bc91620 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServlet.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServlet.java @@ -24,13 +24,8 @@ package org.onap.dmaap.datarouter.provisioning; -import java.io.IOException; -import java.io.InvalidObjectException; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; import org.json.JSONObject; import org.onap.dmaap.datarouter.authz.AuthorizationResponse; import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord; @@ -38,8 +33,11 @@ import org.onap.dmaap.datarouter.provisioning.beans.Feed; import org.onap.dmaap.datarouter.provisioning.eelf.EelfMsgs; import org.onap.dmaap.datarouter.provisioning.utils.JSONUtilities; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.util.List; import static org.onap.dmaap.datarouter.provisioning.utils.HttpServletUtils.sendResponseError; @@ -55,7 +53,7 @@ public class DRFeedsServlet extends ProxyServlet { //Adding EELF Logger Rally:US664892 private static EELFLogger eelflogger = EELFManager.getInstance() - .getLogger(DRFeedsServlet.class); + .getLogger(DRFeedsServlet.class); /** * DELETE on the <drFeedsURL> -- not supported. @@ -109,8 +107,8 @@ public class DRFeedsServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); return; } - String path = req - .getRequestURI(); // Note: I think this should be getPathInfo(), but that doesn't work (Jetty bug?) + // Note: I think this should be getPathInfo(), but that doesn't work (Jetty bug?) + String path = req.getRequestURI(); if (path != null && !path.equals("/")) { message = "Bad URL."; elr.setMessage(message); @@ -236,8 +234,8 @@ public class DRFeedsServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); return; } - String path = req - .getRequestURI(); // Note: I think this should be getPathInfo(), but that doesn't work (Jetty bug?) + // Note: I think this should be getPathInfo(), but that doesn't work (Jetty bug?) + String path = req.getRequestURI(); if (path != null && !path.equals("/")) { message = "Bad URL."; elr.setMessage(message); @@ -257,16 +255,6 @@ public class DRFeedsServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (!aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; - } JSONObject jo = getJSONfromInput(req); if (jo == null) { message = "Badly formed JSON"; @@ -288,7 +276,7 @@ public class DRFeedsServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_CONFLICT, message, eventlogger); return; } - Feed feed = null; + Feed feed; try { feed = new Feed(jo); } catch (InvalidObjectException e) { @@ -299,6 +287,60 @@ public class DRFeedsServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); return; } + + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - No legacy user check as all new users will be AAF users + */ + String aafInstance = feed.getAafInstance(); + if (Boolean.parseBoolean(isCadiEnabled)) { + if ((aafInstance == null || aafInstance.equals("") || (aafInstance.equalsIgnoreCase("legacy")) && req.getHeader(EXCLUDE_AAF_HEADER).equalsIgnoreCase("true"))) { + // Check with the Authorizer + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + if (req.getHeader(EXCLUDE_AAF_HEADER).equalsIgnoreCase("true")) { + message = "DRFeedsServlet.doPost() -Invalid request exclude_AAF should not be true if passing AAF_Instance value= " + aafInstance; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + String permission = getFeedPermission(aafInstance, BaseServlet.CREATE_PERMISSION); + eventlogger.info("DRFeedsServlet.doPost().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } + } else { + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } + /* + * END - AAF changes + */ + feed.setPublisher(bhdr); // set from X-DMAAP-DR-ON-BEHALF-OF header // Check if this feed already exists diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/FeedServlet.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/FeedServlet.java index e64f2c69..4ab3ef4c 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/FeedServlet.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/FeedServlet.java @@ -107,17 +107,37 @@ public class FeedServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (! aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - check on permissions based on Legacy/AAF users to allow to delete/remove feed + */ + String aafInstance = feed.getAafInstance(); + if (aafInstance == null || aafInstance.equals("") || aafInstance.equalsIgnoreCase("legacy")) { + AuthorizationResponse aresp = authz.decide(req); + if (! aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + String permission = getFeedPermission(aafInstance, BaseServlet.DELETE_PERMISSION); + eventlogger.info("FeedServlet.doDelete().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } } - + /* + * END - AAF changes + */ // Delete FEED table entry (set DELETED flag) feed.setDeleted(true); if (doUpdate(feed)) { @@ -286,7 +306,7 @@ public class FeedServlet extends ProxyServlet { } if (intlogger.isDebugEnabled()) intlogger.debug(jo.toString()); - Feed feed = null; + Feed feed; try { feed = new Feed(jo); } catch (InvalidObjectException e) { @@ -317,24 +337,50 @@ public class FeedServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); return; } - if (!oldFeed.getVersion().equals(feed.getVersion())) { - message = "The version of the feed may not be updated."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_BAD_REQUEST); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); - return; + // US DSCDR-19 for DCAE if version is not null, version can't be changed + if ((oldFeed.getVersion() != null) && (feed.getVersion() != null)) { + if (!oldFeed.getVersion().equals(feed.getVersion())) { + message = "The version of the feed may not be updated."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_BAD_REQUEST); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); + return; + } } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (! aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; + + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - check on permissions based on Legacy/AAF users to allow feed edit/update/modify + */ + String aafInstance = feed.getAafInstance(); + if (aafInstance == null || aafInstance.equals("") || aafInstance.equalsIgnoreCase("legacy")) { + // Check with the Authorizer + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + String permission = getFeedPermission(aafInstance, BaseServlet.EDIT_PERMISSION); + eventlogger.info("FeedServlet.doPut().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } } + /* + * END - AAF changes + */ // Update FEEDS table entries if (doUpdate(feed)) { diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/Main.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/Main.java index 651d7316..1bd3cbfa 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/Main.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/Main.java @@ -24,34 +24,28 @@ package org.onap.dmaap.datarouter.provisioning; -import java.security.*; -import java.util.*; - import org.apache.log4j.Logger; import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.NCSARequestLog; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.RequestLogHandler; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.onap.dmaap.datarouter.provisioning.utils.DB; -import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader; -import org.onap.dmaap.datarouter.provisioning.utils.PurgeLogDirTask; -import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter; +import org.onap.aaf.cadi.PropAccess; +import org.onap.dmaap.datarouter.provisioning.utils.*; import javax.servlet.DispatcherType; +import java.io.IOException; +import java.io.InputStream; +import java.security.Security; +import java.util.EnumSet; +import java.util.Properties; +import java.util.Timer; /** *

@@ -87,18 +81,31 @@ public class Main { /** * The truststore to use if none is specified */ - public static final String DEFAULT_TRUSTSTORE = "/opt/java/jdk/jdk180/jre/lib/security/cacerts"; - public static final String KEYSTORE_TYPE_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.type"; - public static final String KEYSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.path"; - public static final String KEYSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.password"; - public static final String TRUSTSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.path"; - public static final String TRUSTSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.password"; + static final String DEFAULT_TRUSTSTORE = "/opt/java/jdk/jdk180/jre/lib/security/cacerts"; + static final String KEYSTORE_TYPE_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.type"; + static final String KEYSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.path"; + static final String KEYSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.keystore.password"; + static final String TRUSTSTORE_PATH_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.path"; + static final String TRUSTSTORE_PASS_PROPERTY = "org.onap.dmaap.datarouter.provserver.truststore.password"; + public static final Logger intlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal"); /** * The one and only {@link Server} instance in this JVM */ private static Server server; + class Inner { + InputStream getCadiProps() { + InputStream in = null; + try { + in = getClass().getClassLoader().getResourceAsStream("drProvCadi.properties"); + } catch (Exception e) { + intlogger.error("Exception in Main.getCadiProps() method ", e); + } + return in; + } + } + /** * Starts the Data Router Provisioning server. * @@ -106,29 +113,19 @@ public class Main { * @throws Exception if Jetty has a problem starting */ public static void main(String[] args) throws Exception { - Security.setProperty("networkaddress.cache.ttl", "4"); - Logger logger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal"); + // Get prov properties + Properties provProperties = (new DB()).getProperties(); // Check DB is accessible and contains the expected tables if (!checkDatabase()) { System.exit(1); } - logger.info("PROV0000 **** AT&T Data Router Provisioning Server starting...."); + intlogger.info("PROV0000 **** AT&T Data Router Provisioning Server starting...."); - // Get properties - Properties p = (new DB()).getProperties(); - int httpPort = Integer.parseInt(p.getProperty("org.onap.dmaap.datarouter.provserver.http.port", "8080")); - int httpsPort = Integer.parseInt(p.getProperty("org.onap.dmaap.datarouter.provserver.https.port", "8443")); - - // HTTP configuration - HttpConfiguration httpConfiguration = new HttpConfiguration(); - httpConfiguration.setSecureScheme("https"); - httpConfiguration.setSecurePort(httpsPort); - httpConfiguration.setOutputBufferSize(32768); - httpConfiguration.setRequestHeaderSize(2048); - httpConfiguration.setSendServerVersion(true); - httpConfiguration.setSendDateHeader(false); + Security.setProperty("networkaddress.cache.ttl", "4"); + int httpPort = Integer.parseInt(provProperties.getProperty("org.onap.dmaap.datarouter.provserver.http.port", "8080")); + int httpsPort = Integer.parseInt(provProperties.getProperty("org.onap.dmaap.datarouter.provserver.https.port", "8443")); // Server's thread pool QueuedThreadPool queuedThreadPool = new QueuedThreadPool(); @@ -138,121 +135,155 @@ public class Main { // The server itself server = new Server(queuedThreadPool); + server.setStopAtShutdown(true); + server.setStopTimeout(5000); + server.setDumpAfterStart(false); + server.setDumpBeforeStop(false); + + // Request log configuration + NCSARequestLog ncsaRequestLog = new NCSARequestLog(); + ncsaRequestLog.setFilename(provProperties.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir") + "/request.log.yyyy_mm_dd"); + ncsaRequestLog.setFilenameDateFormat("yyyyMMdd"); + ncsaRequestLog.setRetainDays(90); + ncsaRequestLog.setAppend(true); + ncsaRequestLog.setExtended(false); + ncsaRequestLog.setLogCookies(false); + ncsaRequestLog.setLogTimeZone("GMT"); + + RequestLogHandler requestLogHandler = new RequestLogHandler(); + requestLogHandler.setRequestLog(ncsaRequestLog); + server.setRequestLog(ncsaRequestLog); + + // HTTP configuration + HttpConfiguration httpConfiguration = new HttpConfiguration(); + httpConfiguration.setSecureScheme("https"); + httpConfiguration.setSecurePort(httpsPort); + httpConfiguration.setOutputBufferSize(32768); + httpConfiguration.setRequestHeaderSize(8192); + httpConfiguration.setResponseHeaderSize(8192); + httpConfiguration.setSendServerVersion(true); + httpConfiguration.setSendDateHeader(false); - // HTTP connector - HandlerCollection hc; - try (ServerConnector httpServerConnector = new ServerConnector(server, - new HttpConnectionFactory(httpConfiguration))) { + //HTTP Connector + HandlerCollection handlerCollection; + try (ServerConnector httpServerConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration))) { httpServerConnector.setPort(httpPort); httpServerConnector.setAcceptQueueSize(2); httpServerConnector.setIdleTimeout(300000); + // SSL Context + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStoreType(provProperties.getProperty(KEYSTORE_TYPE_PROPERTY, "jks")); + sslContextFactory.setKeyStorePath(provProperties.getProperty(KEYSTORE_PATH_PROPERTY)); + sslContextFactory.setKeyStorePassword(provProperties.getProperty(KEYSTORE_PASS_PROPERTY)); + sslContextFactory.setKeyManagerPassword(provProperties.getProperty("org.onap.dmaap.datarouter.provserver.keymanager.password")); + + String ts = provProperties.getProperty(TRUSTSTORE_PATH_PROPERTY); + if (ts != null && ts.length() > 0) { + intlogger.info("@@ TS -> " + ts); + sslContextFactory.setTrustStorePath(ts); + sslContextFactory.setTrustStorePassword(provProperties.getProperty(TRUSTSTORE_PASS_PROPERTY)); + } else { + sslContextFactory.setTrustStorePath(DEFAULT_TRUSTSTORE); + sslContextFactory.setTrustStorePassword("changeit"); + } + + sslContextFactory.setWantClientAuth(true); + sslContextFactory.setExcludeCipherSuites( + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" + ); + sslContextFactory.addExcludeProtocols("SSLv3"); + sslContextFactory.setIncludeProtocols(provProperties.getProperty( + "org.onap.dmaap.datarouter.provserver.https.include.protocols", "TLSv1.1|TLSv1.2").trim().split("\\|")); + + intlogger.info("Not supported protocols prov server:-" + String.join(",", sslContextFactory.getExcludeProtocols())); + intlogger.info("Supported protocols prov server:-" + String.join(",", sslContextFactory.getIncludeProtocols())); + intlogger.info("Not supported ciphers prov server:-" + String.join(",", sslContextFactory.getExcludeCipherSuites())); + intlogger.info("Supported ciphers prov server:-" + String.join(",", sslContextFactory.getIncludeCipherSuites())); + // HTTPS configuration HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration); httpsConfiguration.setRequestHeaderSize(8192); // HTTPS connector - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath(p.getProperty(KEYSTORE_PATH_PROPERTY)); - sslContextFactory.setKeyStorePassword(p.getProperty(KEYSTORE_PASS_PROPERTY)); - sslContextFactory - .setKeyManagerPassword(p.getProperty("org.onap.dmaap.datarouter.provserver.keymanager.password")); - // SSL stuff - /* Skip SSLv3 Fixes */ - sslContextFactory.addExcludeProtocols("SSLv3"); - logger.info("Excluded protocols prov-" + Arrays.toString(sslContextFactory.getExcludeProtocols())); - /* End of SSLv3 Fixes */ - try (ServerConnector httpsServerConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(httpsConfiguration))) { + httpsServerConnector.setPort(httpsPort); httpsServerConnector.setIdleTimeout(30000); httpsServerConnector.setAcceptQueueSize(2); - sslContextFactory.setKeyStoreType(p.getProperty(KEYSTORE_TYPE_PROPERTY, "jks")); - sslContextFactory.setKeyStorePath(p.getProperty(KEYSTORE_PATH_PROPERTY)); - sslContextFactory.setKeyStorePassword(p.getProperty(KEYSTORE_PASS_PROPERTY)); - sslContextFactory - .setKeyManagerPassword(p.getProperty("org.onap.dmaap.datarouter.provserver.keymanager.password")); - - String ts = p.getProperty(TRUSTSTORE_PATH_PROPERTY); - if (ts != null && ts.length() > 0) { - logger.info("@@ TS -> " + ts); - sslContextFactory.setTrustStorePath(ts); - sslContextFactory.setTrustStorePassword(p.getProperty(TRUSTSTORE_PASS_PROPERTY)); - } else { - sslContextFactory.setTrustStorePath(DEFAULT_TRUSTSTORE); - sslContextFactory.setTrustStorePassword("changeit"); + // Servlet and Filter configuration + ServletContextHandler servletContextHandler = new ServletContextHandler(0); + servletContextHandler.setContextPath("/"); + servletContextHandler.addServlet(new ServletHolder(new FeedServlet()), "/feed/*"); + servletContextHandler.addServlet(new ServletHolder(new FeedLogServlet()), "/feedlog/*"); + servletContextHandler.addServlet(new ServletHolder(new PublishServlet()), "/publish/*"); + servletContextHandler.addServlet(new ServletHolder(new SubscribeServlet()), "/subscribe/*"); + servletContextHandler.addServlet(new ServletHolder(new StatisticsServlet()), "/statistics/*"); + servletContextHandler.addServlet(new ServletHolder(new SubLogServlet()), "/sublog/*"); + servletContextHandler.addServlet(new ServletHolder(new GroupServlet()), "/group/*"); + servletContextHandler.addServlet(new ServletHolder(new SubscriptionServlet()), "/subs/*"); + servletContextHandler.addServlet(new ServletHolder(new InternalServlet()), "/internal/*"); + servletContextHandler.addServlet(new ServletHolder(new RouteServlet()), "/internal/route/*"); + servletContextHandler.addServlet(new ServletHolder(new DRFeedsServlet()), "/"); + servletContextHandler.addFilter(new FilterHolder(new ThrottleFilter()), "/publish/*", EnumSet.of(DispatcherType.REQUEST)); + + //CADI Filter activation check + if (Boolean.parseBoolean(provProperties.getProperty("org.onap.dmaap.datarouter.provserver.cadi.enabled", "false"))) { + //Get cadi properties + Properties cadiProperties = null; + try { + intlogger.info("PROV0001 Prov - Loading CADI properties"); + cadiProperties = new Properties(); + Inner obj = new Main().new Inner(); + InputStream in = obj.getCadiProps(); + cadiProperties.load(in); + } catch (IOException e1) { + intlogger.error("PROV0001 Exception loading CADI properties", e1); + } + cadiProperties.setProperty("aaf_locate_url", provProperties.getProperty("org.onap.dmaap.datarouter.provserver.cadi.aaf.url", "https://aaf-onap-test.osaaf.org:8095")); + intlogger.info("PROV0001 aaf_url set to - " + cadiProperties.getProperty("aaf_url")); + + PropAccess access = new PropAccess(cadiProperties); + servletContextHandler.addFilter(new FilterHolder(new DRProvCadiFilter(true, access)), "/*", EnumSet.of(DispatcherType.REQUEST)); } - sslContextFactory.setWantClientAuth(true); - // Servlet and Filter configuration - ServletContextHandler ctxt = new ServletContextHandler(0); - ctxt.setContextPath("/"); - ctxt.addServlet(new ServletHolder(new FeedServlet()), "/feed/*"); - ctxt.addServlet(new ServletHolder(new FeedLogServlet()), "/feedlog/*"); - ctxt.addServlet(new ServletHolder(new PublishServlet()), "/publish/*"); - ctxt.addServlet(new ServletHolder(new SubscribeServlet()), "/subscribe/*"); - ctxt.addServlet(new ServletHolder(new StatisticsServlet()), "/statistics/*"); - ctxt.addServlet(new ServletHolder(new SubLogServlet()), "/sublog/*"); - ctxt.addServlet(new ServletHolder(new GroupServlet()), - "/group/*"); //Provision groups - Rally US708115 -1610 - ctxt.addServlet(new ServletHolder(new SubscriptionServlet()), "/subs/*"); - ctxt.addServlet(new ServletHolder(new InternalServlet()), "/internal/*"); - ctxt.addServlet(new ServletHolder(new RouteServlet()), "/internal/route/*"); - ctxt.addServlet(new ServletHolder(new DRFeedsServlet()), "/"); - ctxt.addFilter(new FilterHolder(new ThrottleFilter()), "/publish/*", EnumSet.of(DispatcherType.REQUEST)); - - ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.addHandler(ctxt); - - // Request log configuration - NCSARequestLog nrl = new NCSARequestLog(); - nrl.setFilename( - p.getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir") + "/request.log.yyyy_mm_dd"); - nrl.setFilenameDateFormat("yyyyMMdd"); - nrl.setRetainDays(90); - nrl.setAppend(true); - nrl.setExtended(false); - nrl.setLogCookies(false); - nrl.setLogTimeZone("GMT"); - - RequestLogHandler reqlog = new RequestLogHandler(); - reqlog.setRequestLog(nrl); + ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection(); + contextHandlerCollection.addHandler(servletContextHandler); // Server's Handler collection - hc = new HandlerCollection(); - hc.setHandlers(new Handler[]{contexts, new DefaultHandler()}); - hc.addHandler(reqlog); - - // Daemon to clean up the log directory on a daily basis - Timer rolex = new Timer(); - rolex.scheduleAtFixedRate(new PurgeLogDirTask(), 0, 86400000L); // run once per day - - // Start LogfileLoader - LogfileLoader.getLoader(); - - try (ServerConnector serverConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(httpsConfiguration))) { - serverConnector.setPort(httpsPort); - serverConnector.setIdleTimeout(500000); - } + handlerCollection = new HandlerCollection(); + handlerCollection.setHandlers(new Handler[]{contextHandlerCollection, new DefaultHandler()}); + handlerCollection.addHandler(requestLogHandler); server.setConnectors(new Connector[]{httpServerConnector, httpsServerConnector}); } } - server.setHandler(hc); - server.setStopAtShutdown(true); - server.setStopTimeout(5000); + server.setHandler(handlerCollection); - server.setDumpAfterStart(false); - server.setDumpBeforeStop(false); + // Daemon to clean up the log directory on a daily basis + Timer rolex = new Timer(); + rolex.scheduleAtFixedRate(new PurgeLogDirTask(), 0, 86400000L); // run once per day + + // Start LogfileLoader + LogfileLoader.getLoader(); - server.start(); + try { + server.start(); + intlogger.info("Prov Server started-" + server.getState()); + } catch (Exception e) { + intlogger.info("Jetty failed to start. Reporting will we unavailable", e); + } server.join(); - logger.info("PROV0001 **** AT&T Data Router Provisioning Server halted."); + intlogger.info("PROV0001 **** AT&T Data Router Provisioning Server halted."); } private static boolean checkDatabase() { @@ -270,7 +301,7 @@ public class Main { Thread.sleep(5000L); System.exit(0); } catch (Exception e) { - // ignore + intlogger.error("Exception in Main.shutdown() method " + e); } }); } diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscribeServlet.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscribeServlet.java index 2127f004..35ce062d 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscribeServlet.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscribeServlet.java @@ -128,17 +128,6 @@ public class SubscribeServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (!aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; - } - // Display a list of URLs Collection list = Subscription.getSubscriptionUrlList(feedid); String t = JSONUtilities.createJSONArray(list); @@ -228,17 +217,6 @@ public class SubscribeServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (!aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; - } - // check content type is SUB_CONTENT_TYPE, version 1.0 ContentHeader ch = getContentHeader(req); String ver = ch.getAttribute("version"); @@ -272,7 +250,7 @@ public class SubscribeServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_CONFLICT, message, eventlogger); return; } - Subscription sub = null; + Subscription sub; try { sub = new Subscription(jo); } catch (InvalidObjectException e) { @@ -286,13 +264,70 @@ public class SubscribeServlet extends ProxyServlet { } sub.setFeedid(feedid); sub.setSubscriber(bhdr); // set from X-DMAAP-DR-ON-BEHALF-OF header + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - check on permissions based on Legacy/AAF users to allow to create/add subscription + */ + String feedAafInstance = feed.getAafInstance(); + String subAafInstance = sub.getAafInstance(); + boolean subAafLegacyEmptyOrNull = (subAafInstance == null || subAafInstance.equals("") || subAafInstance.equalsIgnoreCase("legacy")); + // This extra check added to verify AAF feed with AAF subscriber having empty aaf instance check + if (feedAafInstance == null || feedAafInstance.equals("") || feedAafInstance.equalsIgnoreCase("legacy")) { + if (subAafLegacyEmptyOrNull) { + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access"; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + //If Legacy Feed and AAF instance provided in Subscriber JSON + message = "AAF Subscriber can not be added to legacy Feed- " + feedid; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + //New AAF Requirement to add legacy subscriber to AAF Feed + if (subAafLegacyEmptyOrNull) { + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + //New AAF Requirement to add subscriber by publisher on publisher approval only + String permission = getSubscriberPermission(subAafInstance, BaseServlet.APPROVE_SUB_PERMISSION); + eventlogger.info("SubscribeServlet.doPost().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } + } + /* + * END - AAF changes + */ // Check if this subscription already exists; not an error (yet), just warn Subscription sub2 = Subscription.getSubscriptionMatching(sub); if (sub2 != null) { intlogger.warn( - "PROV0011 Creating a duplicate subscription: new subid=" + sub.getSubid() + ", old subid=" + sub2 - .getSubid()); + "PROV0011 Creating a duplicate subscription: new subid=" + sub.getSubid() + ", old subid=" + sub2.getSubid()); } // Create SUBSCRIPTIONS table entries diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServlet.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServlet.java index ec4d33a0..d7c46570 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServlet.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServlet.java @@ -58,7 +58,7 @@ import static org.onap.dmaap.datarouter.provisioning.utils.HttpServletUtils.send @SuppressWarnings("serial") public class SubscriptionServlet extends ProxyServlet { - public static final String SUBCNTRL_CONTENT_TYPE = "application/vnd.dmaap-dr.subscription-control"; + private static final String SUBCNTRL_CONTENT_TYPE = "application/vnd.dmaap-dr.subscription-control"; //Adding EELF Logger Rally:US664892 private static EELFLogger eelflogger = EELFManager.getInstance() .getLogger(SubscriptionServlet.class); @@ -113,17 +113,37 @@ public class SubscriptionServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (!aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - check on permissions based on Legacy/AAF users to allow to delete/remove subscription + */ + String aafInstance = sub.getAafInstance(); + if (aafInstance == null || aafInstance.equals("") || aafInstance.equalsIgnoreCase("legacy")) { + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + String permission = getSubscriberPermission(aafInstance, BaseServlet.DELETE_PERMISSION); + eventlogger.info("SubscriptionServlet.doDelete().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } } - + /* + * END - AAF changes + */ // Delete Subscription if (doDelete(sub)) { activeSubs--; @@ -270,16 +290,6 @@ public class SubscriptionServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger); return; } - // Check with the Authorizer - AuthorizationResponse aresp = authz.decide(req); - if (!aresp.isAuthorized()) { - message = "Policy Engine disallows access."; - elr.setMessage(message); - elr.setResult(HttpServletResponse.SC_FORBIDDEN); - eventlogger.info(elr); - sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); - return; - } // check content type is SUB_CONTENT_TYPE, version 1.0 ContentHeader ch = getContentHeader(req); String ver = ch.getAttribute("version"); @@ -314,6 +324,38 @@ public class SubscriptionServlet extends ProxyServlet { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger); return; } + + /* + * START - AAF changes + * TDP EPIC US# 307413 + * CADI code - check on permissions based on Legacy/AAF users to allow to delete/remove subscription + */ + String aafInstance = sub.getAafInstance(); + if (aafInstance == null || aafInstance.equals("") || aafInstance.equalsIgnoreCase("legacy")) { + AuthorizationResponse aresp = authz.decide(req); + if (!aresp.isAuthorized()) { + message = "Policy Engine disallows access."; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } else { + String permission = getSubscriberPermission(aafInstance, BaseServlet.EDIT_PERMISSION); + eventlogger.info("SubscriptionServlet.doDelete().. Permission String - " + permission); + if (!req.isUserInRole(permission)) { + message = "AAF disallows access to permission - " + permission; + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_FORBIDDEN); + eventlogger.info(elr); + sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger); + return; + } + } + /* + * END - AAF changes + */ sub.setSubid(oldsub.getSubid()); sub.setFeedid(oldsub.getFeedid()); sub.setSubscriber(bhdr); // set from X-DMAAP-DR-ON-BEHALF-OF header @@ -373,13 +415,6 @@ public class SubscriptionServlet extends ProxyServlet { */ @Override public void doPost(HttpServletRequest req, HttpServletResponse resp) { -// OLD pre-3.0 code -// String message = "POST not allowed for the subscriptionURL."; -// EventLogRecord elr = new EventLogRecord(req); -// elr.setMessage(message); -// elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED); -// eventlogger.info(elr); -// resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, message); setIpFqdnRequestIDandInvocationIDForEelf("doPost", req); eelflogger.info(EelfMsgs.ENTRY); diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Feed.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Feed.java index a2076b04..502dbbd1 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Feed.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Feed.java @@ -24,17 +24,21 @@ package org.onap.dmaap.datarouter.provisioning.beans; +import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.onap.dmaap.datarouter.provisioning.utils.DB; import org.onap.dmaap.datarouter.provisioning.utils.JSONUtilities; +import org.onap.dmaap.datarouter.provisioning.utils.PasswordProcessor; import org.onap.dmaap.datarouter.provisioning.utils.URLUtilities; import java.io.InvalidObjectException; +import java.security.GeneralSecurityException; import java.sql.*; -import java.util.*; import java.util.Date; +import java.util.*; /** * The representation of a Feed. Feeds can be retrieved from the DB, or stored/updated in the DB. @@ -59,6 +63,7 @@ public class Feed extends Syncable { private boolean suspended; private Date last_mod; private Date created_date; + private String aaf_instance; /** * Check if a feed ID is valid. @@ -82,7 +87,7 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.error("SQLException " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0024 Feed.isFeedValid: ", e); } return count != 0; } @@ -132,8 +137,8 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.info("countActiveFeeds: " + e.getMessage()); - intlogger.error("SQLException " + e.getMessage()); + intlogger.info("PROV0025 Feed.countActiveFeeds: " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0025 Feed.countActiveFeeds: ", e); } return count; } @@ -153,8 +158,8 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.info("getMaxFeedID: " + e.getMessage()); - intlogger.error("SQLException " + e.getMessage()); + intlogger.info("PROV0026 Feed.getMaxFeedID: "+e.getMessage()); + intlogger.log(Level.WARN, "PROV0026 Feed.getMaxFeedID: ", e); } return max; } @@ -200,7 +205,7 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.error("SQLException " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0027 Feed.getAllFeeds: ", e); } return map.values(); } @@ -234,7 +239,7 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.error("SQLException " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0028 Feed.getFilteredFeedUrlList: ", e); } return list; } @@ -271,7 +276,7 @@ public class Feed extends Syncable { } db.release(conn); } catch (SQLException e) { - intlogger.error("SQLException " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0029 Feed.getFeedBySQL: ", e); } return feed; } @@ -294,6 +299,7 @@ public class Feed extends Syncable { this.suspended = false; this.last_mod = new Date(); this.created_date = new Date(); + this.aaf_instance = ""; } public Feed(ResultSet rs) throws SQLException { @@ -315,6 +321,7 @@ public class Feed extends Syncable { this.suspended = rs.getBoolean("SUSPENDED"); this.last_mod = rs.getDate("LAST_MOD"); this.created_date = rs.getTimestamp("CREATED_DATE"); + this.aaf_instance = rs.getString("AAF_INSTANCE"); } public Feed(JSONObject jo) throws InvalidObjectException { @@ -322,41 +329,49 @@ public class Feed extends Syncable { try { // The JSONObject is assumed to contain a vnd.dmaap-dr.feed representation this.feedid = jo.optInt("feedid", -1); - this.groupid = jo.optInt("groupid"); //New field is added - Groups feature Rally:US708115 - 1610 + this.groupid = jo.optInt("groupid"); this.name = jo.getString("name"); + this.aaf_instance = jo.optString("aaf_instance", "legacy"); + if(!(aaf_instance.equalsIgnoreCase("legacy"))){ + if (aaf_instance.length() > 255){ + throw new InvalidObjectException("aaf_instance field is too long"); + } + } if (name.length() > 255) throw new InvalidObjectException("name field is too long"); - this.version = jo.getString("version"); - if (version.length() > 20) + try { + this.version = jo.getString("version"); + } catch (JSONException e) { + this.version = null; + } + if(version != null && version.length() > 20) throw new InvalidObjectException("version field is too long"); this.description = jo.optString("description"); - this.business_description = jo.optString("business_description"); // New field is added - Groups feature Rally:US708102 - 1610 + this.business_description = jo.optString("business_description"); if (description.length() > 1000) throw new InvalidObjectException("technical description field is too long"); - - if (business_description.length() > 1000) // New field is added - Groups feature Rally:US708102 - 1610 + if (business_description.length() > 1000) throw new InvalidObjectException("business description field is too long"); - this.authorization = new FeedAuthorization(); JSONObject jauth = jo.getJSONObject("authorization"); this.authorization.setClassification(jauth.getString("classification")); if (this.authorization.getClassification().length() > 32) throw new InvalidObjectException("classification field is too long"); - JSONArray ja = jauth.getJSONArray("endpoint_ids"); - for (int i = 0; i < ja.length(); i++) { - JSONObject id = ja.getJSONObject(i); + JSONArray endPointIds = jauth.getJSONArray("endpoint_ids"); + for (int i = 0; i < endPointIds.length(); i++) { + JSONObject id = endPointIds.getJSONObject(i); FeedEndpointID fid = new FeedEndpointID(id.getString("id"), id.getString("password")); - if (fid.getId().length() > 20) + if (fid.getId().length() > 60) throw new InvalidObjectException("id field is too long (" + fid.getId() + ")"); if (fid.getPassword().length() > 32) - throw new InvalidObjectException("password field is too long (" + fid.getPassword() + ")"); + throw new InvalidObjectException("password field is too long ("+ fid.getPassword()+")"); //Fortify scan fixes - Privacy Violation this.authorization.getEndpoint_ids().add(fid); } if (this.authorization.getEndpoint_ids().size() < 1) throw new InvalidObjectException("need to specify at least one endpoint_id"); - ja = jauth.getJSONArray("endpoint_addrs"); - for (int i = 0; i < ja.length(); i++) { - String addr = ja.getString(i); + endPointIds = jauth.getJSONArray("endpoint_addrs"); + for (int i = 0; i < endPointIds.length(); i++) { + String addr = endPointIds.getString(i); if (!JSONUtilities.validIPAddrOrSubnet(addr)) throw new InvalidObjectException("bad IP addr or subnet mask: " + addr); this.authorization.getEndpoint_addrs().add(addr); @@ -368,8 +383,10 @@ public class Feed extends Syncable { JSONObject jol = jo.optJSONObject("links"); this.links = (jol == null) ? (new FeedLinks()) : (new FeedLinks(jol)); } catch (InvalidObjectException e) { + intlogger.log(Level.WARN, "PROV0030 Feed.Feed: ", e); throw e; } catch (Exception e) { + intlogger.error("PROV0031 Feed.Feed: invalid JSON: "+e); throw new InvalidObjectException("invalid JSON: " + e.getMessage()); } } @@ -389,6 +406,14 @@ public class Feed extends Syncable { fl.setLog(URLUtilities.generateFeedLogURL(feedid)); } + public String getAafInstance() { + return aaf_instance; + } + + public void setAaf_instance(String aaf_instance) { + this.aaf_instance = aaf_instance; + } + //new getter setters for groups- Rally:US708115 - 1610 public int getGroupid() { return groupid; @@ -499,6 +524,7 @@ public class Feed extends Syncable { jo.put("suspend", suspended); jo.put("last_mod", last_mod.getTime()); jo.put("created_date", created_date.getTime()); + jo.put("aaf_instance", aaf_instance); return jo; } @@ -581,7 +607,7 @@ public class Feed extends Syncable { } // Finally, create the FEEDS row - sql = "insert into FEEDS (FEEDID, NAME, VERSION, DESCRIPTION, AUTH_CLASS, PUBLISHER, SELF_LINK, PUBLISH_LINK, SUBSCRIBE_LINK, LOG_LINK, DELETED, SUSPENDED,BUSINESS_DESCRIPTION, GROUPID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)"; + sql = "insert into FEEDS (FEEDID, NAME, VERSION, DESCRIPTION, AUTH_CLASS, PUBLISHER, SELF_LINK, PUBLISH_LINK, SUBSCRIBE_LINK, LOG_LINK, DELETED, SUSPENDED,BUSINESS_DESCRIPTION, GROUPID, AAF_INSTANCE) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; try(PreparedStatement ps2 = c.prepareStatement(sql)) { ps2.setInt(1, feedid); ps2.setString(2, getName()); @@ -595,8 +621,9 @@ public class Feed extends Syncable { ps2.setString(10, getLinks().getLog()); ps2.setBoolean(11, isDeleted()); ps2.setBoolean(12, isSuspended()); - ps2.setString(13, getBusiness_description()); // New field is added - Groups feature Rally:US708102 - 1610 - ps2.setInt(14, groupid); //New field is added - Groups feature Rally:US708115 - 1610 + ps2.setString(13, getBusiness_description()); + ps2.setInt(14, groupid); + ps2.setString(15, getAafInstance()); ps2.executeUpdate(); } } catch (SQLException e) { @@ -675,8 +702,8 @@ public class Feed extends Syncable { ps.setString(2, getAuthorization().getClassification()); ps.setInt(3, deleted ? 1 : 0); ps.setInt(4, suspended ? 1 : 0); - ps.setString(5, getBusiness_description()); // New field is added - Groups feature Rally:US708102 - 1610 - ps.setInt(6, groupid); //New field is added - Groups feature Rally:US708115 - 1610 + ps.setString(5, getBusiness_description()); + ps.setInt(6, groupid); ps.setInt(7, feedid); ps.executeUpdate(); ps.close(); @@ -760,6 +787,8 @@ public class Feed extends Syncable { return false; if (suspended != of.suspended) return false; + if (!aaf_instance.equals(of.aaf_instance)) + return false; return true; } @@ -770,6 +799,6 @@ public class Feed extends Syncable { @Override public int hashCode() { - return Objects.hash(feedid, groupid, name, version, description, business_description, authorization, publisher, links, deleted, suspended, last_mod, created_date); + return super.hashCode(); } -} +} \ No newline at end of file diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Subscription.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Subscription.java index 0c0c5461..bdc062f9 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Subscription.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/beans/Subscription.java @@ -23,23 +23,19 @@ package org.onap.dmaap.datarouter.provisioning.beans; -import java.io.InvalidObjectException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.Properties; +import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.json.JSONObject; import org.onap.dmaap.datarouter.provisioning.utils.DB; +import org.onap.dmaap.datarouter.provisioning.utils.PasswordProcessor; import org.onap.dmaap.datarouter.provisioning.utils.URLUtilities; +import java.io.InvalidObjectException; +import java.security.GeneralSecurityException; +import java.sql.*; +import java.util.Date; +import java.util.*; + /** * The representation of a Subscription. Subscriptions can be retrieved from the DB, or stored/updated in the DB. * @@ -62,6 +58,7 @@ public class Subscription extends Syncable { private int feedid; private int groupid; //New field is added - Groups feature Rally:US708115 - 1610 private SubDelivery delivery; + private boolean followRedirect; private boolean metadataOnly; private String subscriber; private SubLinks links; @@ -69,18 +66,20 @@ public class Subscription extends Syncable { private Date lastMod; private Date createdDate; private boolean privilegedSubscriber; + private String aafInstance; private boolean decompress; public static Subscription getSubscriptionMatching(Subscription sub) { SubDelivery deli = sub.getDelivery(); String sql = String.format( - "select * from SUBSCRIPTIONS where FEEDID = %d and DELIVERY_URL = \"%s\" and DELIVERY_USER = \"%s\" and DELIVERY_PASSWORD = \"%s\" and DELIVERY_USE100 = %d and METADATA_ONLY = %d", + "select * from SUBSCRIPTIONS where FEEDID = %d and DELIVERY_URL = \"%s\" and DELIVERY_USER = \"%s\" and DELIVERY_PASSWORD = \"%s\" and DELIVERY_USE100 = %d and METADATA_ONLY = %d and FOLLOW_REDIRECTS = %d", sub.getFeedid(), deli.getUrl(), deli.getUser(), deli.getPassword(), deli.isUse100() ? 1 : 0, - sub.isMetadataOnly() ? 1 : 0 + sub.isMetadataOnly() ? 1 : 0, + sub.isFollowRedirect() ? 1 :0 ); List list = getSubscriptionsForSQL(sql); return !list.isEmpty() ? list.get(0) : null; @@ -145,7 +144,6 @@ public class Subscription extends Syncable { DB db = new DB(); @SuppressWarnings("resource") Connection conn = db.getConnection(); - try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setString(1, String.valueOf(feedid)); try (ResultSet rs = stmt.executeQuery()) { @@ -197,12 +195,14 @@ public class Subscription extends Syncable { this.groupid = -1; //New field is added - Groups feature Rally:US708115 - 1610 this.delivery = new SubDelivery(url, user, password, false); this.metadataOnly = false; + this.followRedirect = false; this.subscriber = ""; this.links = new SubLinks(); this.suspended = false; this.lastMod = new Date(); this.createdDate = new Date(); this.privilegedSubscriber = false; + this.aafInstance = ""; this.decompress = false; } @@ -212,13 +212,14 @@ public class Subscription extends Syncable { this.groupid = rs.getInt("GROUPID"); //New field is added - Groups feature Rally:US708115 - 1610 this.delivery = new SubDelivery(rs); this.metadataOnly = rs.getBoolean("METADATA_ONLY"); + this.followRedirect = rs.getBoolean("FOLLOW_REDIRECTS"); this.subscriber = rs.getString("SUBSCRIBER"); - this.links = new SubLinks(rs.getString("SELF_LINK"), URLUtilities.generateFeedURL(feedid), - rs.getString("LOG_LINK")); + this.links = new SubLinks(rs.getString("SELF_LINK"), URLUtilities.generateFeedURL(feedid), rs.getString("LOG_LINK")); this.suspended = rs.getBoolean("SUSPENDED"); this.lastMod = rs.getDate("LAST_MOD"); this.createdDate = rs.getDate("CREATED_DATE"); this.privilegedSubscriber = rs.getBoolean("PRIVILEGED_SUBSCRIBER"); + this.aafInstance = rs.getString("AAF_INSTANCE"); this.decompress = rs.getBoolean("DECOMPRESS"); } @@ -229,7 +230,11 @@ public class Subscription extends Syncable { this.subid = jo.optInt(SUBID_KEY, -1); this.feedid = jo.optInt(FEEDID_KEY, -1); this.groupid = jo.optInt(GROUPID_KEY, -1); //New field is added - Groups feature Rally:US708115 - 1610 - + this.aafInstance = jo.optString("aaf_instance", "legacy"); + if(!(aafInstance.equalsIgnoreCase("legacy"))){ + if (aafInstance.length() > 255) + throw new InvalidObjectException("aaf_instance field is too long"); + } JSONObject jdeli = jo.getJSONObject("delivery"); String url = jdeli.getString("url"); String user = jdeli.getString("user"); @@ -245,15 +250,15 @@ public class Subscription extends Syncable { if (url.length() > 256) { throw new InvalidObjectException("delivery url field is too long"); } - if (user.length() > 20) { + if (user.length() > 60) { throw new InvalidObjectException("delivery user field is too long"); } if (password.length() > 32) { throw new InvalidObjectException("delivery password field is too long"); } this.delivery = new SubDelivery(url, user, password, use100); - this.metadataOnly = jo.getBoolean("metadataOnly"); + this.followRedirect = jo.optBoolean("follow_redirect", false); this.suspended = jo.optBoolean("suspend", false); this.privilegedSubscriber = jo.optBoolean("privilegedSubscriber", false); this.decompress = jo.optBoolean("decompress", false); @@ -296,6 +301,13 @@ public class Subscription extends Syncable { SubLinks sl = getLinks(); sl.setFeed(URLUtilities.generateFeedURL(feedid)); } + public String getAafInstance() { + return aafInstance; + } + + public void setAafInstance(String aafInstance) { + this.aafInstance = aafInstance; + } //New getter setters for Groups feature Rally:US708115 - 1610 public int getGroupid() { @@ -322,7 +334,14 @@ public class Subscription extends Syncable { this.metadataOnly = metadataOnly; } - public boolean isSuspended() { + private boolean isFollowRedirect() { + return followRedirect; + } + public void setFollowRedirect(boolean followRedirect) { + this.followRedirect = followRedirect; + } + + boolean isSuspended() { return suspended; } @@ -355,7 +374,7 @@ public class Subscription extends Syncable { return links; } - public void setLinks(SubLinks links) { + void setLinks(SubLinks links) { this.links = links; } @@ -375,12 +394,14 @@ public class Subscription extends Syncable { jo.put(GROUPID_KEY, groupid); //New field is added - Groups feature Rally:US708115 - 1610 jo.put("delivery", delivery.asJSONObject()); jo.put("metadataOnly", metadataOnly); + jo.put("follow_redirect", followRedirect); jo.put("subscriber", subscriber); jo.put("links", links.asJSONObject()); jo.put("suspend", suspended); jo.put(LAST_MOD_KEY, lastMod.getTime()); jo.put(CREATED_DATE, createdDate.getTime()); jo.put("privilegedSubscriber", privilegedSubscriber); + jo.put("aaf_instance", aafInstance); jo.put("decompress", decompress); return jo; } @@ -419,7 +440,7 @@ public class Subscription extends Syncable { } // Create the SUBSCRIPTIONS row - String sql = "insert into SUBSCRIPTIONS (SUBID, FEEDID, DELIVERY_URL, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, PRIVILEGED_SUBSCRIBER, DECOMPRESS) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + String sql = "insert into SUBSCRIPTIONS (SUBID, FEEDID, DELIVERY_URL, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, PRIVILEGED_SUBSCRIBER, FOLLOW_REDIRECTS, DECOMPRESS, AAF_INSTANCE) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; ps = c.prepareStatement(sql, new String[]{SUBID_COL}); ps.setInt(1, subid); ps.setInt(2, feedid); @@ -432,7 +453,9 @@ public class Subscription extends Syncable { ps.setBoolean(9, isSuspended()); ps.setInt(10, groupid); //New field is added - Groups feature Rally:US708115 - 1610 ps.setBoolean(11, isPrivilegedSubscriber()); - ps.setBoolean(12, isDecompress()); + ps.setInt(12, isFollowRedirect() ? 1 : 0); + ps.setBoolean(13, isDecompress()); + ps.setString(14, getAafInstance()); ps.execute(); ps.close(); // Update the row to set the URLs @@ -446,6 +469,7 @@ public class Subscription extends Syncable { } catch (SQLException e) { rv = false; intlogger.warn("PROV0005 doInsert: " + e.getMessage()); + intlogger.log(Level.WARN, "PROV0005 Subscription.doInsert(1): ", e); } finally { try { if (ps != null) { @@ -463,7 +487,7 @@ public class Subscription extends Syncable { boolean rv = true; PreparedStatement ps = null; try { - String sql = "update SUBSCRIPTIONS set DELIVERY_URL = ?, DELIVERY_USER = ?, DELIVERY_PASSWORD = ?, DELIVERY_USE100 = ?, METADATA_ONLY = ?, SUSPENDED = ?, GROUPID = ?, PRIVILEGED_SUBSCRIBER = ?, DECOMPRESS = ? where SUBID = ?"; + String sql = "update SUBSCRIPTIONS set DELIVERY_URL = ?, DELIVERY_USER = ?, DELIVERY_PASSWORD = ?, DELIVERY_USE100 = ?, METADATA_ONLY = ?, SUSPENDED = ?, GROUPID = ?, PRIVILEGED_SUBSCRIBER = ?, FOLLOW_REDIRECTS = ?, DECOMPRESS = ? where SUBID = ?"; ps = c.prepareStatement(sql); ps.setString(1, delivery.getUrl()); ps.setString(2, delivery.getUser()); @@ -473,8 +497,9 @@ public class Subscription extends Syncable { ps.setInt(6, suspended ? 1 : 0); ps.setInt(7, groupid); //New field is added - Groups feature Rally:US708115 - 1610 ps.setInt(8, privilegedSubscriber ? 1 : 0); - ps.setInt(9, decompress ? 1 : 0); - ps.setInt(10, subid); + ps.setInt(9, isFollowRedirect() ? 1 : 0); + ps.setInt(10, isDecompress() ? 1 : 0); + ps.setInt(11, subid); ps.executeUpdate(); } catch (SQLException e) { rv = false; @@ -576,19 +601,27 @@ public class Subscription extends Syncable { if (metadataOnly != os.metadataOnly) { return false; } + if (followRedirect != os.followRedirect) { + return false; + } if (!subscriber.equals(os.subscriber)) { return false; } if (!links.equals(os.links)) { return false; } - return suspended == os.suspended; + if (suspended != os.suspended) { + return false; + } + if (!aafInstance.equals(os.aafInstance)) { + return false; + } + return true; } @Override public int hashCode() { - return Objects.hash(subid, feedid, groupid, delivery, metadataOnly, subscriber, links, suspended, lastMod, - createdDate); + return super.hashCode(); } @Override diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DB.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DB.java index 3e2436fa..8ca71187 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DB.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DB.java @@ -185,8 +185,8 @@ public class DB { connection = getConnection(); Set actualTables = getTableSet(connection); boolean initialize = false; - for (String table : expectedTables) { - initialize |= !actualTables.contains(table.toLowerCase()); + for (String tableName : expectedTables) { + initialize |= !actualTables.contains(tableName); } if (initialize) { intlogger.info("PROV9001: First time startup; The database is being initialized."); @@ -211,13 +211,13 @@ public class DB { * @return the set of table names */ private Set getTableSet(Connection connection) { - Set tables = new HashSet(); + Set tables = new HashSet<>(); try { DatabaseMetaData md = connection.getMetaData(); ResultSet rs = md.getTables(null, null, "%", null); if (rs != null) { while (rs.next()) { - tables.add(rs.getString("TABLE_NAME")); + tables.add(rs.getString("TABLE_NAME").toUpperCase()); } rs.close(); } diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilter.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilter.java new file mode 100644 index 00000000..fb8b0724 --- /dev/null +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilter.java @@ -0,0 +1,259 @@ +/** + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.provisioning.utils; + +import org.apache.log4j.Logger; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.dmaap.datarouter.provisioning.BaseServlet; +import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord; +import org.onap.dmaap.datarouter.provisioning.beans.Feed; +import org.onap.dmaap.datarouter.provisioning.beans.Subscription; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +public class DRProvCadiFilter extends CadiFilter { + private static Logger eventlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.events"); + private static Logger intlogger = Logger.getLogger("org.onap.dmaap.datarouter.provisioning.internal"); + private String aafInstance = ""; + + public DRProvCadiFilter(boolean init, PropAccess access) throws ServletException { + super(init, access); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = null; + HttpServletResponse httpResponse = null; + //cadi code + try { + httpRequest = (HttpServletRequest) request; + httpResponse = (HttpServletResponse) response; + } catch (ClassCastException e) { + try { + throw new ServletException("Only serving HTTP today", e); + } catch (ServletException e1) { + intlogger.error("PROV7001 DRProvCadiFilter.doFilter: ", e1); + } + } + EventLogRecord elr = new EventLogRecord(httpRequest); + String excludeAAF = httpRequest.getHeader(BaseServlet.EXCLUDE_AAF_HEADER);//send this param value as true, if want to add legacy feed/subscriber in AAF env + + String pathUrl = httpRequest.getServletPath(); + if (!(pathUrl.contains("internal") || + pathUrl.contains("sublog") || + pathUrl.contains("feedlog") || + pathUrl.contains("statistics") || + pathUrl.contains("publish") || + pathUrl.contains("group"))) { + + String method = httpRequest.getMethod().toUpperCase(); + if (!(method.equals("POST"))) { // if request method is PUT method (publish or Feed update) Needs to check for DELETE + if (method.equals("PUT") || method.equals("DELETE")) { + if ((pathUrl.contains("subs"))) {//edit subscriber + int subId = BaseServlet.getIdFromPath(httpRequest); + if (subId <= 0) { + String message = String.format("Invalid request URI - %s", httpRequest.getPathInfo()); + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_NOT_FOUND); + eventlogger.info(elr); + httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND, message); + return; + } + if (isAAFSubscriber(subId)) {//edit AAF Subscriber + String message = String.format("DRProvCadiFilter - Edit AAF Subscriber : %d : AAF Instance - %s", subId, aafInstance); + elr.setMessage(message); + eventlogger.info(elr); + //request.setAttribute("aafInstance", aafInstance);// no need to set it in request since it is taken care in respective servlets + super.doFilter(request, response, chain); + + } else {//Edit or publish legacy Subscriber + String message = "DRProvCadiFilter - Edit/Publish Legacy Subscriber :" + subId; + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } + + } else {//edit or publish Feed + int feedId = BaseServlet.getIdFromPath(httpRequest); + if (feedId <= 0) { + String message = "Invalid request URI - " + httpRequest.getPathInfo(); + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_NOT_FOUND); + eventlogger.info(elr); + httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND, message); + return; + } + + if (isAAFFeed(feedId)) {//edit AAF Feed + String message = "DRProvCadiFilter - Edit AAF Feed:" + feedId + ":" + "AAF Instance -" + aafInstance; + elr.setMessage(message); + eventlogger.info(elr); + super.doFilter(request, response, chain); + + } else {//Edit or publish legacy Feed + String message = "DRProvCadiFilter - Edit/Publish Legacy Feed:" + feedId; + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } + } + } else {// in all other cases defaults to legacy behavior + String message = "DRProvCadiFilter - Default Legacy Feed/Subscriber URI -:" + httpRequest.getPathInfo(); + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } + } else { + //check to add legacy/AAF subscriber + if ((pathUrl.contains("subscribe"))) {//add subscriber + int feedId = BaseServlet.getIdFromPath(httpRequest); + if (feedId <= 0) { + String message = "Invalid request URI - " + httpRequest.getPathInfo(); + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_NOT_FOUND); + eventlogger.info(elr); + httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND, message); + return; + } + if (isAAFFeed(feedId)) {//check if AAF Feed or legacy to add new subscriber + if (excludeAAF == null) { + String message = "DRProvCadiFilter -Invalid request Header Parmeter " + BaseServlet.EXCLUDE_AAF_HEADER + " = " + httpRequest.getHeader(BaseServlet.EXCLUDE_AAF_HEADER); + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_BAD_REQUEST); + eventlogger.info(elr); + httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, message); + return; + } + if (excludeAAF.equalsIgnoreCase("true")) {//Check to add legacy subscriber to AAF Feed + String message = "DRProvCadiFilter - add legacy subscriber to AAF Feed, FeedID:" + feedId; + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } else { + String message = "DRProvCadiFilter - Add AAF subscriber to AAF Feed, FeedID:" + feedId + ":" + "AAF Instance -" + aafInstance; + elr.setMessage(message); + eventlogger.info(elr); + super.doFilter(request, response, chain); + } + } else {//Add legacy susbcriber to legacy Feed + String message = "DRProvCadiFilter - add legacy subscriber to legacy Feed:" + feedId; + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } + } else {//add AAF feed + if (excludeAAF == null) { + String message = "DRProvCadiFilter -Invalid request Header Parmeter " + BaseServlet.EXCLUDE_AAF_HEADER + " = " + httpRequest.getHeader(BaseServlet.EXCLUDE_AAF_HEADER); + elr.setMessage(message); + elr.setResult(HttpServletResponse.SC_BAD_REQUEST); + eventlogger.info(elr); + httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, message); + return; + } + if (excludeAAF.equalsIgnoreCase("true")) {//add legacy feed + String message = "DRProvCadiFilter - Create new legacy Feed : EXCLUDE_AAF = " + excludeAAF; + elr.setMessage(message); + eventlogger.info(elr); + chain.doFilter(request, response); + } else {//add AAF Feed + String message = "DRProvCadiFilter - Create new AAF Feed : EXCLUDE_AAF = " + excludeAAF; + elr.setMessage(message); + eventlogger.info(elr); + super.doFilter(request, response, chain); + } + } + } + } else { + //All other requests default to (Non CADI) legacy + chain.doFilter(request, response); + } + } + + /** + * Check if it is AAF feed OR existing feed. + * + * @param feedId the Feed ID + * @return true if it is valid + */ + @SuppressWarnings("resource") + private boolean isAAFFeed(int feedId) { + try { + Feed feed = Feed.getFeedById(feedId); + if (feed != null) { + if (!((feed.getAafInstance().equalsIgnoreCase("legacy")) || feed.getAafInstance() == null || feed.getAafInstance().equals(""))) { //also apply null check and empty check too + aafInstance = feed.getAafInstance(); + String message = "DRProvCadiFilter.isAAFFeed: aafInstance-:" + aafInstance + "; feedId:- " + feedId; + intlogger.debug(message); + return true; + } else { + return false; + } + } else { + String message = "DRProvCadiFilter.isAAFFeed; Feed does not exist FeedID:-" + feedId; + intlogger.debug(message); + } + + } catch (Exception e) { + intlogger.error("PROV0073 DRProvCadiFilter.isAAFFeed: ", e); + return false; + } + return false; + } + + /** + * Check if it is AAF sub OR existing sub. + * + * @param subId the Sub ID + * @return true if it is valid + */ + @SuppressWarnings("resource") + private boolean isAAFSubscriber(int subId) { + try { + Subscription subscriber = Subscription.getSubscriptionById(subId); + if (subscriber != null) { + if (!((subscriber.getAafInstance().equalsIgnoreCase("legacy")) || subscriber.getAafInstance() == null || subscriber.getAafInstance().equals(""))) { //also apply null check and empty check too + aafInstance = subscriber.getAafInstance(); + String message = "DRProvCadiFilter.isAAFSubscriber: aafInstance-:" + aafInstance + "; subId:- " + subId; + intlogger.debug(message); + return true; + } else { + return false; + } + } else { + String message = "DRProvCadiFilter.isAAFSubscriber; Subscriber does not exist subId:-" + subId; + intlogger.debug(message); + } + } catch (Exception e) { + intlogger.error("PROV0073 DRProvCadiFilter.isAAFSubscriber: ", e); + return false; + } + return false; + } + +} diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/LogfileLoader.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/LogfileLoader.java index af9f8295..6c5a13fd 100644 --- a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/LogfileLoader.java +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/LogfileLoader.java @@ -82,7 +82,7 @@ public class LogfileLoader extends Thread { /** * This is a singleton -- there is only one LogfileLoader object in the server */ - private static LogfileLoader p; + private static LogfileLoader logfileLoader; /** * Get the singleton LogfileLoader object, and start it if it is not running. @@ -90,11 +90,11 @@ public class LogfileLoader extends Thread { * @return the LogfileLoader */ public static synchronized LogfileLoader getLoader() { - if (p == null) - p = new LogfileLoader(); - if (!p.isAlive()) - p.start(); - return p; + if (logfileLoader == null) + logfileLoader = new LogfileLoader(); + if (!logfileLoader.isAlive()) + logfileLoader.start(); + return logfileLoader; } /** diff --git a/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/PasswordProcessor.java b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/PasswordProcessor.java new file mode 100644 index 00000000..44142031 --- /dev/null +++ b/datarouter-prov/src/main/java/org/onap/dmaap/datarouter/provisioning/utils/PasswordProcessor.java @@ -0,0 +1,73 @@ +/** + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.provisioning.utils; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Base64; + +/** + * The Processing of a Password. Password can be encrypted and decrypted. + * @author Vikram Singh + * @version $Id: PasswordProcessor.java,v 1.0 2016/12/14 10:16:52 EST + */ +public class PasswordProcessor { + + private PasswordProcessor(){} + + private static final String SECRET_KEY_FACTORY_TYPE = "PBEWithMD5AndDES"; + private static final String PASSWORD_ENCRYPTION_STRING = (new DB()).getProperties().getProperty("org.onap.dmaap.datarouter.provserver.passwordencryption"); + private static final char[] PASSWORD = PASSWORD_ENCRYPTION_STRING.toCharArray(); + private static final byte[] SALT = {(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12, (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,}; + + /** + * Encrypt password. + * @param property the Password + * @return Encrypted password. + */ + public static String encrypt(String property) throws GeneralSecurityException { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_TYPE); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance(SECRET_KEY_FACTORY_TYPE); + pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 32)); + return Base64.getEncoder().encodeToString(pbeCipher.doFinal(property.getBytes(StandardCharsets.UTF_8))); + } + + /** + * Decrypt password. + * @param property the Password + * @return Decrypt password. + */ + public static String decrypt(String property) throws GeneralSecurityException { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_TYPE); + SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); + Cipher pbeCipher = Cipher.getInstance(SECRET_KEY_FACTORY_TYPE); + pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 32)); + return new String(pbeCipher.doFinal(Base64.getDecoder().decode(property)), StandardCharsets.UTF_8); + } + +} diff --git a/datarouter-prov/src/main/resources/drProvCadi.properties b/datarouter-prov/src/main/resources/drProvCadi.properties new file mode 100644 index 00000000..56f2e5c0 --- /dev/null +++ b/datarouter-prov/src/main/resources/drProvCadi.properties @@ -0,0 +1,23 @@ +cadi_x509_issuers=CN=intermediateCA_1, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_7, OU=OSAAF, O=ONAP, C=US:CN=intermediateCA_9, OU=OSAAF, O=ONAP, C=US +cadi_keyfile=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.keyfile +cadi_keystore=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.jks +cadi_keystore_password=AT{];bvaDiytVD&oWhMZj0N5 +cadi_key_password=AT{];bvaDiytVD&oWhMZj0N5 +cadi_alias=dmaap-dr-prov@dmaap-dr.onap.org +cadi_truststore=/opt/app/datartr/aaf_certs/org.onap.dmaap-dr.trust.jks +cadi_truststore_password=ljlS@Y}0]{UO(TnwvEWkgJ%] + +aaf_env=DEV +aaf_locate_url=https://aaf-onap-test.osaaf.org:8095 +aaf_oauth2_introspect_url=https://AAF_LOCATE_URL/AAF_NS.introspect:2.1/introspect +aaf_oauth2_token_url=https://AAF_LOCATE_URL/AAF_NS.token:2.1/token +aaf_url=https://AAF_LOCATE_URL/AAF_NS.service:2.1 +cadi_protocols=TLSv1.1,TLSv1.2 +cm_url=https://AAF_LOCATE_URL/AAF_NS.cm:2.1 +fs_url=https://AAF_LOCATE_URL/AAF_NS.fs.2.1 +gui_url=https://AAF_LOCATE_URL/AAF_NS.gui.2.1 + +cadi_latitude=53.423 +cadi_longitude=7.940 + +cadi_loglevel=DEBUG \ No newline at end of file diff --git a/datarouter-prov/src/main/resources/misc/sql_init_01.sql b/datarouter-prov/src/main/resources/misc/sql_init_01.sql index 14c59a65..55f0aee9 100755 --- a/datarouter-prov/src/main/resources/misc/sql_init_01.sql +++ b/datarouter-prov/src/main/resources/misc/sql_init_01.sql @@ -1,10 +1,8 @@ -use datarouter; - CREATE TABLE FEEDS ( FEEDID INT UNSIGNED NOT NULL PRIMARY KEY, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, NAME VARCHAR(255) NOT NULL, - VERSION VARCHAR(20) NOT NULL, + VERSION VARCHAR(20) NULL, DESCRIPTION VARCHAR(1000), BUSINESS_DESCRIPTION VARCHAR(1000) DEFAULT NULL, AUTH_CLASS VARCHAR(32) NOT NULL, @@ -16,13 +14,14 @@ CREATE TABLE FEEDS ( DELETED BOOLEAN DEFAULT FALSE, LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + AAF_INSTANCE VARCHAR(256) ); CREATE TABLE FEED_ENDPOINT_IDS ( FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20) NOT NULL, - PASSWORD VARCHAR(32) NOT NULL + USERID VARCHAR(60) NOT NULL, + PASSWORD VARCHAR(100) NOT NULL ); CREATE TABLE FEED_ENDPOINT_ADDRS ( @@ -35,8 +34,9 @@ CREATE TABLE SUBSCRIPTIONS ( FEEDID INT UNSIGNED NOT NULL, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, DELIVERY_URL VARCHAR(256), - DELIVERY_USER VARCHAR(20), - DELIVERY_PASSWORD VARCHAR(32), + FOLLOW_REDIRECTS TINYINT(1) NOT NULL DEFAULT 0, + DELIVERY_USER VARCHAR(60), + DELIVERY_PASSWORD VARCHAR(100), DELIVERY_USE100 BOOLEAN DEFAULT FALSE, METADATA_ONLY BOOLEAN DEFAULT FALSE, SUBSCRIBER VARCHAR(8) NOT NULL, @@ -45,8 +45,9 @@ CREATE TABLE SUBSCRIPTIONS ( LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, PRIVILEGED_SUBSCRIBER BOOLEAN DEFAULT FALSE, + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DECOMPRESS BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + AAF_INSTANCE VARCHAR(256) ); @@ -89,7 +90,7 @@ CREATE TABLE LOG_RECORDS ( CREATE TABLE INGRESS_ROUTES ( SEQUENCE INT UNSIGNED NOT NULL, FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20), + USERID VARCHAR(50), SUBNET VARCHAR(44), NODESET INT UNSIGNED NOT NULL ); @@ -144,6 +145,6 @@ INSERT INTO PARAMETERS VALUES ('PROV_MAXFEED_COUNT', '10000'), ('PROV_MAXSUB_COUNT', '100000'), ('PROV_REQUIRE_CERT', 'false'), - ('PROV_REQUIRE_SECURE', 'false'), + ('PROV_REQUIRE_SECURE', 'true'), ('_INT_VALUES', 'LOGROLL_INTERVAL|PROV_MAXFEED_COUNT|PROV_MAXSUB_COUNT|DELIVERY_INIT_RETRY_INTERVAL|DELIVERY_MAX_RETRY_INTERVAL|DELIVERY_RETRY_RATIO|DELIVERY_MAX_AGE|DELIVERY_FILE_PROCESS_INTERVAL') - ; + ; \ No newline at end of file diff --git a/datarouter-prov/src/main/resources/provserver.properties b/datarouter-prov/src/main/resources/provserver.properties index 4dcdee5f..45393461 100755 --- a/datarouter-prov/src/main/resources/provserver.properties +++ b/datarouter-prov/src/main/resources/provserver.properties @@ -47,6 +47,22 @@ org.onap.dmaap.datarouter.provserver.localhost = 127.0.0.1 # Database access org.onap.dmaap.datarouter.db.driver = org.mariadb.jdbc.Driver -org.onap.dmaap.datarouter.db.url = jdbc:mariadb://172.100.0.2:3306/datarouter +org.onap.dmaap.datarouter.db.url = jdbc:mariadb://datarouter-mariadb:3306/datarouter org.onap.dmaap.datarouter.db.login = datarouter org.onap.dmaap.datarouter.db.password = datarouter + +# PROV - DEFAULT ENABLED TLS PROTOCOLS +org.onap.dmaap.datarouter.provserver.https.include.protocols = TLSv1.1|TLSv1.2 + +# AAF config +org.onap.dmaap.datarouter.provserver.cadi.enabled = false + +org.onap.dmaap.datarouter.provserver.passwordencryption = PasswordEncryptionKey#@$%^&1234# +org.onap.dmaap.datarouter.provserver.aaf.feed.type = org.onap.dmaap-dr.feed +org.onap.dmaap.datarouter.provserver.aaf.sub.type = org.onap.dmaap-dr.sub +org.onap.dmaap.datarouter.provserver.aaf.instance = legacy +org.onap.dmaap.datarouter.provserver.aaf.action.publish = publish +org.onap.dmaap.datarouter.provserver.aaf.action.subscribe = subscribe + +# AAF URL to connect to AAF server +org.onap.dmaap.datarouter.provserver.cadi.aaf.url = https://aaf-onap-test.osaaf.org:8095 \ No newline at end of file diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServletTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServletTest.java index a8f9c56a..e2a2bc21 100755 --- a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServletTest.java +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DRFeedsServletTest.java @@ -22,59 +22,75 @@ ******************************************************************************/ package org.onap.dmaap.datarouter.provisioning; -import static org.hamcrest.Matchers.notNullValue; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.argThat; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER; - -import java.util.HashSet; -import java.util.Set; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import org.apache.commons.lang3.reflect.FieldUtils; import org.jetbrains.annotations.NotNull; import org.json.JSONArray; import org.json.JSONObject; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.onap.dmaap.datarouter.authz.AuthorizationResponse; import org.onap.dmaap.datarouter.authz.Authorizer; -import org.onap.dmaap.datarouter.provisioning.beans.Feed; import org.onap.dmaap.datarouter.provisioning.beans.Insertable; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.onap.dmaap.datarouter.provisioning.utils.DB; import org.powermock.modules.junit4.PowerMockRunner; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Mockito.*; +import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER; + @RunWith(PowerMockRunner.class) -@SuppressStaticInitializationFor("org.onap.dmaap.datarouter.provisioning.beans.Feed") public class DRFeedsServletTest extends DrServletTestBase { private static DRFeedsServlet drfeedsServlet; + private static EntityManagerFactory emf; + private static EntityManager em; + private DB db; @Mock private HttpServletRequest request; @Mock private HttpServletResponse response; - ListAppender listAppender; + private ListAppender listAppender; + + @BeforeClass + public static void init() { + emf = Persistence.createEntityManagerFactory("dr-unit-tests"); + em = emf.createEntityManager(); + System.setProperty( + "org.onap.dmaap.datarouter.provserver.properties", + "src/test/resources/h2Database.properties"); + } + + @AfterClass + public static void tearDownClass() { + em.clear(); + em.close(); + emf.close(); + } @Before public void setUp() throws Exception { - super.setUp(); listAppender = setTestLogger(DRFeedsServlet.class); drfeedsServlet = new DRFeedsServlet(); + db = new DB(); setAuthoriserToReturnRequestIsAuthorized(); setPokerToNotCreateTimersWhenDeleteFeedIsCalled(); setupValidAuthorisedRequest(); @@ -137,14 +153,11 @@ public class DRFeedsServletTest extends DrServletTestBase { public void Given_Request_Is_HTTP_GET_And_Request_Succeeds_With_Valid_Name_And_Version() throws Exception { ServletOutputStream outStream = mock(ServletOutputStream.class); when(response.getOutputStream()).thenReturn(outStream); - when(request.getParameter("name")).thenReturn("stub_name"); - when(request.getParameter("version")).thenReturn("stub_version"); - PowerMockito.mockStatic(Feed.class); - Feed feed = mock(Feed.class); - PowerMockito.when(Feed.getFeedByNameVersion(anyString(), anyString())).thenReturn(feed); - when(feed.asJSONObject(true)).thenReturn(mock(JSONObject.class)); + when(request.getParameter("name")).thenReturn("Feed1"); + when(request.getParameter("version")).thenReturn("v0.1"); drfeedsServlet.doGet(request, response); verify(response).setStatus(eq(HttpServletResponse.SC_OK)); + verify(response).setContentType(BaseServlet.FEEDFULL_CONTENT_TYPE); verifyEnteringExitCalled(listAppender); } @@ -205,54 +218,70 @@ public class DRFeedsServletTest extends DrServletTestBase { } @Test - public void Given_Request_Is_HTTP_POST_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() + public void Given_Request_Is_HTTP_POST_And_CadiEnabled_Is_True_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { setAuthoriserToReturnRequestNotAuthorized(); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isCadiEnabled", "true", true); + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("true"); + JSONObject JSObject = buildRequestJsonObject(); + DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "not_stub_name"); + jo.put("version", "1.0"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "legacy"); + return jo; + } + }; drfeedsServlet.doPost(request, response); verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } @Test - public void Given_Request_Is_HTTP_POST_And_Request_Contains_Badly_Formed_JSON_Then_Bad_Request_Response_Is_Generated() - throws Exception { - drfeedsServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); - } - - @Test - public void Given_Request_Is_HTTP_POST_And_Active_Feeds_Equals_Max_Feeds_Then_Bad_Request_Response_Is_Generated() - throws Exception { - FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxFeeds", 0, true); + public void Given_Request_Is_HTTP_POST_And_CadiEnabled_Is_False_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() + throws Exception { + setAuthoriserToReturnRequestNotAuthorized(); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isCadiEnabled", "false", true); + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("true"); + JSONObject JSObject = buildRequestJsonObject(); DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { - return new JSONObject(); + JSONObject jo = new JSONObject(); + jo.put("name", "not_stub_name"); + jo.put("version", "1.0"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "legacy"); + return jo; } }; drfeedsServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_CONFLICT), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } @Test - public void Given_Request_Is_HTTP_POST_And_Feed_Is_Not_Valid_Object_Bad_Request_Response_Is_Generated() - throws Exception { - when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn(null); + public void Given_Request_Is_HTTP_POST_And_AAF_DRFeed_And_Exclude_AAF_Is_True_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("true"); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isCadiEnabled", "true", true); JSONObject JSObject = buildRequestJsonObject(); - DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); + jo.put("name", "not_stub_name"); + jo.put("version", "1.0"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "https://aaf-onap-test.osaaf.org:8095"); return jo; } }; - drfeedsServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("Invalid request exclude_AAF")); } @Test - public void Given_Request_Is_HTTP_POST_And_Feed_Already_Exists_Bad_Request_Response_Is_Generated() - throws Exception { - setFeedToReturnInvalidFeedIdSupplied(); + public void Given_Request_Is_HTTP_POST_And_AAF_DRFeed_And_Exclude_AAF_Is_False_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("false"); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isCadiEnabled", "true", true); JSONObject JSObject = buildRequestJsonObject(); DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -260,59 +289,119 @@ public class DRFeedsServletTest extends DrServletTestBase { jo.put("name", "not_stub_name"); jo.put("version", "1.0"); jo.put("authorization", JSObject); + jo.put("aaf_instance", "*"); return jo; } }; drfeedsServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access to permission")); } @Test - public void Given_Request_Is_HTTP_POST_And_POST_Fails_Bad_Request_Response_Is_Generated() throws Exception { + public void Given_Request_Is_HTTP_POST_And_AAF_DRFeed_And_Exclude_AAF_Is_False_With_Permissions_Then_Created_OK_Response_Is_Generated() throws Exception { + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isCadiEnabled", "true", true); + ServletOutputStream outStream = mock(ServletOutputStream.class); + when(response.getOutputStream()).thenReturn(outStream); + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("false"); JSONObject JSObject = buildRequestJsonObject(); + when(request.isUserInRole("org.onap.dmaap-dr.feed|*|create")).thenReturn(true); DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); - jo.put("name", "stub_name"); - jo.put("version", "2.0"); + jo.put("name", "not_stub_name"); + jo.put("version", "1.0"); jo.put("authorization", JSObject); + jo.put("aaf_instance", "*"); return jo; } @Override protected boolean doInsert(Insertable bean) { - return false; + return true; } }; drfeedsServlet.doPost(request, response); - verify(response) - .sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), argThat(notNullValue(String.class))); + verify(response).setStatus(eq(HttpServletResponse.SC_CREATED)); + verifyEnteringExitCalled(listAppender); } + @Test + public void Given_Request_Is_HTTP_POST_And_Request_Contains_Badly_Formed_JSON_Then_Bad_Request_Response_Is_Generated() + throws Exception { + drfeedsServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + } @Test - public void Given_Request_Is_HTTP_POST_And_Change_On_Feeds_Succeeds_A_STATUS_OK_Response_Is_Generated() + public void Given_Request_Is_HTTP_POST_And_Active_Feeds_Equals_Max_Feeds_Then_Bad_Request_Response_Is_Generated() throws Exception { - ServletOutputStream outStream = mock(ServletOutputStream.class); - when(response.getOutputStream()).thenReturn(outStream); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxFeeds", 0, true); + DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + return new JSONObject(); + } + }; + drfeedsServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_CONFLICT), argThat(notNullValue(String.class))); + } + + @Test + public void Given_Request_Is_HTTP_POST_And_Feed_Is_Not_Valid_Object_Bad_Request_Response_Is_Generated() + throws Exception { + DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + return new JSONObject(); + } + }; + + drfeedsServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + } + + @Test + public void Given_Request_Is_HTTP_POST_And_Feed_Already_Exists_Bad_Request_Response_Is_Generated() + throws Exception { + when(request.getParameter("name")).thenReturn("AafFeed"); + when(request.getParameter("version")).thenReturn("v0.1"); + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("false"); + when(request.isUserInRole("org.onap.dmaap-dr.feed|*|create")).thenReturn(true); JSONObject JSObject = buildRequestJsonObject(); + DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "AafFeed"); + jo.put("version", "v0.1"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "*"); + return jo; + } + }; + drfeedsServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), contains("This feed already exists in the database")); + } + + @Test + public void Given_Request_Is_HTTP_POST_And_POST_Fails_Bad_Request_Response_Is_Generated() throws Exception { + JSONObject JSObject = buildRequestJsonObject(); + when(request.getHeader(DRFeedsServlet.EXCLUDE_AAF_HEADER)).thenReturn("true"); DRFeedsServlet drfeedsServlet = new DRFeedsServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); jo.put("name", "stub_name"); - jo.put("version", "1.0"); + jo.put("version", "2.0"); jo.put("authorization", JSObject); + jo.put("aaf_instance", "legacy"); return jo; } @Override protected boolean doInsert(Insertable bean) { - return true; + return false; } }; drfeedsServlet.doPost(request, response); - verify(response).setStatus(eq(HttpServletResponse.SC_CREATED)); - verifyEnteringExitCalled(listAppender); + verify(response) + .sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), argThat(notNullValue(String.class))); } @NotNull @@ -335,7 +424,7 @@ public class DRFeedsServletTest extends DrServletTestBase { private void setUpValidSecurityOnHttpRequest() throws Exception { when(request.isSecure()).thenReturn(true); - Set authAddressesAndNetworks = new HashSet(); + Set authAddressesAndNetworks = new HashSet<>(); authAddressesAndNetworks.add(("127.0.0.1")); FieldUtils .writeDeclaredStaticField(BaseServlet.class, "authorizedAddressesAndNetworks", authAddressesAndNetworks, @@ -348,29 +437,6 @@ public class DRFeedsServletTest extends DrServletTestBase { when(request.getHeader(BEHALF_HEADER)).thenReturn(headerValue); } - private void setValidPathInfoInHttpHeader() { - when(request.getPathInfo()).thenReturn("/123"); - } - - private void setFeedToReturnInvalidFeedIdSupplied() { - PowerMockito.mockStatic(Feed.class); - PowerMockito.when(Feed.getFeedById(anyInt())).thenReturn(null); - when(Feed.getFeedByNameVersion(anyString(), anyString())).thenReturn(mock(Feed.class)); - } - - private void setFeedToReturnValidFeedForSuppliedId() { - PowerMockito.mockStatic(Feed.class); - Feed feed = mock(Feed.class); - PowerMockito.when(Feed.getFeedById(anyInt())).thenReturn(feed); - when(feed.isDeleted()).thenReturn(false); - when(feed.asJSONObject(true)).thenReturn(mock(JSONObject.class)); - when(feed.getPublisher()).thenReturn("Stub_Value"); - when(feed.getName()).thenReturn("stub_name"); - when(feed.getVersion()).thenReturn("1.0"); - when(feed.asLimitedJSONObject()).thenReturn(mock(JSONObject.class)); - PowerMockito.when(feed.getFeedByNameVersion(anyString(), anyString())).thenReturn(null); - } - private void setAuthoriserToReturnRequestNotAuthorized() throws IllegalAccessException { AuthorizationResponse authResponse = mock(AuthorizationResponse.class); Authorizer authorizer = mock(Authorizer.class); @@ -395,13 +461,10 @@ public class DRFeedsServletTest extends DrServletTestBase { private void setupValidAuthorisedRequest() throws Exception { setUpValidSecurityOnHttpRequest(); setBehalfHeader("Stub_Value"); - setValidPathInfoInHttpHeader(); - setFeedToReturnValidFeedForSuppliedId(); } - private void setUpValidContentHeadersAndJSONOnHttpRequest() { + private void setUpValidContentHeadersAndJSONOnHttpRequest() throws IllegalAccessException { when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.feed; version=1.0"); when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_subjectGroup"); - } } diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DrServletTestBase.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DrServletTestBase.java index 265a2ee9..bad6e2cb 100644 --- a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DrServletTestBase.java +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/DrServletTestBase.java @@ -28,17 +28,11 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; import org.junit.Before; import org.onap.dmaap.datarouter.provisioning.utils.DB; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; import java.util.Properties; -import java.util.Scanner; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; @@ -46,7 +40,6 @@ import static org.mockito.Mockito.when; public class DrServletTestBase { - @Before public void setUp() throws Exception { Properties props = new Properties(); @@ -61,7 +54,7 @@ public class DrServletTestBase { FieldUtils.writeDeclaredStaticField(BaseServlet.class, "synctask", synchronizerTask, true); } - public ListAppender setTestLogger(Class c) { + ListAppender setTestLogger(Class c) { Logger logger = (Logger) LoggerFactory.getLogger(c); ListAppender listAppender = new ListAppender<>(); listAppender.start(); @@ -69,7 +62,7 @@ public class DrServletTestBase { return listAppender; } - public void verifyEnteringExitCalled(ListAppender listAppender) { + void verifyEnteringExitCalled(ListAppender listAppender) { assertEquals("EELF0004I Entering data router provisioning component with RequestId and InvocationId", listAppender.list.get(0).getMessage()); assertEquals("EELF0005I Exiting data router provisioning component with RequestId and InvocationId", listAppender.list.get(2).getMessage()); assertEquals(3, listAppender.list.size()); diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/FeedServletTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/FeedServletTest.java index f042e11d..f4eac05f 100755 --- a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/FeedServletTest.java +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/FeedServletTest.java @@ -71,7 +71,7 @@ public class FeedServletTest extends DrServletTestBase { private static EntityManager em; private DB db; - ListAppender listAppender; + private ListAppender listAppender; @BeforeClass public static void init() { @@ -120,8 +120,7 @@ public class FeedServletTest extends DrServletTestBase { @Test - public void Given_Request_Is_HTTP_DELETE_And_Path_Header_Is_Not_Set_In_Request_With_Valid_Path_Then_Bad_Request_Response_Is_Generated() - throws Exception { + public void Given_Request_Is_HTTP_DELETE_And_Path_Header_Is_Not_Set_In_Request_With_Valid_Path_Then_Bad_Request_Response_Is_Generated() throws Exception { when(request.getPathInfo()).thenReturn(null); feedServlet.doDelete(request, response); verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); @@ -129,8 +128,7 @@ public class FeedServletTest extends DrServletTestBase { @Test - public void Given_Request_Is_HTTP_DELETE_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() - throws Exception { + public void Given_Request_Is_HTTP_DELETE_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { when(request.getPathInfo()).thenReturn("/123"); feedServlet.doDelete(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); @@ -138,13 +136,28 @@ public class FeedServletTest extends DrServletTestBase { @Test - public void Given_Request_Is_HTTP_DELETE_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() - throws Exception { + public void Given_Request_Is_HTTP_DELETE_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { setAuthoriserToReturnRequestNotAuthorized(); feedServlet.doDelete(request, response); verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } + @Test + public void Given_Request_Is_HTTP_DELETE_And_AAF_Feed_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); + feedServlet.doDelete(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access to permission")); + } + + @Test + public void Given_Request_Is_HTTP_DELETE_And_AAF_Feed_With_Permissions_Then_A_NO_CONTENT_Response_Is_Generated() { + when(request.getPathInfo()).thenReturn("/3"); + when(request.isUserInRole("org.onap.dmaap-dr.feed|*|delete")).thenReturn(true); + feedServlet.doDelete(request, response); + verify(response).setStatus(eq(HttpServletResponse.SC_NO_CONTENT)); + verifyEnteringExitCalled(listAppender); + } + @Test public void Given_Request_Is_HTTP_DELETE_And_Delete_On_Database_Fails_An_Internal_Server_Error_Is_Reported() @@ -161,8 +174,7 @@ public class FeedServletTest extends DrServletTestBase { @Test - public void Given_Request_Is_HTTP_DELETE_And_Delete_On_Database_Succeeds_A_NO_CONTENT_Response_Is_Generated() - throws Exception { + public void Given_Request_Is_HTTP_DELETE_And_Delete_On_Database_Succeeds_A_NO_CONTENT_Response_Is_Generated() throws Exception { feedServlet.doDelete(request, response); verify(response).setStatus(eq(HttpServletResponse.SC_NO_CONTENT)); reinsertFeedIntoDb(); @@ -209,6 +221,7 @@ public class FeedServletTest extends DrServletTestBase { public void Given_Request_Is_HTTP_GET_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { setAuthoriserToReturnRequestNotAuthorized(); + when(request.getPathInfo()).thenReturn("/2"); feedServlet.doGet(request, response); verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } @@ -218,6 +231,7 @@ public class FeedServletTest extends DrServletTestBase { public void Given_Request_Is_HTTP_GET_And_Request_Succeeds() throws Exception { ServletOutputStream outStream = mock(ServletOutputStream.class); when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/2"); feedServlet.doGet(request, response); verify(response).setStatus(eq(HttpServletResponse.SC_OK)); verifyEnteringExitCalled(listAppender); @@ -264,9 +278,9 @@ public class FeedServletTest extends DrServletTestBase { throws Exception { when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.feed-fail; version=2.0"); when(request.getContentType()).thenReturn("stub_contentType"); + when(request.getPathInfo()).thenReturn("/2"); feedServlet.doPut(request, response); - verify(response) - .sendError(eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), argThat(notNullValue(String.class))); } @Test @@ -274,12 +288,19 @@ public class FeedServletTest extends DrServletTestBase { throws Exception { ServletInputStream inStream = mock(ServletInputStream.class); when(request.getInputStream()).thenReturn(inStream); + when(request.getPathInfo()).thenReturn("/2"); + FeedServlet feedServlet = new FeedServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + return null; + } + }; feedServlet.doPut(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), contains("Badly formed JSON")); } @Test public void Given_Request_Is_HTTP_PUT_And_Request_Contains_Invalid_JSON_Then_Bad_Request_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { return new JSONObject(); @@ -292,6 +313,7 @@ public class FeedServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_PUT_And_Feed_Change_Is_Not_Publisher_Who_Requested_Feed_Bad_Request_Response_Is_Generated() throws Exception { when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn(null); + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -302,13 +324,13 @@ public class FeedServletTest extends DrServletTestBase { return jo; } }; - feedServlet.doPut(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), contains("must be modified by the same publisher")); } @Test public void Given_Request_Is_HTTP_PUT_And_Feed_Name_Change_is_Requested_Bad_Request_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -320,52 +342,99 @@ public class FeedServletTest extends DrServletTestBase { } }; feedServlet.doPut(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), contains("name of the feed may not be updated")); } @Test public void Given_Request_Is_HTTP_PUT_And_Feed_Version_Change_is_Requested_Bad_Request_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); - jo.put("name", "stub_name"); - jo.put("version", "2.0"); + jo.put("name", "AafFeed"); + jo.put("version", "v0.2"); jo.put("authorization", JSObject); return jo; } }; feedServlet.doPut(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), contains("version of the feed may not be updated")); } @Test public void Given_Request_Is_HTTP_PUT_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { + setAuthoriserToReturnRequestNotAuthorized(); + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); - jo.put("name", "Feed1"); + jo.put("name", "AafFeed"); jo.put("version", "v0.1"); jo.put("authorization", JSObject); return jo; } }; - setAuthoriserToReturnRequestNotAuthorized(); feedServlet.doPut(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("Policy Engine disallows access")); } @Test - public void Given_Request_Is_HTTP_PUT_And_Change_On_Feeds_Fails_An_Internal_Server_Error_Response_Is_Generated() throws Exception { + public void Given_Request_Is_HTTP_PUT_And_AAF_Feed_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); + JSONObject JSObject = buildRequestJsonObject(); + FeedServlet feedServlet = new FeedServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "AafFeed"); + jo.put("version", "v0.1"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "https://aaf-onap-test.osaaf.org:8095"); + return jo; + } + }; + feedServlet.doPut(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access to permission")); + } + + @Test + public void Given_Request_Is_HTTP_PUT_And_AAF_Feed_With_Permissions_Then_STATUS_OK__Response_Is_Generated() throws Exception { ServletOutputStream outStream = mock(ServletOutputStream.class); when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/2"); + when(request.isUserInRole("org.onap.dmaap-dr.feed|*|edit")).thenReturn(true); + JSONObject JSObject = buildRequestJsonObject(); + FeedServlet feedServlet = new FeedServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "AafFeed"); + jo.put("version", "v0.1"); + jo.put("authorization", JSObject); + jo.put("aaf_instance", "*"); + return jo; + } + @Override + protected boolean doUpdate(Updateable bean) { + return true; + } + + }; + feedServlet.doPut(request, response); + verify(response).setStatus(eq(HttpServletResponse.SC_OK)); + verifyEnteringExitCalled(listAppender); + } + @Test + public void Given_Request_Is_HTTP_PUT_And_Change_On_Feeds_Fails_An_Internal_Server_Error_Response_Is_Generated() throws Exception { + ServletOutputStream outStream = mock(ServletOutputStream.class); + when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); - jo.put("name", "Feed1"); + jo.put("name", "AafFeed"); jo.put("version", "v0.1"); jo.put("authorization", JSObject); return jo; @@ -384,15 +453,20 @@ public class FeedServletTest extends DrServletTestBase { public void Given_Request_Is_HTTP_PUT_And_Change_On_Feeds_Suceeds_A_STATUS_OK_Response_Is_Generated() throws Exception { ServletOutputStream outStream = mock(ServletOutputStream.class); when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/2"); JSONObject JSObject = buildRequestJsonObject(); FeedServlet feedServlet = new FeedServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { JSONObject jo = new JSONObject(); - jo.put("name", "Feed1"); + jo.put("name", "AafFeed"); jo.put("version", "v0.1"); jo.put("authorization", JSObject); return jo; } + @Override + protected boolean doUpdate(Updateable bean) { + return true; + } }; feedServlet.doPut(request, response); @@ -427,11 +501,9 @@ public class FeedServletTest extends DrServletTestBase { private void setUpValidSecurityOnHttpRequest() throws Exception { when(request.isSecure()).thenReturn(true); - Set authAddressesAndNetworks = new HashSet(); + Set authAddressesAndNetworks = new HashSet<>(); authAddressesAndNetworks.add(("127.0.0.1")); - FieldUtils - .writeDeclaredStaticField(BaseServlet.class, "authorizedAddressesAndNetworks", authAddressesAndNetworks, - true); + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "authorizedAddressesAndNetworks", authAddressesAndNetworks,true); FieldUtils.writeDeclaredStaticField(BaseServlet.class, "requireCert", false, true); } diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscribeServletTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscribeServletTest.java index 0b5c23fe..b867c672 100755 --- a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscribeServletTest.java +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscribeServletTest.java @@ -27,19 +27,24 @@ import ch.qos.logback.core.read.ListAppender; import org.apache.commons.lang3.reflect.FieldUtils; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.onap.dmaap.datarouter.authz.AuthorizationResponse; import org.onap.dmaap.datarouter.authz.Authorizer; -import org.onap.dmaap.datarouter.provisioning.beans.Feed; import org.onap.dmaap.datarouter.provisioning.beans.Insertable; import org.onap.dmaap.datarouter.provisioning.beans.Subscription; +import org.onap.dmaap.datarouter.provisioning.utils.DB; import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -54,20 +59,39 @@ import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER; @RunWith(PowerMockRunner.class) -@SuppressStaticInitializationFor({"org.onap.dmaap.datarouter.provisioning.beans.Feed", "org.onap.dmaap.datarouter.provisioning.beans.Subscription"}) +@PrepareForTest(Subscription.class) public class SubscribeServletTest extends DrServletTestBase { private static SubscribeServlet subscribeServlet; + private static EntityManagerFactory emf; + private static EntityManager em; + private DB db; @Mock private HttpServletRequest request; @Mock private HttpServletResponse response; - ListAppender listAppender; + private ListAppender listAppender; + + @BeforeClass + public static void init() { + emf = Persistence.createEntityManagerFactory("dr-unit-tests"); + em = emf.createEntityManager(); + System.setProperty( + "org.onap.dmaap.datarouter.provserver.properties", + "src/test/resources/h2Database.properties"); + } + + @AfterClass + public static void tearDownClass() { + em.clear(); + em.close(); + emf.close(); + } @Before public void setUp() throws Exception { - super.setUp(); + db = new DB(); listAppender = setTestLogger(SubscribeServlet.class); subscribeServlet = new SubscribeServlet(); setAuthoriserToReturnRequestIsAuthorized(); @@ -110,26 +134,18 @@ public class SubscribeServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_GET_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - setFeedToReturnInvalidFeedIdSupplied(); + when(request.getPathInfo()).thenReturn("/123"); subscribeServlet.doGet(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); } - - @Test - public void Given_Request_Is_HTTP_GET_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { - setAuthoriserToReturnRequestNotAuthorized(); - subscribeServlet.doGet(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); - } - - @Test public void Given_Request_Is_HTTP_GET_And_Request_Succeeds() throws Exception { ServletOutputStream outStream = mock(ServletOutputStream.class); when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/1"); PowerMockito.mockStatic(Subscription.class); - List list = new ArrayList(); + List list = new ArrayList<>(); list.add("{}"); PowerMockito.when(Subscription.getSubscriptionUrlList(anyInt())).thenReturn(list); subscribeServlet.doGet(request, response); @@ -171,7 +187,7 @@ public class SubscribeServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_POST_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - setFeedToReturnInvalidFeedIdSupplied(); + when(request.getPathInfo()).thenReturn("/123"); subscribeServlet.doPost(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); } @@ -179,41 +195,107 @@ public class SubscribeServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_POST_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { setAuthoriserToReturnRequestNotAuthorized(); + when(request.getPathInfo()).thenReturn("/1"); + JSONObject JSObject = buildRequestJsonObject(); + SubscribeServlet subscribeServlet = new SubscribeServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("sync", false); + return jo; + } + @Override + protected boolean doInsert(Insertable bean) { + return false; + } + }; subscribeServlet.doPost(request, response); verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } @Test - public void Given_Request_Is_HTTP_POST_And_Content_Header_Is_Not_Supported_Type_Then_Unsupported_Media_Type_Response_Is_Generated() throws Exception { - when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.feed; version=1.1"); - when(request.getContentType()).thenReturn("stub_contentType"); + public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_Legacy_Feed_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/1"); + JSONObject JSObject = buildRequestJsonObject(); + SubscribeServlet subscribeServlet = new SubscribeServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "*"); + jo.put("follow_redirect", false); + jo.put("sync", false); + return jo; + } + @Override + protected boolean doInsert(Insertable bean) { + return false; + } + }; subscribeServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF Subscriber can not be added to legacy Feed")); } @Test - public void Given_Request_Is_HTTP_POST_And_Request_Contains_Badly_Formed_JSON_Then_Bad_Request_Response_Is_Generated() throws Exception { + public void Given_Request_Is_HTTP_POST_And_Legacy_Subscriber_Added_To_AAF_Feed_And_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { + setAuthoriserToReturnRequestNotAuthorized(); + when(request.getPathInfo()).thenReturn("/2"); + JSONObject JSObject = buildRequestJsonObject(); + SubscribeServlet subscribeServlet = new SubscribeServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); + jo.put("sync", false); + return jo; + } + }; subscribeServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("Policy Engine disallows access.")); } @Test - public void Given_Request_Is_HTTP_POST_And_Active_Feeds_Equals_Max_Feeds_Then_Bad_Request_Response_Is_Generated() throws Exception { - FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxSubs", 0, true); + public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_AAF_Feed_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); + JSONObject JSObject = buildRequestJsonObject(); SubscribeServlet subscribeServlet = new SubscribeServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { - return new JSONObject(); + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "*"); + jo.put("follow_redirect", false); + jo.put("sync", false); + return jo; } }; subscribeServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_CONFLICT), argThat(notNullValue(String.class))); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access to permission")); } @Test - public void Given_Request_Is_HTTP_POST_And_POST_Fails_Bad_Request_Response_Is_Generated() throws Exception { + public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_AAF_Feed_With_Permissions_Then_OK_Response_Is_Generated() throws Exception { + ServletOutputStream outStream = mock(ServletOutputStream.class); + when(response.getOutputStream()).thenReturn(outStream); + when(request.getPathInfo()).thenReturn("/2"); + when(request.isUserInRole("org.onap.dmaap-dr.feed|*|approveSub")).thenReturn(true); PowerMockito.mockStatic(Subscription.class); - PowerMockito.when(Subscription.getSubscriptionMatching(mock(Subscription.class))).thenReturn(null); - PowerMockito.when(Subscription.countActiveSubscriptions()).thenReturn(0); + PowerMockito.when(Subscription.getSubscriptionMatching(new Subscription())).thenReturn(null); JSONObject JSObject = buildRequestJsonObject(); SubscribeServlet subscribeServlet = new SubscribeServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -223,26 +305,56 @@ public class SubscribeServletTest extends DrServletTestBase { jo.put("metadataOnly", true); jo.put("suspend", true); jo.put("delivery", JSObject); + jo.put("aaf_instance", "*"); + jo.put("follow_redirect", false); jo.put("sync", false); return jo; } @Override protected boolean doInsert(Insertable bean) { - return false; + return true; } }; subscribeServlet.doPost(request, response); - verify(response).sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), argThat(notNullValue(String.class))); + verify(response).setStatus(eq(HttpServletResponse.SC_CREATED)); + verifyEnteringExitCalled(listAppender); } + @Test + public void Given_Request_Is_HTTP_POST_And_Content_Header_Is_Not_Supported_Type_Then_Unsupported_Media_Type_Response_Is_Generated() throws Exception { + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.feed; version=1.1"); + when(request.getContentType()).thenReturn("stub_contentType"); + when(request.getPathInfo()).thenReturn("/1"); + subscribeServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), argThat(notNullValue(String.class))); + } @Test - public void Given_Request_Is_HTTP_POST_And_Change_On_Feeds_Succeeds_A_STATUS_OK_Response_Is_Generated() throws Exception { - ServletOutputStream outStream = mock(ServletOutputStream.class); - when(response.getOutputStream()).thenReturn(outStream); + public void Given_Request_Is_HTTP_POST_And_Request_Contains_Badly_Formed_JSON_Then_Bad_Request_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/1"); + subscribeServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + } + + @Test + public void Given_Request_Is_HTTP_POST_And_Active_Feeds_Equals_Max_Feeds_Then_Bad_Request_Response_Is_Generated() throws Exception { + FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxSubs", 0, true); + when(request.getPathInfo()).thenReturn("/1"); + SubscribeServlet subscribeServlet = new SubscribeServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + return new JSONObject(); + } + }; + subscribeServlet.doPost(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_CONFLICT), argThat(notNullValue(String.class))); + } + + @Test + public void Given_Request_Is_HTTP_POST_And_POST_Fails_Bad_Request_Response_Is_Generated() throws Exception { + when(request.getPathInfo()).thenReturn("/2"); PowerMockito.mockStatic(Subscription.class); - PowerMockito.when(Subscription.getSubscriptionMatching(mock(Subscription.class))).thenReturn(null); + PowerMockito.when(Subscription.getSubscriptionMatching(new Subscription())).thenReturn(null); JSONObject JSObject = buildRequestJsonObject(); SubscribeServlet subscribeServlet = new SubscribeServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -252,21 +364,21 @@ public class SubscribeServletTest extends DrServletTestBase { jo.put("metadataOnly", true); jo.put("suspend", true); jo.put("delivery", JSObject); - jo.put("sync", true); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); + jo.put("sync", false); return jo; } @Override protected boolean doInsert(Insertable bean) { - return true; + return false; } }; subscribeServlet.doPost(request, response); - verify(response).setStatus(eq(HttpServletResponse.SC_CREATED)); - verifyEnteringExitCalled(listAppender); + verify(response).sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), argThat(notNullValue(String.class))); } - @NotNull private JSONObject buildRequestJsonObject() { JSONObject JSObject = new JSONObject(); @@ -279,7 +391,7 @@ public class SubscribeServletTest extends DrServletTestBase { private void setUpValidSecurityOnHttpRequest() throws Exception { when(request.isSecure()).thenReturn(true); - Set authAddressesAndNetworks = new HashSet(); + Set authAddressesAndNetworks = new HashSet<>(); authAddressesAndNetworks.add(("127.0.0.1")); FieldUtils.writeDeclaredStaticField(BaseServlet.class, "authorizedAddressesAndNetworks", authAddressesAndNetworks, true); FieldUtils.writeDeclaredStaticField(BaseServlet.class, "requireCert", false, true); @@ -290,27 +402,6 @@ public class SubscribeServletTest extends DrServletTestBase { when(request.getHeader(BEHALF_HEADER)).thenReturn(headerValue); } - private void setValidPathInfoInHttpHeader() { - when(request.getPathInfo()).thenReturn("/123"); - } - - private void setFeedToReturnInvalidFeedIdSupplied() { - PowerMockito.mockStatic(Feed.class); - PowerMockito.when(Feed.getFeedById(anyInt())).thenReturn(null); - } - - private void setFeedToReturnValidFeedForSuppliedId() { - PowerMockito.mockStatic(Feed.class); - Feed feed = mock(Feed.class); - PowerMockito.when(Feed.getFeedById(anyInt())).thenReturn(feed); - when(feed.isDeleted()).thenReturn(false); - when(feed.asJSONObject(true)).thenReturn(mock(JSONObject.class)); - when(feed.getPublisher()).thenReturn("Stub_Value"); - when(feed.getName()).thenReturn("stub_name"); - when(feed.getVersion()).thenReturn("1.0"); - when(feed.asLimitedJSONObject()).thenReturn(mock(JSONObject.class)); - } - private void setAuthoriserToReturnRequestNotAuthorized() throws IllegalAccessException { AuthorizationResponse authResponse = mock(AuthorizationResponse.class); Authorizer authorizer = mock(Authorizer.class); @@ -335,8 +426,6 @@ public class SubscribeServletTest extends DrServletTestBase { private void setupValidAuthorisedRequest() throws Exception { setUpValidSecurityOnHttpRequest(); setBehalfHeader("Stub_Value"); - setValidPathInfoInHttpHeader(); - setFeedToReturnValidFeedForSuppliedId(); } private void setUpValidContentHeadersAndJSONOnHttpRequest() { diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServletTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServletTest.java index aede69cf..a17e23e0 100755 --- a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServletTest.java +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/SubscriptionServletTest.java @@ -27,7 +27,10 @@ import ch.qos.logback.core.read.ListAppender; import org.apache.commons.lang3.reflect.FieldUtils; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; -import org.junit.*; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.onap.dmaap.datarouter.authz.AuthorizationResponse; @@ -37,6 +40,9 @@ import org.onap.dmaap.datarouter.provisioning.beans.SubDelivery; import org.onap.dmaap.datarouter.provisioning.beans.Subscription; import org.onap.dmaap.datarouter.provisioning.beans.Updateable; import org.onap.dmaap.datarouter.provisioning.utils.DB; +import org.onap.dmaap.datarouter.provisioning.utils.PasswordProcessor; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import javax.persistence.EntityManager; @@ -46,7 +52,6 @@ import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.FileNotFoundException; import java.sql.SQLException; import java.util.HashSet; import java.util.Set; @@ -57,6 +62,7 @@ import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER; @RunWith(PowerMockRunner.class) +@PrepareForTest(PasswordProcessor.class) public class SubscriptionServletTest extends DrServletTestBase { private static EntityManagerFactory emf; private static EntityManager em; @@ -72,7 +78,7 @@ public class SubscriptionServletTest extends DrServletTestBase { @Mock private HttpServletResponse response; - ListAppender listAppender; + private ListAppender listAppender; @BeforeClass public static void init() { @@ -84,7 +90,7 @@ public class SubscriptionServletTest extends DrServletTestBase { } @AfterClass - public static void tearDownClass() throws FileNotFoundException { + public static void tearDownClass() { em.clear(); em.close(); emf.close(); @@ -125,7 +131,7 @@ public class SubscriptionServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_DELETE_And_Subscription_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - when(request.getPathInfo()).thenReturn("/3"); + when(request.getPathInfo()).thenReturn("/123"); subscriptionServlet.doDelete(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); } @@ -149,11 +155,22 @@ public class SubscriptionServletTest extends DrServletTestBase { } @Test - public void Given_Request_Is_HTTP_DELETE_And_Delete_On_Database_Succeeds_A_NO_CONTENT_Response_Is_Generated() throws Exception { + public void Given_Request_Is_HTTP_DELETE_And_AAF_CADI_Is_Enabled_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + when(request.getPathInfo()).thenReturn("/2"); + subscriptionServlet.doDelete(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access")); + } + + @Test + public void Given_Request_Is_HTTP_DELETE_And_AAF_CADI_Is_Enabled_With_Permissions_Then_A_NO_CONTENT_Response_Is_Generated() throws Exception { + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + when(request.getPathInfo()).thenReturn("/2"); + when(request.isUserInRole("org.onap.dmaap-dr.sub|*|delete")).thenReturn(true); subscriptionServlet.doDelete(request, response); verify(response).setStatus(eq(HttpServletResponse.SC_NO_CONTENT)); verifyEnteringExitCalled(listAppender); - insertSubscriptionIntoDb(); + resetAafSubscriptionInDB(); } @Test @@ -180,7 +197,7 @@ public class SubscriptionServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_GET_And_Subscription_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - when(request.getPathInfo()).thenReturn("/3"); + when(request.getPathInfo()).thenReturn("/123"); subscriptionServlet.doGet(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); } @@ -225,7 +242,7 @@ public class SubscriptionServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_PUT_And_Subscription_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - when(request.getPathInfo()).thenReturn("/3"); + when(request.getPathInfo()).thenReturn("/123"); subscriptionServlet.doPut(request, response); verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); } @@ -233,10 +250,82 @@ public class SubscriptionServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_PUT_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception { setAuthoriserToReturnRequestNotAuthorized(); + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + JSONObject JSObject = buildRequestJsonObject(); + SubscriptionServlet subscriptionServlet = new SubscriptionServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); + jo.put("decompress", true); + jo.put("sync", true); + jo.put("changeowner", true); + return jo; + } + }; subscriptionServlet.doPut(request, response); verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class))); } + @Test + public void Given_Request_Is_HTTP_PUT_And_AAF_CADI_Is_Enabled_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception { + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + when(request.getPathInfo()).thenReturn("/3"); + JSONObject JSObject = buildRequestJsonObject(); + SubscriptionServlet subscriptionServlet = new SubscriptionServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "*"); + jo.put("follow_redirect", false); + jo.put("sync", true); + jo.put("changeowner", true); + return jo; + } + }; + subscriptionServlet.doPut(request, response); + verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access")); + } + + @Test + public void Given_Request_Is_HTTP_PUT_And_AAF_CADI_Is_Enabled_With_Permissions_Then_OK_Response_Is_Generated() throws Exception { + ServletOutputStream outStream = mock(ServletOutputStream.class); + when(response.getOutputStream()).thenReturn(outStream); + when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_subjectGroup"); + when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + when(request.getPathInfo()).thenReturn("/3"); + when(request.isUserInRole("org.onap.dmaap-dr.sub|*|edit")).thenReturn(true); + PowerMockito.mockStatic(PasswordProcessor.class); + JSONObject JSObject = buildRequestJsonObject(); + SubscriptionServlet subscriptionServlet = new SubscriptionServlet() { + protected JSONObject getJSONfromInput(HttpServletRequest req) { + JSONObject jo = new JSONObject(); + jo.put("name", "stub_name"); + jo.put("version", "2.0"); + jo.put("metadataOnly", true); + jo.put("suspend", true); + jo.put("delivery", JSObject); + jo.put("aaf_instance", "*"); + jo.put("follow_redirect", false); + jo.put("sync", true); + return jo; + } + }; + subscriptionServlet.doPut(request, response); + verify(response).setStatus(eq(HttpServletResponse.SC_OK)); + resetAafSubscriptionInDB(); + verifyEnteringExitCalled(listAppender); + } + @Test public void Given_Request_Is_HTTP_PUT_And_Content_Header_Is_Not_Supported_Type_Then_Unsupported_Media_Type_Response_Is_Generated() throws Exception { when(request.getContentType()).thenReturn("stub_ContentType"); @@ -281,6 +370,8 @@ public class SubscriptionServletTest extends DrServletTestBase { jo.put("privilegedSubscriber", true); jo.put("decompress", true); jo.put("delivery", JSObject); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); jo.put("subscriber", "differentSubscriber"); jo.put("sync", true); return jo; @@ -304,7 +395,9 @@ public class SubscriptionServletTest extends DrServletTestBase { jo.put("suspend", true); jo.put("privilegedSubscriber", true); jo.put("delivery", JSObject); + jo.put("aaf_instance", "legacy"); jo.put("decompress", true); + jo.put("follow_redirect", false); jo.put("sync", true); return jo; } @@ -324,6 +417,7 @@ public class SubscriptionServletTest extends DrServletTestBase { when(response.getOutputStream()).thenReturn(outStream); when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_subjectGroup"); when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0"); + PowerMockito.mockStatic(PasswordProcessor.class); JSONObject JSObject = buildRequestJsonObject(); SubscriptionServlet subscriptionServlet = new SubscriptionServlet() { protected JSONObject getJSONfromInput(HttpServletRequest req) { @@ -335,6 +429,8 @@ public class SubscriptionServletTest extends DrServletTestBase { jo.put("privilegedSubscriber", true); jo.put("decompress", true); jo.put("delivery", JSObject); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); jo.put("sync", true); jo.put("changeowner", true); return jo; @@ -370,7 +466,7 @@ public class SubscriptionServletTest extends DrServletTestBase { @Test public void Given_Request_Is_HTTP_POST_And_Subscription_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception { - when(request.getPathInfo()).thenReturn("/3"); + when(request.getPathInfo()).thenReturn("/123"); subscriptionServlet.doPost(request, response); verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); } @@ -435,6 +531,8 @@ public class SubscriptionServletTest extends DrServletTestBase { jo.put("suspend", true); jo.put("delivery", JSObject); jo.put("privilegedSubscriber", false); + jo.put("aaf_instance", "legacy"); + jo.put("follow_redirect", false); jo.put("decompress", false); jo.put("failed", false); return jo; @@ -498,8 +596,8 @@ public class SubscriptionServletTest extends DrServletTestBase { setValidPathInfoInHttpHeader(); } - private void insertSubscriptionIntoDb() throws SQLException { - Subscription subscription = new Subscription(URL, USER, PASSWORD); + private void changeSubscriptionBackToNormal() throws SQLException { + Subscription subscription = new Subscription("https://172.100.0.5", "user1", "password1"); subscription.setSubid(1); subscription.setSubscriber("user1"); subscription.setFeedid(1); @@ -510,22 +608,23 @@ public class SubscriptionServletTest extends DrServletTestBase { subscription.setSuspended(false); subscription.setPrivilegedSubscriber(false); subscription.setDecompress(false); - subscription.doInsert(db.getConnection()); + subscription.changeOwnerShip(); + subscription.doUpdate(db.getConnection()); } - private void changeSubscriptionBackToNormal() throws SQLException { - Subscription subscription = new Subscription("https://172.100.0.5", "user1", "password1"); - subscription.setSubid(1); - subscription.setSubscriber("user1"); + private void resetAafSubscriptionInDB() throws SQLException { + Subscription subscription = new Subscription("https://172.100.0.5:8080", "user2", "password2"); + subscription.setSubid(2); + subscription.setSubscriber("user2"); subscription.setFeedid(1); SubDelivery subDelivery = new SubDelivery(URL, USER, PASSWORD, true); subscription.setDelivery(subDelivery); subscription.setGroupid(1); subscription.setMetadataOnly(false); subscription.setSuspended(false); - subscription.setPrivilegedSubscriber(false); + subscription.setAafInstance("https://aaf-onap-test.osaaf.org:8095"); subscription.setDecompress(false); - subscription.changeOwnerShip(); + subscription.setPrivilegedSubscriber(false); subscription.doUpdate(db.getConnection()); } } \ No newline at end of file diff --git a/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilterTest.java b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilterTest.java new file mode 100644 index 00000000..5e24c5a8 --- /dev/null +++ b/datarouter-prov/src/test/java/org/onap/dmaap/datarouter/provisioning/utils/DRProvCadiFilterTest.java @@ -0,0 +1,269 @@ +/**- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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.dmaap.datarouter.provisioning.utils; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.dmaap.datarouter.provisioning.BaseServlet; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.api.support.membermodification.MemberMatcher; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.*; +import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({CadiFilter.class}) +public class DRProvCadiFilterTest { + + @Mock + private PropAccess access; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain chain; + + private DRProvCadiFilter cadiFilter; + + + private static EntityManagerFactory emf; + private static EntityManager em; + + + @BeforeClass + public static void init() { + emf = Persistence.createEntityManagerFactory("dr-unit-tests"); + em = emf.createEntityManager(); + System.setProperty( + "org.onap.dmaap.datarouter.provserver.properties", + "src/test/resources/h2Database.properties"); + } + + @Before + public void setUp() throws Exception { + cadiFilter = new DRProvCadiFilter(false, access); + } + + @Test + public void Given_doFilter_Called_And_Path_Contains_subs_And_SubId_Is_Incorrectly_Set_Then_Not_Found_Response_Returned() throws Exception{ + setRequestMocking("PUT", "subs"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + } + + @Test + public void Given_doFilter_called_And_Path_Contains_subs_And_Is_AAF_Subscriber_then_call_Super_doFilter() throws Exception{ + setRequestMocking("PUT", "subs"); + when(request.getPathInfo()).thenReturn("/2"); + PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(CadiFilter.class)); + cadiFilter.doFilter(request, response, chain); + verify(chain, times(0)).doFilter(request, response); + } + + @Test + public void Given_doFilter_called_And_Path_Contains_subs_And_Is_Not_AAF_Subscriber_then_call_chain_doFilter() throws Exception{ + setRequestMocking("PUT", "subs"); + when(request.getPathInfo()).thenReturn("/5"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + } + + @Test + public void Given_doFilter_called_And_FeedId_Is_Incorrectly_Set_Then_Not_Found_Response_Returned () throws Exception{ + setRequestMocking("PUT", "feeds"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + } + + @Test + public void Given_doFilter_called_And_FeedId_Is_Correctly_Set_And_Is_AAF_Feed_Then_Call_Super_doFilter() throws Exception{ + setRequestMocking("PUT", "feeds"); + when(request.getPathInfo()).thenReturn("/2"); + PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(CadiFilter.class)); + cadiFilter.doFilter(request, response, chain); + verify(chain, times(0)).doFilter(request, response); + } + + @Test + public void Given_doFilter_called_And_FeedId_Is_Correctly_Set_And_Is_Not_AAF_Feed_then_call_chain_doFilter() throws Exception{ + setRequestMocking("PUT", "feeds"); + when(request.getPathInfo()).thenReturn("/1"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + } + + @Test + public void Given_doFilter_called_With_Get_Then_call_chain_doFilter() throws Exception{ + setRequestMocking("GET", "feeds"); + when(request.getPathInfo()).thenReturn("/5"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + } + + + @Test + public void Given_doFilter_called_With_POST_Then_call_chain_doFilter() throws Exception{ + setRequestMocking("POST", "subscribe"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + + } + + @Test + public void Given_doFilter_called_With_POST_And_FeedId_Is_Incorrectly_Set_Then_Not_Found_Response_Returned() throws Exception{ + setRequestMocking("POST", "subscribe"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Exclude_AAF_Is_NULL_Then_Bad_Request_Response_Returned() throws Exception{ + setRequestMocking("POST", "subscribe"); + when(request.getPathInfo()).thenReturn("/2"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Exclude_AAF_Equals_True_Then_Call_Chain_doFilter() throws Exception{ + setRequestMocking("POST", "subscribe"); + when(request.getPathInfo()).thenReturn("/2"); + when(request.getHeader("X-EXCLUDE-AAF")).thenReturn("true"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Exclude_AAF_Equals_False_Then_Call_Super_doFilter() throws Exception{ + setRequestMocking("POST", "subscribe"); + when(request.getPathInfo()).thenReturn("/2"); + when(request.getHeader("X-EXCLUDE-AAF")).thenReturn("false"); + PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(CadiFilter.class)); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(0)).doFilter(request, response); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Is_Not_AAF_Exclude_AAF_Equals_Then_Call_Chain_doFilter() throws Exception{ + setRequestMocking("POST", "subscribe"); + when(request.getPathInfo()).thenReturn("/5"); + when(request.getHeader("X-EXCLUDE-AAF")).thenReturn("false"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Path_Not_Includes_subscribe_And_Exclude_AAF_Is_NULL_Then_Bad_Request_Response_Returned() throws Exception{ + setRequestMocking("POST", "other"); + when(request.getPathInfo()).thenReturn("/5"); + + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class))); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Path_Not_Includes_subscribe_And_Exclude_AAF_Equals_True_Then_Call_Chain_doFilter() throws Exception{ + setRequestMocking("POST", "other"); + when(request.getPathInfo()).thenReturn("/5"); + when(request.getHeader("X-EXCLUDE-AAF")).thenReturn("true"); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(1)).doFilter(request, response); + + } + + @Test + public void Given_doFilter_called_With_POST_And_Path_Not_Includes_subscribe_And_Exclude_AAF_Equals_False_Then_Call_Super_doFilter() throws Exception{ + setRequestMocking("POST", "other"); + when(request.getPathInfo()).thenReturn("/5"); + when(request.getHeader("X-EXCLUDE-AAF")).thenReturn("false"); + PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(CadiFilter.class)); + + cadiFilter.doFilter(request, response, chain); + verify(chain, times(0)).doFilter(request, response); + + } + + @Test + public void Given_doFilter_Called_And_Path_Contains_subs_And_getSubId_Throws_NumberFormatException_then_Not_Found_response_returned() throws Exception{ + setRequestMocking("PUT", "subs"); + when(request.getPathInfo()).thenReturn("5/"); + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + + } + + @Test + public void Given_doFilter_called_And_FeedId_Throws_Set_Then_Not_Found_Response_Returned () throws Exception{ + setRequestMocking("PUT", "feeds"); + when(request.getPathInfo()).thenReturn("//5"); + cadiFilter.doFilter(request, response, chain); + verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class))); + } + + private void setRequestMocking(String method, String servletPath) + { + when(request.getRemoteAddr()).thenReturn(null); + when(request.getHeader(BEHALF_HEADER)).thenReturn(null); + when(request.getAttribute(BaseServlet.CERT_ATTRIBUTE)).thenReturn(null); + when(request.getMethod()).thenReturn(method); + when(request.getServletPath()).thenReturn(servletPath); + } + + } diff --git a/datarouter-prov/src/test/resources/create.sql b/datarouter-prov/src/test/resources/create.sql index 9412adf2..1fb30c90 100755 --- a/datarouter-prov/src/test/resources/create.sql +++ b/datarouter-prov/src/test/resources/create.sql @@ -2,7 +2,7 @@ CREATE TABLE FEEDS ( FEEDID INT UNSIGNED NOT NULL PRIMARY KEY, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, NAME VARCHAR(255) NOT NULL, - VERSION VARCHAR(20) NOT NULL, + VERSION VARCHAR(20) NULL, DESCRIPTION VARCHAR(1000), BUSINESS_DESCRIPTION VARCHAR(1000) DEFAULT NULL, AUTH_CLASS VARCHAR(32) NOT NULL, @@ -14,13 +14,14 @@ CREATE TABLE FEEDS ( DELETED BOOLEAN DEFAULT FALSE, LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + AAF_INSTANCE VARCHAR(256) ); CREATE TABLE FEED_ENDPOINT_IDS ( FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20) NOT NULL, - PASSWORD VARCHAR(32) NOT NULL + USERID VARCHAR(60) NOT NULL, + PASSWORD VARCHAR(100) NOT NULL ); CREATE TABLE FEED_ENDPOINT_ADDRS ( @@ -33,8 +34,9 @@ CREATE TABLE SUBSCRIPTIONS ( FEEDID INT UNSIGNED NOT NULL, GROUPID INT(10) UNSIGNED NOT NULL DEFAULT 0, DELIVERY_URL VARCHAR(256), - DELIVERY_USER VARCHAR(20), - DELIVERY_PASSWORD VARCHAR(32), + FOLLOW_REDIRECTS TINYINT(1) NOT NULL DEFAULT 0, + DELIVERY_USER VARCHAR(60), + DELIVERY_PASSWORD VARCHAR(100), DELIVERY_USE100 BOOLEAN DEFAULT FALSE, METADATA_ONLY BOOLEAN DEFAULT FALSE, SUBSCRIBER VARCHAR(8) NOT NULL, @@ -43,8 +45,9 @@ CREATE TABLE SUBSCRIPTIONS ( LAST_MOD TIMESTAMP DEFAULT CURRENT_TIMESTAMP, SUSPENDED BOOLEAN DEFAULT FALSE, PRIVILEGED_SUBSCRIBER BOOLEAN DEFAULT FALSE, + CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP, DECOMPRESS BOOLEAN DEFAULT FALSE, - CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP + AAF_INSTANCE VARCHAR(256) ); @@ -87,7 +90,7 @@ CREATE TABLE LOG_RECORDS ( CREATE TABLE INGRESS_ROUTES ( SEQUENCE INT UNSIGNED NOT NULL, FEEDID INT UNSIGNED NOT NULL, - USERID VARCHAR(20), + USERID VARCHAR(50), SUBNET VARCHAR(44), NODESET INT UNSIGNED NOT NULL ); @@ -136,7 +139,7 @@ INSERT INTO PARAMETERS VALUES ('DELIVERY_MAX_RETRY_INTERVAL', '3600'), ('DELIVERY_FILE_PROCESS_INTERVAL', '600'), ('DELIVERY_RETRY_RATIO', '2'), - ('LOGROLL_INTERVAL', '300'), + ('LOGROLL_INTERVAL', '30'), ('PROV_AUTH_ADDRESSES', 'dmaap-dr-prov|dmaap-dr-node'), ('PROV_AUTH_SUBJECTS', ''), ('PROV_MAXFEED_COUNT', '10000'), @@ -149,11 +152,17 @@ INSERT INTO PARAMETERS VALUES INSERT INTO GROUPS(GROUPID, AUTHID, NAME, DESCRIPTION, CLASSIFICATION, MEMBERS) VALUES (1, 'Basic dXNlcjE6cGFzc3dvcmQx', 'Group1', 'First Group for testing', 'Class1', 'Member1'); -INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, PRIVILEGED_SUBSCRIBER, DECOMPRESS) -VALUES (1, 1, 'https://172.100.0.5:8080', 'user1', 'password1', true, false, 'user1', false, 1, false, false); +INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, FOLLOW_REDIRECTS, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, PRIVILEGED_SUBSCRIBER, AAF_INSTANCE, DECOMPRESS) +VALUES (1, 1, 'https://172.100.0.5:8080', 0, 'user1', 'password1', true, false, 'user1', false, 1, false, 'legacy', false); -INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, DELIVERY_USER, DELIVERY_PASSWORD, SUBSCRIBER, SELF_LINK, LOG_LINK) -VALUES (23, 1, 'http://delivery_url', 'user1', 'somepassword', 'sub123', 'selflink', 'loglink'); +INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, FOLLOW_REDIRECTS, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, AAF_INSTANCE) +VALUES (2, 1, 'https://172.100.0.5:8080', 0, 'user2', 'password2', true, true, 'subsc2', false, 1, '*'); + +INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, FOLLOW_REDIRECTS, DELIVERY_USER, DELIVERY_PASSWORD, DELIVERY_USE100, METADATA_ONLY, SUBSCRIBER, SUSPENDED, GROUPID, AAF_INSTANCE) +VALUES (3, 1, 'https://172.100.0.5:8080', 0, 'user3', 'password3', true, true, 'subsc3', false, 1, '*'); + +INSERT INTO SUBSCRIPTIONS(SUBID, FEEDID, DELIVERY_URL, DELIVERY_USER, DELIVERY_PASSWORD, SUBSCRIBER, SELF_LINK, LOG_LINK, AAF_INSTANCE) +VALUES (23, 1, 'http://delivery_url', 'user1', 'somepassword', 'sub123', 'selflink', 'loglink', 'legacy'); INSERT INTO FEED_ENDPOINT_IDS(FEEDID, USERID, PASSWORD) VALUES (1, 'USER', 'PASSWORD'); @@ -164,6 +173,12 @@ VALUES (1, '172.0.0.1'); INSERT INTO FEEDS(FEEDID, GROUPID, NAME, VERSION, DESCRIPTION, BUSINESS_DESCRIPTION, AUTH_CLASS, PUBLISHER, SELF_LINK, PUBLISH_LINK, SUBSCRIBE_LINK, LOG_LINK) VALUES (1, 1,'Feed1','v0.1', 'First Feed for testing', 'First Feed for testing', 'auth_class', 'pub','self_link','publish_link','subscribe_link','log_link'); +INSERT INTO FEEDS(FEEDID, GROUPID, NAME, VERSION, DESCRIPTION, BUSINESS_DESCRIPTION, AUTH_CLASS, PUBLISHER, SELF_LINK, PUBLISH_LINK, SUBSCRIBE_LINK, LOG_LINK, AAF_INSTANCE) +VALUES (2, 1,'AafFeed','v0.1', 'AAF Feed for testing', 'AAF Feed for testing', 'auth_class', 'pub','self_link','publish_link','subscribe_link','log_link','*'); + +INSERT INTO FEEDS(FEEDID, GROUPID, NAME, VERSION, DESCRIPTION, BUSINESS_DESCRIPTION, AUTH_CLASS, PUBLISHER, SELF_LINK, PUBLISH_LINK, SUBSCRIBE_LINK, LOG_LINK, AAF_INSTANCE) +VALUES (3, 1,'DeleteableAafFeed','v0.1', 'AAF Feed3 for testing', 'AAF Feed3 for testing', 'auth_class', 'pub','self_link','publish_link','subscribe_link','log_link','*'); + insert into INGRESS_ROUTES(SEQUENCE, FEEDID , USERID, SUBNET, NODESET) VALUES (1,1,'user',null,2); diff --git a/datarouter-prov/src/test/resources/h2Database.properties b/datarouter-prov/src/test/resources/h2Database.properties index a7ed3fa0..fee9c688 100755 --- a/datarouter-prov/src/test/resources/h2Database.properties +++ b/datarouter-prov/src/test/resources/h2Database.properties @@ -28,4 +28,5 @@ org.onap.dmaap.datarouter.provserver.isaddressauthenabled = true org.onap.dmaap.datarouter.provserver.https.relaxation = false org.onap.dmaap.datarouter.provserver.accesslog.dir = unit-test-logs org.onap.dmaap.datarouter.provserver.spooldir = unit-test-logs/spool -org.onap.dmaap.datarouter.provserver.localhost = 127.0.0.1 \ No newline at end of file +org.onap.dmaap.datarouter.provserver.localhost = 127.0.0.1 +org.onap.dmaap.datarouter.provserver.passwordencryption = PasswordEncryptionKey#@$%^&1234# \ No newline at end of file diff --git a/pom.xml b/pom.xml index a515dc5d..3de167a2 100755 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ 1.4.10 26.0-jre 1.2.3 + 2.1.10 /content/repositories/snapshots/ /content/repositories/releases/ /content/repositories/staging/ -- 2.16.6