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