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