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