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