3993b4df6e7de9c0a4bccdc1d2f9a7bed66f95e5
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / BaseServlet.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * * ===========================================================================
7  * * Licensed under the Apache License, Version 2.0 (the "License");
8  * * you may not use this file except in compliance with the License.
9  * * You may obtain a copy of the License at
10  * *
11  *  *      http://www.apache.org/licenses/LICENSE-2.0
12  * *
13  *  * Unless required by applicable law or agreed to in writing, software
14  * * distributed under the License is distributed on an "AS IS" BASIS,
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * * See the License for the specific language governing permissions and
17  * * limitations under the License.
18  * * ============LICENSE_END====================================================
19  * *
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24
25 package org.onap.dmaap.datarouter.provisioning;
26
27 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
28 import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
29 import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS;
30 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
31
32 import com.att.eelf.configuration.EELFLogger;
33 import com.att.eelf.configuration.EELFManager;
34 import java.net.InetAddress;
35 import java.net.UnknownHostException;
36 import java.security.GeneralSecurityException;
37 import java.security.cert.X509Certificate;
38 import java.sql.Connection;
39 import java.sql.SQLException;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Properties;
46 import java.util.Set;
47 import java.util.UUID;
48 import javax.servlet.ServletConfig;
49 import javax.servlet.ServletException;
50 import javax.servlet.http.HttpServlet;
51 import javax.servlet.http.HttpServletRequest;
52 import org.apache.commons.lang3.StringUtils;
53 import org.jetbrains.annotations.Nullable;
54 import org.json.JSONArray;
55 import org.json.JSONException;
56 import org.json.JSONObject;
57 import org.json.JSONTokener;
58 import org.onap.dmaap.datarouter.authz.Authorizer;
59 import org.onap.dmaap.datarouter.authz.impl.ProvAuthorizer;
60 import org.onap.dmaap.datarouter.authz.impl.ProvDataProvider;
61 import org.onap.dmaap.datarouter.provisioning.beans.Deleteable;
62 import org.onap.dmaap.datarouter.provisioning.beans.Feed;
63 import org.onap.dmaap.datarouter.provisioning.beans.Group;
64 import org.onap.dmaap.datarouter.provisioning.beans.Insertable;
65 import org.onap.dmaap.datarouter.provisioning.beans.NodeClass;
66 import org.onap.dmaap.datarouter.provisioning.beans.Parameters;
67 import org.onap.dmaap.datarouter.provisioning.beans.Subscription;
68 import org.onap.dmaap.datarouter.provisioning.beans.Updateable;
69 import org.onap.dmaap.datarouter.provisioning.utils.DB;
70 import org.onap.dmaap.datarouter.provisioning.utils.PasswordProcessor;
71 import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter;
72 import org.slf4j.MDC;
73
74
75 /**
76  * This is the base class for all Servlets in the provisioning code. It provides standard constants and some common
77  * methods.
78  *
79  * @author Robert Eby
80  * @version $Id: BaseServlet.java,v 1.16 2014/03/12 19:45:40 eby Exp $
81  */
82 @SuppressWarnings("serial")
83 public class BaseServlet extends HttpServlet implements ProvDataProvider {
84
85     public static final String BEHALF_HEADER = "X-DMAAP-DR-ON-BEHALF-OF";
86
87     public static final String EXCLUDE_AAF_HEADER = "X-EXCLUDE-AAF";
88
89     private static final String AAF_CADI_FEED_TYPE = "org.onap.dmaap.datarouter.provserver.aaf.feed.type";
90     private static final String AAF_CADI_SUB_TYPE = "org.onap.dmaap.datarouter.provserver.aaf.sub.type";
91     private static final String AAF_INSTANCE = "org.onap.dmaap.datarouter.provserver.aaf.instance";
92     private static final String AAF_CADI_FEED = "org.onap.dmaap-dr.feed";
93     private static final String AAF_CADI_SUB = "org.onap.dmaap-dr.sub";
94
95     static final String CREATE_PERMISSION = "create";
96     static final String EDIT_PERMISSION = "edit";
97     static final String DELETE_PERMISSION = "delete";
98     private static final String PUBLISH_PERMISSION = "publish";
99     private static final String SUSPEND_PERMISSION = "suspend";
100     private static final String RESTORE_PERMISSION = "restore";
101     private static final String SUBSCRIBE_PERMISSION = "subscribe";
102     static final String APPROVE_SUB_PERMISSION = "approveSub";
103
104     static final String FEED_BASECONTENT_TYPE = "application/vnd.dmaap-dr.feed";
105     public static final String FEED_CONTENT_TYPE = "application/vnd.dmaap-dr.feed; version=2.0";
106     public static final String FEEDFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.feed-full; version=2.0";
107     public static final String FEEDLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.feed-list; version=1.0";
108     static final String SUB_BASECONTENT_TYPE = "application/vnd.dmaap-dr.subscription";
109     public static final String SUB_CONTENT_TYPE = "application/vnd.dmaap-dr.subscription; version=2.0";
110     public static final String SUBFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.subscription-full; version=2.0";
111     static final String SUBLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.subscription-list; version=1.0";
112
113
114     //Adding groups functionality, ...1610
115     static final String GROUP_BASECONTENT_TYPE = "application/vnd.dmaap-dr.group";
116     static final String GROUP_CONTENT_TYPE = "application/vnd.dmaap-dr.group; version=2.0";
117     static final String GROUPFULL_CONTENT_TYPE = "application/vnd.dmaap-dr.group-full; version=2.0";
118     public static final String GROUPLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.fegrouped-list; version=1.0";
119
120
121     public static final String LOGLIST_CONTENT_TYPE = "application/vnd.dmaap-dr.log-list; version=1.0";
122     public static final String PROVFULL_CONTENT_TYPE1 = "application/vnd.dmaap-dr.provfeed-full; version=1.0";
123     public static final String PROVFULL_CONTENT_TYPE2 = "application/vnd.dmaap-dr.provfeed-full; version=2.0";
124     public static final String CERT_ATTRIBUTE = "javax.servlet.request.X509Certificate";
125
126     static final String DB_PROBLEM_MSG = "There has been a problem with the DB.  It is suggested you try the operation again.";
127
128     private static final int DEFAULT_MAX_FEEDS = 10000;
129     private static final int DEFAULT_MAX_SUBS = 100000;
130     private static final int DEFAULT_POKETIMER1 = 5;
131     private static final int DEFAULT_POKETIMER2 = 30;
132     private static final String DEFAULT_DOMAIN = "onap";
133     private static final String DEFAULT_PROVSRVR_NAME = "dmaap-dr-prov";
134
135     //Common Errors
136     static final String MISSING_ON_BEHALF = "Missing X-DMAAP-DR-ON-BEHALF-OF header.";
137     static final String MISSING_FEED = "Missing or bad feed number.";
138     static final String POLICY_ENGINE = "Policy Engine disallows access.";
139     static final String UNAUTHORIZED = "Unauthorized.";
140     static final String BAD_SUB = "Missing or bad subscription number.";
141     static final String BAD_JSON = "Badly formed JSON";
142     static final String BAD_URL = "Bad URL.";
143
144     public static final String API = "/api/";
145     static final String LOGS = "/logs/";
146     static final String TEXT_CT = "text/plain";
147     static final String INGRESS = "/ingress/";
148     static final String EGRESS = "/egress/";
149     static final String NETWORK = "/network/";
150     static final String GROUPID = "groupid";
151     public static final String FEEDID = "feedid";
152     static final String FEEDIDS = "feedids";
153     static final String SUBID = "subid";
154     static final String EVENT_TYPE = "eventType";
155     static final String OUTPUT_TYPE = "output_type";
156     static final String START_TIME = "start_time";
157     static final String END_TIME = "end_time";
158     static final String REASON_SQL = "reasonSQL";
159
160
161     /**
162      * A boolean to trigger one time "provisioning changed" event on startup.
163      */
164     private static boolean startmsgFlag = true;
165     /**
166      * This POD should require SSL connections from clients; pulled from the DB (PROV_REQUIRE_SECURE).
167      */
168     private static boolean requireSecure = true;
169     /**
170      * This POD should require signed, recognized certificates from clients; pulled from the DB (PROV_REQUIRE_CERT).
171      */
172     private static boolean requireCert = true;
173     /**
174      * The set of authorized addresses and networks; pulled from the DB (PROV_AUTH_ADDRESSES).
175      */
176     private static Set<String> authorizedAddressesAndNetworks = new HashSet<>();
177     /**
178      * The set of authorized names; pulled from the DB (PROV_AUTH_SUBJECTS).
179      */
180     private static Set<String> authorizedNames = new HashSet<>();
181     /**
182      * The FQDN of the initially "active" provisioning server in this Data Router ecosystem.
183      */
184     private static String initialActivePod;
185     /**
186      * The FQDN of the initially "standby" provisioning server in this Data Router ecosystem.
187      */
188     private static String initialStandbyPod;
189     /**
190      * The FQDN of this provisioning server in this Data Router ecosystem.
191      */
192     private static String thisPod;
193     /**
194      * "Timer 1" - used to determine when to notify nodes of provisioning changes.
195      */
196     private static long pokeTimer1;
197     /**
198      * "Timer 2" - used to determine when to notify nodes of provisioning changes.
199      */
200     private static long pokeTimer2;
201     /**
202      * Array of nodes names and/or FQDNs.
203      */
204     private static String[] nodes = new String[0];
205     /**
206      * [DATARTR-27] Poke all the DR nodes : Array of nodes names and/or FQDNs.
207      */
208     private static String[] drnodes = new String[0];
209     /**
210      * Array of node IP addresses.
211      */
212     private static InetAddress[] nodeAddresses = new InetAddress[0];
213     /**
214      * Array of POD IP addresses.
215      */
216     private static InetAddress[] podAddresses = new InetAddress[0];
217     /**
218      * The maximum number of feeds allowed; pulled from the DB (PROV_MAXFEED_COUNT).
219      */
220     static int maxFeeds = 0;
221     /**
222      * The maximum number of subscriptions allowed; pulled from the DB (PROV_MAXSUB_COUNT).
223      */
224     static int maxSubs = 0;
225     /**
226      * The current number of feeds in the system.
227      */
228     static int activeFeeds = 0;
229     /**
230      * The current number of subscriptions in the system.
231      */
232     static int activeSubs = 0;
233
234     /**
235      * The domain used to generate a FQDN from the "bare" node names.
236      */
237     private static String provDomain = "web.att.com";
238
239     /**
240      * The standard FQDN of the provisioning server in this Data Router ecosystem.
241      */
242     private static String provName = "feeds-drtr.web.att.com";
243
244     /**
245      * The standard FQDN of the ACTIVE_POD provisioning server in this Data Router ecosystem.
246      */
247     private static String activeProvName = "feeds-drtr.web.att.com";
248
249     /**
250      * This logger is used to log provisioning events.
251      */
252     protected static EELFLogger eventlogger;
253     /**
254      * This logger is used to log internal events (errors, etc.)
255      */
256     protected static EELFLogger intlogger;
257     /**
258      * Authorizer - interface to the Policy Engine.
259      */
260     protected static Authorizer authz;
261     /**
262      * The Synchronizer used to sync active DB to standby one.
263      */
264     private static SynchronizerTask synctask = null;
265
266     //Data Router Subscriber HTTPS Relaxation feature USERSTORYID:US674047.
267     private InetAddress thishost;
268     private InetAddress loopback;
269
270     //DMAAP-597 (Tech Dept) REST request source IP auth relaxation to accommodate OOM kubernetes deploy
271     private static String isAddressAuthEnabled = (new DB()).getProperties()
272             .getProperty("org.onap.dmaap.datarouter.provserver.isaddressauthenabled", "false");
273
274     static String isCadiEnabled = (new DB()).getProperties()
275             .getProperty("org.onap.dmaap.datarouter.provserver.cadi.enabled", "false");
276
277     /**
278      * Initialize data common to all the provisioning server servlets.
279      */
280     protected BaseServlet() {
281         if (eventlogger == null) {
282             eventlogger = EELFManager.getInstance().getLogger("EventLog");
283         }
284         if (intlogger == null) {
285             this.intlogger = EELFManager.getInstance().getLogger("InternalLog");
286         }
287         if (authz == null) {
288             authz = new ProvAuthorizer(this);
289         }
290         if (startmsgFlag) {
291             startmsgFlag = false;
292             provisioningParametersChanged();
293         }
294         if (synctask == null) {
295             synctask = SynchronizerTask.getSynchronizer();
296         }
297         String name = this.getClass().getName();
298         intlogger.info("PROV0002 Servlet " + name + " started.");
299     }
300
301     @Override
302     public void init(ServletConfig config) throws ServletException {
303         super.init(config);
304         try {
305             thishost = InetAddress.getLocalHost();
306             loopback = InetAddress.getLoopbackAddress();
307         } catch (UnknownHostException e) {
308             intlogger.info("BaseServlet.init: " + e.getMessage(), e);
309         }
310     }
311
312     public static int getIdFromPath(HttpServletRequest req) {
313         String path = req.getPathInfo();
314         if (path == null || path.length() < 2) {
315             return -1;
316         }
317         try {
318             return Integer.parseInt(path.substring(1));
319         } catch (NumberFormatException e) {
320             return -1;
321         }
322     }
323
324     /**
325      * Read the request's input stream and return a JSONObject from it.
326      *
327      * @param req the HTTP request
328      * @return the JSONObject, or null if the stream cannot be parsed
329      */
330     JSONObject getJSONfromInput(HttpServletRequest req) {
331         JSONObject jo = null;
332         try {
333             jo = new JSONObject(new JSONTokener(req.getInputStream()));
334             if (intlogger.isDebugEnabled()) {
335                 intlogger.debug("JSON: " + jo.toString());
336             }
337         } catch (Exception e) {
338             intlogger.info("Error reading JSON: " + e);
339         }
340         return jo;
341     }
342
343     /**
344      * This method encrypt/decrypt the key in the JSON passed by user request inside the authorisation
345      * header object in request before logging the JSON.
346      *
347      * @param jo      the JSON passed in http request.
348      * @param maskKey the key to be masked in the JSON passed.
349      * @param action  whether to mask the key or unmask it in a JSON passed.
350      * @return the JSONObject, or null if the stream cannot be parsed.
351      */
352     static JSONObject maskJSON(JSONObject jo, String maskKey, boolean action) {
353         if (!jo.isNull("authorization")) {
354             JSONArray endpointIds = jo.getJSONObject("authorization").getJSONArray("endpoint_ids");
355             for (int index = 0; index < endpointIds.length(); index++) {
356                 if ((!endpointIds.getJSONObject(index).isNull(maskKey))) {
357                     String password = endpointIds.getJSONObject(index).get(maskKey).toString();
358                     processPassword(maskKey, action, endpointIds, index, password);
359                 }
360             }
361         }
362         return jo;
363     }
364
365     private static void processPassword(String maskKey, boolean action, JSONArray endpointIds, int index,
366             String password) {
367         try {
368             if (action) {
369                 endpointIds.getJSONObject(index).put(maskKey, PasswordProcessor.encrypt(password));
370             } else {
371                 endpointIds.getJSONObject(index).put(maskKey, PasswordProcessor.decrypt(password));
372             }
373         } catch (JSONException | GeneralSecurityException e) {
374             intlogger.info("Error reading JSON while masking: " + e);
375         }
376     }
377
378     /**
379      * Check if the remote host is authorized to perform provisioning. Is the request secure? Is it coming from an
380      * authorized IP address or network (configured via PROV_AUTH_ADDRESSES)? Does it have a valid client certificate
381      * (configured via PROV_AUTH_SUBJECTS)?
382      *
383      * @param request the request
384      * @return an error string, or null if all is OK
385      */
386     String isAuthorizedForProvisioning(HttpServletRequest request) {
387         if (!Boolean.parseBoolean(isAddressAuthEnabled)) {
388             return null;
389         }
390         // Is the request https?
391         if (requireSecure && !request.isSecure()) {
392             return "Request must be made over an HTTPS connection.";
393         }
394         String remoteHostCheck = checkRemoteHostAuthorization(request);
395         if (remoteHostCheck != null) {
396             return remoteHostCheck;
397         }
398         // Does remote have a valid certificate?
399         if (requireCert) {
400             X509Certificate[] certs = (X509Certificate[]) request.getAttribute(CERT_ATTRIBUTE);
401             if (certs == null || certs.length == 0) {
402                 return "Client certificate is missing.";
403             }
404             // cert[0] is the client cert
405             // see http://www.proto.research.att.com/java/java7/api/javax/net/ssl/SSLSession.html#getPeerCertificates()
406             String name = certs[0].getSubjectX500Principal().getName();
407             if (!authorizedNames.contains(name)) {
408                 return "No authorized certificate found.";
409             }
410         }
411         // No problems!
412         return null;
413     }
414
415     @Nullable
416     private String checkRemoteHostAuthorization(HttpServletRequest request) {
417         // Is remote IP authorized?
418         String remote = request.getRemoteAddr();
419         try {
420             boolean found = false;
421             InetAddress ip = InetAddress.getByName(remote);
422             for (String addrnet : authorizedAddressesAndNetworks) {
423                 found |= addressMatchesNetwork(ip, addrnet);
424             }
425             if (!found) {
426                 return "Unauthorized address: " + remote;
427             }
428         } catch (UnknownHostException e) {
429             intlogger.error("PROV0051 BaseServlet.isAuthorizedForProvisioning: " + e.getMessage(), e);
430             return "Unauthorized address: " + remote;
431         }
432         return null;
433     }
434
435     /**
436      * Check if the remote IP address is authorized to see the /internal URL tree.
437      *
438      * @param request the HTTP request
439      * @return true iff authorized
440      */
441     boolean isAuthorizedForInternal(HttpServletRequest request) {
442         try {
443             if (!Boolean.parseBoolean(isAddressAuthEnabled)) {
444                 return true;
445             }
446             InetAddress ip = InetAddress.getByName(request.getRemoteAddr());
447             for (InetAddress node : getNodeAddresses()) {
448                 if (ip.equals(node)) {
449                     return true;
450                 }
451             }
452             for (InetAddress pod : getPodAddresses()) {
453                 if (ip.equals(pod)) {
454                     return true;
455                 }
456             }
457             if (ip.equals(thishost)) {
458                 return true;
459             }
460             if (ip.equals(loopback)) {
461                 return true;
462             }
463         } catch (UnknownHostException e) {
464             intlogger.error("PROV0052 BaseServlet.isAuthorizedForInternal: " + e.getMessage(), e);
465         }
466         return false;
467     }
468
469     /**
470      * Check if an IP address matches a network address.
471      *
472      * @param ip the IP address
473      * @param s  the network address; a bare IP address may be matched also
474      * @return true if they intersect
475      */
476     private static boolean addressMatchesNetwork(InetAddress ip, String s) {
477         int mlen = -1;
478         int n = s.indexOf('/');
479         if (n >= 0) {
480             mlen = Integer.parseInt(s.substring(n + 1));
481             s = s.substring(0, n);
482         }
483         try {
484             InetAddress i2 = InetAddress.getByName(s);
485             byte[] b1 = ip.getAddress();
486             byte[] b2 = i2.getAddress();
487             if (b1.length != b2.length) {
488                 return false;
489             }
490             if (mlen > 0) {
491                 byte[] masks = {
492                         (byte) 0x00, (byte) 0x80, (byte) 0xC0, (byte) 0xE0,
493                         (byte) 0xF0, (byte) 0xF8, (byte) 0xFC, (byte) 0xFE
494                 };
495                 byte mask = masks[mlen % 8];
496                 for (n = mlen / 8; n < b1.length; n++) {
497                     b1[n] &= mask;
498                     b2[n] &= mask;
499                     mask = 0;
500                 }
501             }
502             for (n = 0; n < b1.length; n++) {
503                 if (b1[n] != b2[n]) {
504                     return false;
505                 }
506             }
507         } catch (UnknownHostException e) {
508             intlogger.error("PROV0053 BaseServlet.addressMatchesNetwork: " + e.getMessage(), e);
509             return false;
510         }
511         return true;
512     }
513
514     /**
515      * Something has changed in the provisioning data. Start the timers that will cause the pre-packaged JSON string to
516      * be regenerated, and cause nodes and the other provisioning server to be notified.
517      */
518     static void provisioningDataChanged() {
519         long now = System.currentTimeMillis();
520         Poker p = Poker.getPoker();
521         p.setTimers(now + (pokeTimer1 * 1000L), now + (pokeTimer2 * 1000L));
522     }
523
524     /**
525      * Something in the parameters has changed, reload all parameters from the DB.
526      */
527     static void provisioningParametersChanged() {
528         Map<String, String> map = Parameters.getParameters();
529         requireSecure = getBoolean(map, Parameters.PROV_REQUIRE_SECURE);
530         requireCert = getBoolean(map, Parameters.PROV_REQUIRE_CERT);
531         authorizedAddressesAndNetworks = getSet(map, Parameters.PROV_AUTH_ADDRESSES);
532         authorizedNames = getSet(map, Parameters.PROV_AUTH_SUBJECTS);
533         nodes = getSet(map, Parameters.NODES).toArray(new String[0]);
534         maxFeeds = getInt(map, Parameters.PROV_MAXFEED_COUNT, DEFAULT_MAX_FEEDS);
535         maxSubs = getInt(map, Parameters.PROV_MAXSUB_COUNT, DEFAULT_MAX_SUBS);
536         pokeTimer1 = getInt(map, Parameters.PROV_POKETIMER1, DEFAULT_POKETIMER1);
537         pokeTimer2 = getInt(map, Parameters.PROV_POKETIMER2, DEFAULT_POKETIMER2);
538
539         // The domain used to generate a FQDN from the "bare" node names
540         provDomain = getString(map, Parameters.PROV_DOMAIN, DEFAULT_DOMAIN);
541         provName = getString(map, Parameters.PROV_NAME, DEFAULT_PROVSRVR_NAME);
542         activeProvName = getString(map, Parameters.PROV_ACTIVE_NAME, provName);
543         initialActivePod = getString(map, Parameters.ACTIVE_POD, "");
544         initialStandbyPod = getString(map, Parameters.STANDBY_POD, "");
545
546         //Adding new param for static Routing - Rally:US664862-1610
547         String staticRoutingNodes = getString(map, Parameters.STATIC_ROUTING_NODES, "");
548         activeFeeds = Feed.countActiveFeeds();
549         activeSubs = Subscription.countActiveSubscriptions();
550         try {
551             thisPod = InetAddress.getLocalHost().getHostName();
552         } catch (UnknownHostException e) {
553             thisPod = "";
554             intlogger.warn("PROV0014 Cannot determine the name of this provisioning server.", e);
555         }
556
557         // Normalize the nodes, and fill in nodeAddresses
558         InetAddress[] na = new InetAddress[nodes.length];
559         for (int i = 0; i < nodes.length; i++) {
560             try {
561                 na[i] = InetAddress.getByName(nodes[i]);
562                 intlogger.debug("PROV0003 DNS lookup: " + nodes[i] + " => " + na[i].toString());
563             } catch (UnknownHostException e) {
564                 na[i] = null;
565                 intlogger.warn("PROV0004 Cannot lookup " + nodes[i] + ": " + e.getMessage(), e);
566             }
567         }
568
569         //[DATARTR-27] Poke all the DR nodes: assigning DR Nodes
570         drnodes = nodes.clone();
571
572         //Reset Nodes arr after - removing static routing Nodes, Rally Userstory - US664862 .
573         List<String> filterNodes = new ArrayList<>();
574         for (String node : nodes) {
575             if (!staticRoutingNodes.contains(node)) {
576                 filterNodes.add(node);
577             }
578         }
579         nodes = filterNodes.toArray(new String[0]);
580
581         nodeAddresses = na;
582         NodeClass.setNodes(nodes);        // update NODES table
583
584         // Normalize the PODs, and fill in podAddresses
585         String[] pods = getPods();
586         na = new InetAddress[pods.length];
587         for (int i = 0; i < pods.length; i++) {
588             try {
589                 na[i] = InetAddress.getByName(pods[i]);
590                 intlogger.debug("PROV0003 DNS lookup: " + pods[i] + " => " + na[i].toString());
591             } catch (UnknownHostException e) {
592                 na[i] = null;
593                 intlogger.warn("PROV0004 Cannot lookup " + pods[i] + ": " + e.getMessage(), e);
594             }
595         }
596         podAddresses = na;
597
598         // Update ThrottleFilter
599         ThrottleFilter.configure();
600
601         // Check if we are active or standby POD
602         if (!isInitialActivePOD() && !isInitialStandbyPOD()) {
603             intlogger.warn("PROV0015 This machine is neither the active nor the standby POD.");
604         }
605     }
606
607     public static String getProvName() {
608         return provName;
609     }
610
611     static String getActiveProvName() {
612         return activeProvName;
613     }
614
615     /**
616      * Get an array of all node names in the DR network.
617      *
618      * @return an array of Strings
619      */
620     public static String[] getNodes() {
621         return nodes;
622     }
623
624     /**
625      * [DATARTR-27] Poke all the DR nodes
626      * Get an array of all node names in the DR network.
627      *
628      * @return an array of Strings
629      */
630     public static String[] getDRNodes() {
631         return drnodes;
632     }
633
634     /**
635      * Get an array of all node InetAddresses in the DR network.
636      *
637      * @return an array of InetAddresses
638      */
639     private static InetAddress[] getNodeAddresses() {
640         return nodeAddresses;
641     }
642
643     /**
644      * Get an array of all POD names in the DR network.
645      *
646      * @return an array of Strings
647      */
648     public static String[] getPods() {
649         return new String[]{initialActivePod, initialStandbyPod};
650     }
651
652     /**
653      * Get an array of all POD InetAddresses in the DR network.
654      *
655      * @return an array of InetAddresses
656      */
657     private static InetAddress[] getPodAddresses() {
658         return podAddresses;
659     }
660
661     /**
662      * Gets the FQDN of the initially ACTIVE_POD provisioning server (POD). Note: this used to be called isActivePOD(),
663      * however, that is a misnomer, as the active status could shift to the standby POD without these parameters
664      * changing.  Hence, the function names have been changed to more accurately reflect their purpose.
665      *
666      * @return the FQDN
667      */
668     public static boolean isInitialActivePOD() {
669         return thisPod.equals(initialActivePod);
670     }
671
672     /**
673      * Gets the FQDN of the initially STANDBY_POD provisioning server (POD). Note: this used to be called isStandbyPOD(),
674      * however, that is a misnomer, as the standby status could shift to the active POD without these parameters
675      * changing.  Hence, the function names have been changed to more accurately reflect their purpose.
676      *
677      * @return the FQDN
678      */
679     public static boolean isInitialStandbyPOD() {
680         return thisPod.equals(initialStandbyPod);
681     }
682
683     /**
684      * INSERT an {@link Insertable} bean into the database.
685      *
686      * @param bean the bean representing a row to insert
687      * @return true if the INSERT was successful
688      */
689     protected boolean doInsert(Insertable bean) {
690         boolean rv;
691         DB db = new DB();
692         Connection conn = null;
693         try {
694             conn = db.getConnection();
695             rv = bean.doInsert(conn);
696         } catch (SQLException e) {
697             rv = false;
698             intlogger.warn("PROV0005 doInsert: " + e.getMessage(), e);
699         } finally {
700             if (conn != null) {
701                 db.release(conn);
702             }
703         }
704         return rv;
705     }
706
707     /**
708      * UPDATE an {@link Updateable} bean in the database.
709      *
710      * @param bean the bean representing a row to update
711      * @return true if the UPDATE was successful
712      */
713     protected boolean doUpdate(Updateable bean) {
714         boolean rv;
715         DB db = new DB();
716         Connection conn = null;
717         try {
718             conn = db.getConnection();
719             rv = bean.doUpdate(conn);
720         } catch (SQLException e) {
721             rv = false;
722             intlogger.warn("PROV0006 doUpdate: " + e.getMessage(), e);
723         } finally {
724             if (conn != null) {
725                 db.release(conn);
726             }
727         }
728         return rv;
729     }
730
731     /**
732      * DELETE an {@link Deleteable} bean from the database.
733      *
734      * @param bean the bean representing a row to delete
735      * @return true if the DELETE was successful
736      */
737     protected boolean doDelete(Deleteable bean) {
738         boolean rv;
739         DB db = new DB();
740         Connection conn = null;
741         try {
742             conn = db.getConnection();
743             rv = bean.doDelete(conn);
744         } catch (SQLException e) {
745             rv = false;
746             intlogger.warn("PROV0007 doDelete: " + e.getMessage(), e);
747         } finally {
748             if (conn != null) {
749                 db.release(conn);
750             }
751         }
752         return rv;
753     }
754
755     private static boolean getBoolean(Map<String, String> map, String name) {
756         String s = map.get(name);
757         return "true".equalsIgnoreCase(s);
758     }
759
760     private static String getString(Map<String, String> map, String name, String dflt) {
761         String s = map.get(name);
762         return (s != null) ? s : dflt;
763     }
764
765     private static int getInt(Map<String, String> map, String name, int dflt) {
766         try {
767             String s = map.get(name);
768             return Integer.parseInt(s);
769         } catch (NumberFormatException e) {
770             return dflt;
771         }
772     }
773
774     private static Set<String> getSet(Map<String, String> map, String name) {
775         Set<String> set = new HashSet<>();
776         String s = map.get(name);
777         if (s != null) {
778             String[] pp = s.split("\\|");
779             if (pp != null) {
780                 for (String t : pp) {
781                     String t2 = t.trim();
782                     if (t2.length() > 0) {
783                         set.add(t2);
784                     }
785                 }
786             }
787         }
788         return set;
789     }
790
791     /**
792      * A class used to encapsulate a Content-type header, separating out the "version" attribute (which defaults to
793      * "1.0" if missing).
794      */
795     public class ContentHeader {
796
797         private String type;
798         private Map<String, String> map = new HashMap<>();
799
800         ContentHeader() {
801             this("", "1.0");
802         }
803
804         ContentHeader(String t, String v) {
805             type = t.trim();
806             map.put("version", v);
807         }
808
809         public String getType() {
810             return type;
811         }
812
813         String getAttribute(String key) {
814             String s = map.get(key);
815             if (s == null) {
816                 s = "";
817             }
818             return s;
819         }
820     }
821
822     /**
823      * Get the ContentHeader from an HTTP request.
824      *
825      * @param req the request
826      * @return the header, encapsulated in a ContentHeader object
827      */
828     ContentHeader getContentHeader(HttpServletRequest req) {
829         ContentHeader ch = new ContentHeader();
830         String s = req.getHeader("Content-Type");
831         if (s != null) {
832             String[] pp = s.split(";");
833             ch.type = pp[0].trim();
834             for (int i = 1; i < pp.length; i++) {
835                 int ix = pp[i].indexOf('=');
836                 if (ix > 0) {
837                     String k = pp[i].substring(0, ix).trim();
838                     String v = pp[i].substring(ix + 1).trim();
839                     ch.map.put(k, v);
840                 } else {
841                     ch.map.put(pp[i].trim(), "");
842                 }
843             }
844         }
845         return ch;
846     }
847
848     // Methods for the Policy Engine classes - ProvDataProvider interface
849     @Override
850     public String getFeedOwner(String feedId) {
851         try {
852             int n = Integer.parseInt(feedId);
853             Feed f = Feed.getFeedById(n);
854             if (f != null) {
855                 return f.getPublisher();
856             }
857         } catch (NumberFormatException e) {
858             // ignore
859         }
860         return null;
861     }
862
863     @Override
864     public String getFeedClassification(String feedId) {
865         try {
866             int n = Integer.parseInt(feedId);
867             Feed f = Feed.getFeedById(n);
868             if (f != null) {
869                 return f.getAuthorization().getClassification();
870             }
871         } catch (NumberFormatException e) {
872             // ignore
873         }
874         return null;
875     }
876
877     @Override
878     public String getSubscriptionOwner(String subId) {
879         try {
880             int n = Integer.parseInt(subId);
881             Subscription s = Subscription.getSubscriptionById(n);
882             if (s != null) {
883                 return s.getSubscriber();
884             }
885         } catch (NumberFormatException e) {
886             // ignore
887         }
888         return null;
889     }
890
891     /*
892      * @Method - isUserMemberOfGroup - Rally:US708115
893      * @Params - group object and user to check if exists in given group
894      * @return - boolean value /true/false
895      */
896     private boolean isUserMemberOfGroup(Group group, String user) {
897
898         String groupDetails = group.getMembers().replace("]", "").replace("[", "");
899         String[] s = groupDetails.split("},");
900
901         for (String value : s) {
902             JSONObject jsonObj;
903             try {
904                 jsonObj = new JSONObject(value + "}");
905                 if (jsonObj.get("id").equals(user)) {
906                     return true;
907                 }
908             } catch (JSONException e) {
909                 intlogger.error("JSONException: " + e.getMessage(), e);
910             }
911         }
912         return false;
913
914     }
915
916     /*
917      * @Method - getGroupByFeedGroupId- Rally:US708115
918      * @Params - User to check in group and feedid which is assigned the group.
919      * @return - string value groupid/null
920      */
921     @Override
922     public String getGroupByFeedGroupId(String owner, String feedId) {
923         try {
924             Feed f = Feed.getFeedById(Integer.parseInt(feedId));
925             if (f != null) {
926                 int groupid = f.getGroupid();
927                 if (groupid > 0) {
928                     Group group = Group.getGroupById(groupid);
929                     if (group != null && isUserMemberOfGroup(group, owner)) {
930                         return group.getAuthid();
931                     }
932                 }
933             }
934         } catch (NumberFormatException e) {
935             // ignore
936         }
937         return null;
938     }
939
940     /*
941      * @Method - getGroupBySubGroupId - Rally:US708115
942      * @Params - User to check in group and subid which is assigned the group.
943      * @return - string value groupid/null
944      */
945     @Override
946     public String getGroupBySubGroupId(String owner, String subId) {
947         try {
948             int n = Integer.parseInt(subId);
949             Subscription s = Subscription.getSubscriptionById(n);
950             if (s != null) {
951                 int groupid = s.getGroupid();
952                 if (groupid > 0) {
953                     Group group = Group.getGroupById(groupid);
954                     if (group != null && isUserMemberOfGroup(group, owner)) {
955                         return group.getAuthid();
956                     }
957                 }
958             }
959         } catch (NumberFormatException e) {
960             // ignore
961         }
962         return null;
963     }
964
965     /*
966      * @Method - setIpFqdnRequestIDandInvocationIDForEelf
967      * @Params - method, prints method name in EELF log.
968      * @Params- Req, Request used to get RequestId and InvocationId
969      */
970     void setIpFqdnRequestIDandInvocationIDForEelf(String method, HttpServletRequest req) {
971         setIpFqdnForEelf(method);
972         setMDC(req, "X-ONAP-RequestID", MDC_KEY_REQUEST_ID);
973         setMDC(req, "X-InvocationID", "InvocationId");
974     }
975
976     private void setMDC(HttpServletRequest req, String headerName, String keyName) {
977         String mdcId = req.getHeader(headerName);
978         if (StringUtils.isBlank(mdcId)) {
979             mdcId = UUID.randomUUID().toString();
980         }
981         MDC.put(keyName, mdcId);
982     }
983
984     /*
985      * @Method - setIpFqdnRequestIdForEelf - Rally:US664892
986      * @Params - method, prints method name in EELF log.
987      */
988     void setIpFqdnForEelf(String method) {
989         MDC.clear();
990         MDC.put(MDC_SERVICE_NAME, method);
991         try {
992             MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getHostName());
993             MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
994         } catch (Exception e) {
995             intlogger.error("Exception: " + e.getMessage(), e);
996         }
997
998     }
999
1000     /*
1001      * AAF changes: TDP EPIC US# 307413
1002      * @Method - getFeedPermission - Forming permission string for feed part to check AAF access in CADI Framework
1003      * @Params - aafInstance Passing aafInstance as it's used in permission string
1004      * @Params - userAction Passing CONST values to set different actions in permission string
1005      */
1006     String getFeedPermission(String aafInstance, String userAction) {
1007         try {
1008             Properties props = (new DB()).getProperties();
1009             String type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED);
1010             String action;
1011             switch (userAction) {
1012                 case CREATE_PERMISSION:
1013                     action = CREATE_PERMISSION;
1014                     break;
1015                 case EDIT_PERMISSION:
1016                     action = EDIT_PERMISSION;
1017                     break;
1018                 case DELETE_PERMISSION:
1019                     action = DELETE_PERMISSION;
1020                     break;
1021                 case PUBLISH_PERMISSION:
1022                     action = PUBLISH_PERMISSION;
1023                     break;
1024                 case SUSPEND_PERMISSION:
1025                     action = SUSPEND_PERMISSION;
1026                     break;
1027                 case RESTORE_PERMISSION:
1028                     action = RESTORE_PERMISSION;
1029                     break;
1030                 default:
1031                     action = "*";
1032             }
1033             if (aafInstance == null || "".equals(aafInstance)) {
1034                 aafInstance = props.getProperty(AAF_INSTANCE, "org.onap.dmaap-dr.NoInstanceDefined");
1035             }
1036             return type + "|" + aafInstance + "|" + action;
1037         } catch (Exception e) {
1038             intlogger.error("PROV7005 BaseServlet.getFeedPermission: " + e.getMessage(), e);
1039         }
1040         return null;
1041     }
1042
1043     /*
1044      * AAF changes: TDP EPIC US# 307413
1045      * @Method - getSubscriberPermission - Forming permission string for subscription part to check AAF access in CADI Framework
1046      * @Params - aafInstance Passing aafInstance as it's used in permission string
1047      * @Params - userAction Passing CONST values to set different actions in permission string
1048      */
1049     String getSubscriberPermission(String aafInstance, String userAction) {
1050         try {
1051             Properties props = (new DB()).getProperties();
1052             String type = props.getProperty(AAF_CADI_SUB_TYPE, AAF_CADI_SUB);
1053             String action;
1054             switch (userAction) {
1055                 case SUBSCRIBE_PERMISSION:
1056                     action = SUBSCRIBE_PERMISSION;
1057                     type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED);
1058                     break;
1059                 case EDIT_PERMISSION:
1060                     action = EDIT_PERMISSION;
1061                     break;
1062                 case DELETE_PERMISSION:
1063                     action = DELETE_PERMISSION;
1064                     break;
1065                 case RESTORE_PERMISSION:
1066                     action = RESTORE_PERMISSION;
1067                     break;
1068                 case SUSPEND_PERMISSION:
1069                     action = SUSPEND_PERMISSION;
1070                     break;
1071                 case PUBLISH_PERMISSION:
1072                     action = PUBLISH_PERMISSION;
1073                     break;
1074                 case APPROVE_SUB_PERMISSION:
1075                     action = APPROVE_SUB_PERMISSION;
1076                     type = props.getProperty(AAF_CADI_FEED_TYPE, AAF_CADI_FEED);
1077                     break;
1078                 default:
1079                     action = "*";
1080             }
1081             if (aafInstance == null || "".equals(aafInstance)) {
1082                 aafInstance = props.getProperty(AAF_INSTANCE, "org.onap.dmaap-dr.NoInstanceDefined");
1083             }
1084             return type + "|" + aafInstance + "|" + action;
1085         } catch (Exception e) {
1086             intlogger.error("PROV7005 BaseServlet.getSubscriberPermission: " + e.getMessage(), e);
1087         }
1088         return null;
1089     }
1090 }