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