Fix_Old_Vulnerabilities_in_NodeConfig
[dmaap/datarouter.git] / datarouter-node / src / main / java / org / onap / dmaap / datarouter / node / NodeConfig.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.node;
26
27 import java.util.*;
28 import java.io.*;
29
30 /**
31  * Processed configuration for this node.
32  * <p>
33  * The NodeConfig represents a processed configuration from the Data Router
34  * provisioning server.  Each time configuration data is received from the
35  * provisioning server, a new NodeConfig is created and the previous one
36  * discarded.
37  */
38 public class NodeConfig {
39     /**
40      * Raw configuration entry for a data router node
41      */
42     public static class ProvNode {
43         private String cname;
44
45         /**
46          * Construct a node configuration entry.
47          *
48          * @param cname The cname of the node.
49          */
50         public ProvNode(String cname) {
51             this.cname = cname;
52         }
53
54         /**
55          * Get the cname of the node
56          */
57         public String getCName() {
58             return (cname);
59         }
60     }
61
62     /**
63      * Raw configuration entry for a provisioning parameter
64      */
65     public static class ProvParam {
66         private String name;
67         private String value;
68
69         /**
70          * Construct a provisioning parameter configuration entry.
71          *
72          * @param    name The name of the parameter.
73          * @param    value The value of the parameter.
74          */
75         public ProvParam(String name, String value) {
76             this.name = name;
77             this.value = value;
78         }
79
80         /**
81          * Get the name of the parameter.
82          */
83         public String getName() {
84             return (name);
85         }
86
87         /**
88          * Get the value of the parameter.
89          */
90         public String getValue() {
91             return (value);
92         }
93     }
94
95     /**
96      * Raw configuration entry for a data feed.
97      */
98     public static class ProvFeed {
99         private String id;
100         private String logdata;
101         private String status;
102
103         /**
104          * Construct a feed configuration entry.
105          *
106          * @param id      The feed ID of the entry.
107          * @param logdata String for log entries about the entry.
108          * @param status  The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or null if it is valid.
109          */
110         public ProvFeed(String id, String logdata, String status) {
111             this.id = id;
112             this.logdata = logdata;
113             this.status = status;
114         }
115
116         /**
117          * Get the feed id of the data feed.
118          */
119         public String getId() {
120             return (id);
121         }
122
123         /**
124          * Get the log data of the data feed.
125          */
126         public String getLogData() {
127             return (logdata);
128         }
129
130         /**
131          * Get the status of the data feed.
132          */
133         public String getStatus() {
134             return (status);
135         }
136     }
137
138     /**
139      * Raw configuration entry for a feed user.
140      */
141     public static class ProvFeedUser {
142         private String feedid;
143         private String user;
144         private String credentials;
145
146         /**
147          * Construct a feed user configuration entry
148          *
149          * @param feedid      The feed id.
150          * @param user        The user that will publish to the feed.
151          * @param credentials The Authorization header the user will use to publish.
152          */
153         public ProvFeedUser(String feedid, String user, String credentials) {
154             this.feedid = feedid;
155             this.user = user;
156             this.credentials = credentials;
157         }
158
159         /**
160          * Get the feed id of the feed user.
161          */
162         public String getFeedId() {
163             return (feedid);
164         }
165
166         /**
167          * Get the user for the feed user.
168          */
169         public String getUser() {
170             return (user);
171         }
172
173         /**
174          * Get the credentials for the feed user.
175          */
176         public String getCredentials() {
177             return (credentials);
178         }
179     }
180
181     /**
182      * Raw configuration entry for a feed subnet
183      */
184     public static class ProvFeedSubnet {
185         private String feedid;
186         private String cidr;
187
188         /**
189          * Construct a feed subnet configuration entry
190          *
191          * @param feedid The feed ID
192          * @param cidr   The CIDR allowed to publish to the feed.
193          */
194         public ProvFeedSubnet(String feedid, String cidr) {
195             this.feedid = feedid;
196             this.cidr = cidr;
197         }
198
199         /**
200          * Get the feed id of the feed subnet.
201          */
202         public String getFeedId() {
203             return (feedid);
204         }
205
206         /**
207          * Get the CIDR of the feed subnet.
208          */
209         public String getCidr() {
210             return (cidr);
211         }
212     }
213
214     /**
215      * Raw configuration entry for a subscription
216      */
217     public static class ProvSubscription {
218         private String subid;
219         private String feedid;
220         private String url;
221         private String authuser;
222         private String credentials;
223         private boolean metaonly;
224         private boolean use100;
225
226         /**
227          * Construct a subscription configuration entry
228          *
229          * @param subid       The subscription ID
230          * @param feedid      The feed ID
231          * @param url         The base delivery URL (not including the fileid)
232          * @param authuser    The user in the credentials used to deliver
233          * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the Authorization header.
234          * @param metaonly    Is this a meta data only subscription?
235          * @param use100      Should we send Expect: 100-continue?
236          */
237         public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, boolean metaonly, boolean use100) {
238             this.subid = subid;
239             this.feedid = feedid;
240             this.url = url;
241             this.authuser = authuser;
242             this.credentials = credentials;
243             this.metaonly = metaonly;
244             this.use100 = use100;
245         }
246
247         /**
248          * Get the subscription ID
249          */
250         public String getSubId() {
251             return (subid);
252         }
253
254         /**
255          * Get the feed ID
256          */
257         public String getFeedId() {
258             return (feedid);
259         }
260
261         /**
262          * Get the delivery URL
263          */
264         public String getURL() {
265             return (url);
266         }
267
268         /**
269          * Get the user
270          */
271         public String getAuthUser() {
272             return (authuser);
273         }
274
275         /**
276          * Get the delivery credentials
277          */
278         public String getCredentials() {
279             return (credentials);
280         }
281
282         /**
283          * Is this a meta data only subscription?
284          */
285         public boolean isMetaDataOnly() {
286             return (metaonly);
287         }
288
289         /**
290          * Should we send Expect: 100-continue?
291          */
292         public boolean isUsing100() {
293             return (use100);
294         }
295     }
296
297     /**
298      * Raw configuration entry for controlled ingress to the data router node
299      */
300     public static class ProvForceIngress {
301         private String feedid;
302         private String subnet;
303         private String user;
304         private String[] nodes;
305
306         /**
307          * Construct a forced ingress configuration entry
308          *
309          * @param feedid The feed ID that this entry applies to
310          * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all publisher IP addresses
311          * @param user   The publishing user this entry applies to or "" if it applies to all publishing users.
312          * @param nodes  The array of FQDNs of the data router nodes to redirect publication attempts to.
313          */
314         public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
315             this.feedid = feedid;
316             this.subnet = subnet;
317             this.user = user;
318             this.nodes = nodes;
319         }
320
321         /**
322          * Get the feed ID
323          */
324         public String getFeedId() {
325             return (feedid);
326         }
327
328         /**
329          * Get the subnet
330          */
331         public String getSubnet() {
332             return (subnet);
333         }
334
335         /**
336          * Get the user
337          */
338         public String getUser() {
339             return (user);
340         }
341
342         /**
343          * Get the node
344          */
345         public String[] getNodes() {
346             return (nodes);
347         }
348     }
349
350     /**
351      * Raw configuration entry for controlled egress from the data router
352      */
353     public static class ProvForceEgress {
354         private String subid;
355         private String node;
356
357         /**
358          * Construct a forced egress configuration entry
359          *
360          * @param subid The subscription ID the subscription with forced egress
361          * @param node  The node handling deliveries for this subscription
362          */
363         public ProvForceEgress(String subid, String node) {
364             this.subid = subid;
365             this.node = node;
366         }
367
368         /**
369          * Get the subscription ID
370          */
371         public String getSubId() {
372             return (subid);
373         }
374
375         /**
376          * Get the node
377          */
378         public String getNode() {
379             return (node);
380         }
381     }
382
383     /**
384      * Raw configuration entry for routing within the data router network
385      */
386     public static class ProvHop {
387         private String from;
388         private String to;
389         private String via;
390
391         /**
392          * A human readable description of this entry
393          */
394         public String toString() {
395             return ("Hop " + from + "->" + to + " via " + via);
396         }
397
398         /**
399          * Construct a hop entry
400          *
401          * @param from The FQDN of the node with the data to be delivered
402          * @param to   The FQDN of the node that will deliver to the subscriber
403          * @param via  The FQDN of the node where the from node should send the data
404          */
405         public ProvHop(String from, String to, String via) {
406             this.from = from;
407             this.to = to;
408             this.via = via;
409         }
410
411         /**
412          * Get the from node
413          */
414         public String getFrom() {
415             return (from);
416         }
417
418         /**
419          * Get the to node
420          */
421         public String getTo() {
422             return (to);
423         }
424
425         /**
426          * Get the next intermediate node
427          */
428         public String getVia() {
429             return (via);
430         }
431     }
432
433     private static class Redirection {
434         SubnetMatcher snm;
435         String user;
436         String[] nodes;
437     }
438
439     private static class Feed {
440         String loginfo;
441         String status;
442         SubnetMatcher[] subnets;
443         Hashtable<String, String> authusers = new Hashtable<String, String>();
444         Redirection[] redirections;
445         Target[] targets;
446     }
447
448     private Hashtable<String, String> params = new Hashtable<String, String>();
449     private Hashtable<String, Feed> feeds = new Hashtable<String, Feed>();
450     private Hashtable<String, DestInfo> nodeinfo = new Hashtable<String, DestInfo>();
451     private Hashtable<String, DestInfo> subinfo = new Hashtable<String, DestInfo>();
452     private Hashtable<String, IsFrom> nodes = new Hashtable<String, IsFrom>();
453     private String myname;
454     private String myauth;
455     private DestInfo[] alldests;
456     private int rrcntr;
457
458     /**
459      * Process the raw provisioning data to configure this node
460      *
461      * @param pd          The parsed provisioning data
462      * @param myname      My name as seen by external systems
463      * @param spooldir    The directory where temporary files live
464      * @param port        The port number for URLs
465      * @param nodeauthkey The keying string used to generate node authentication credentials
466      */
467     public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
468         this.myname = myname;
469         for (ProvParam p : pd.getParams()) {
470             params.put(p.getName(), p.getValue());
471         }
472         Vector<DestInfo> div = new Vector<DestInfo>();
473         myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
474         for (ProvNode pn : pd.getNodes()) {
475             String cn = pn.getCName();
476             if (nodeinfo.get(cn) != null) {
477                 continue;
478             }
479             String auth = NodeUtils.getNodeAuthHdr(cn, nodeauthkey);
480             DestInfo di = new DestInfo("n:" + cn, spooldir + "/n/" + cn, null, "n2n-" + cn, "https://" + cn + ":" + port + "/internal/publish", cn, myauth, false, true);
481             (new File(di.getSpool())).mkdirs();
482             div.add(di);
483             nodeinfo.put(cn, di);
484             nodes.put(auth, new IsFrom(cn));
485         }
486         PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[nodeinfo.size()]), pd.getHops());
487         Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<String, Vector<Redirection>>();
488         for (ProvForceIngress pfi : pd.getForceIngress()) {
489             Vector<Redirection> v = rdtab.get(pfi.getFeedId());
490             if (v == null) {
491                 v = new Vector<Redirection>();
492                 rdtab.put(pfi.getFeedId(), v);
493             }
494             Redirection r = new Redirection();
495             if (pfi.getSubnet() != null) {
496                 r.snm = new SubnetMatcher(pfi.getSubnet());
497             }
498             r.user = pfi.getUser();
499             r.nodes = pfi.getNodes();
500             v.add(r);
501         }
502         Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<String, Hashtable<String, String>>();
503         for (ProvFeedUser pfu : pd.getFeedUsers()) {
504             Hashtable<String, String> t = pfutab.get(pfu.getFeedId());
505             if (t == null) {
506                 t = new Hashtable<String, String>();
507                 pfutab.put(pfu.getFeedId(), t);
508             }
509             t.put(pfu.getCredentials(), pfu.getUser());
510         }
511         Hashtable<String, String> egrtab = new Hashtable<String, String>();
512         for (ProvForceEgress pfe : pd.getForceEgress()) {
513             if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
514                 continue;
515             }
516             egrtab.put(pfe.getSubId(), pfe.getNode());
517         }
518         Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<String, Vector<SubnetMatcher>>();
519         for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
520             Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());
521             if (v == null) {
522                 v = new Vector<SubnetMatcher>();
523                 pfstab.put(pfs.getFeedId(), v);
524             }
525             v.add(new SubnetMatcher(pfs.getCidr()));
526         }
527         Hashtable<String, StringBuffer> ttab = new Hashtable<String, StringBuffer>();
528         HashSet<String> allfeeds = new HashSet<String>();
529         for (ProvFeed pfx : pd.getFeeds()) {
530             if (pfx.getStatus() == null) {
531                 allfeeds.add(pfx.getId());
532             }
533         }
534         for (ProvSubscription ps : pd.getSubscriptions()) {
535             String sid = ps.getSubId();
536             String fid = ps.getFeedId();
537             if (!allfeeds.contains(fid)) {
538                 continue;
539             }
540             if (subinfo.get(sid) != null) {
541                 continue;
542             }
543             int sididx = 999;
544             try {
545                 sididx = Integer.parseInt(sid);
546                 sididx -= sididx % 100;
547             } catch (Exception e) {
548             }
549             String siddir = sididx + "/" + sid;
550             DestInfo di = new DestInfo("s:" + sid, spooldir + "/s/" + siddir, sid, fid, ps.getURL(), ps.getAuthUser(), ps.getCredentials(), ps.isMetaDataOnly(), ps.isUsing100());
551             (new File(di.getSpool())).mkdirs();
552             div.add(di);
553             subinfo.put(sid, di);
554             String egr = egrtab.get(sid);
555             if (egr != null) {
556                 sid = pf.getPath(egr) + sid;
557             }
558             StringBuffer sb = ttab.get(fid);
559             if (sb == null) {
560                 sb = new StringBuffer();
561                 ttab.put(fid, sb);
562             }
563             sb.append(' ').append(sid);
564         }
565         alldests = div.toArray(new DestInfo[div.size()]);
566         for (ProvFeed pfx : pd.getFeeds()) {
567             String fid = pfx.getId();
568             Feed f = feeds.get(fid);
569             if (f != null) {
570                 continue;
571             }
572             f = new Feed();
573             feeds.put(fid, f);
574             f.loginfo = pfx.getLogData();
575             f.status = pfx.getStatus();
576             Vector<SubnetMatcher> v1 = pfstab.get(fid);
577             if (v1 == null) {
578                 f.subnets = new SubnetMatcher[0];
579             } else {
580                 f.subnets = v1.toArray(new SubnetMatcher[v1.size()]);
581             }
582             Hashtable<String, String> h1 = pfutab.get(fid);
583             if (h1 == null) {
584                 h1 = new Hashtable<String, String>();
585             }
586             f.authusers = h1;
587             Vector<Redirection> v2 = rdtab.get(fid);
588             if (v2 == null) {
589                 f.redirections = new Redirection[0];
590             } else {
591                 f.redirections = v2.toArray(new Redirection[v2.size()]);
592             }
593             StringBuffer sb = ttab.get(fid);
594             if (sb == null) {
595                 f.targets = new Target[0];
596             } else {
597                 f.targets = parseRouting(sb.toString());
598             }
599         }
600     }
601
602     /**
603      * Parse a target string into an array of targets
604      *
605      * @param routing Target string
606      * @return Array of targets.
607      */
608     public Target[] parseRouting(String routing) {
609         routing = routing.trim();
610         if ("".equals(routing)) {
611             return (new Target[0]);
612         }
613         String[] xx = routing.split("\\s+");
614         Hashtable<String, Target> tmap = new Hashtable<String, Target>();
615         HashSet<String> subset = new HashSet<String>();
616         Vector<Target> tv = new Vector<Target>();
617         Target[] ret = new Target[xx.length];
618         for (int i = 0; i < xx.length; i++) {
619             String t = xx[i];
620             int j = t.indexOf('/');
621             if (j == -1) {
622                 DestInfo di = subinfo.get(t);
623                 if (di == null) {
624                     tv.add(new Target(null, t));
625                 } else {
626                     if (!subset.contains(t)) {
627                         subset.add(t);
628                         tv.add(new Target(di, null));
629                     }
630                 }
631             } else {
632                 String node = t.substring(0, j);
633                 String rtg = t.substring(j + 1);
634                 DestInfo di = nodeinfo.get(node);
635                 if (di == null) {
636                     tv.add(new Target(null, t));
637                 } else {
638                     Target tt = tmap.get(node);
639                     if (tt == null) {
640                         tt = new Target(di, rtg);
641                         tmap.put(node, tt);
642                         tv.add(tt);
643                     } else {
644                         tt.addRouting(rtg);
645                     }
646                 }
647             }
648         }
649         return (tv.toArray(new Target[tv.size()]));
650     }
651
652     /**
653      * Check whether this is a valid node-to-node transfer
654      *
655      * @param credentials Credentials offered by the supposed node
656      * @param ip          IP address the request came from
657      */
658     public boolean isAnotherNode(String credentials, String ip) {
659         IsFrom n = nodes.get(credentials);
660         return (n != null && n.isFrom(ip));
661     }
662
663     /**
664      * Check whether publication is allowed.
665      *
666      * @param feedid      The ID of the feed being requested.
667      * @param credentials The offered credentials
668      * @param ip          The requesting IP address
669      */
670     public String isPublishPermitted(String feedid, String credentials, String ip) {
671         Feed f = feeds.get(feedid);
672         String nf = "Feed does not exist";
673         if (f != null) {
674             nf = f.status;
675         }
676         if (nf != null) {
677             return (nf);
678         }
679         String user = f.authusers.get(credentials);
680         if (user == null) {
681             return ("Publisher not permitted for this feed");
682         }
683         if (f.subnets.length == 0) {
684             return (null);
685         }
686         byte[] addr = NodeUtils.getInetAddress(ip);
687         for (SubnetMatcher snm : f.subnets) {
688             if (snm.matches(addr)) {
689                 return (null);
690             }
691         }
692         return ("Publisher not permitted for this feed");
693     }
694
695     /**
696      * Get authenticated user
697      */
698     public String getAuthUser(String feedid, String credentials) {
699         return (feeds.get(feedid).authusers.get(credentials));
700     }
701
702     /**
703      * Check if the request should be redirected to a different ingress node
704      */
705     public String getIngressNode(String feedid, String user, String ip) {
706         Feed f = feeds.get(feedid);
707         if (f.redirections.length == 0) {
708             return (null);
709         }
710         byte[] addr = NodeUtils.getInetAddress(ip);
711         for (Redirection r : f.redirections) {
712             if (r.user != null && !user.equals(r.user)) {
713                 continue;
714             }
715             if (r.snm != null && !r.snm.matches(addr)) {
716                 continue;
717             }
718             for (String n : r.nodes) {
719                 if (myname.equals(n)) {
720                     return (null);
721                 }
722             }
723             if (r.nodes.length == 0) {
724                 return (null);
725             }
726             return (r.nodes[rrcntr++ % r.nodes.length]);
727         }
728         return (null);
729     }
730
731     /**
732      * Get a provisioned configuration parameter
733      */
734     public String getProvParam(String name) {
735         return (params.get(name));
736     }
737
738     /**
739      * Get all the DestInfos
740      */
741     public DestInfo[] getAllDests() {
742         return (alldests);
743     }
744
745     /**
746      * Get the targets for a feed
747      *
748      * @param feedid The feed ID
749      * @return The targets this feed should be delivered to
750      */
751     public Target[] getTargets(String feedid) {
752         if (feedid == null) {
753             return (new Target[0]);
754         }
755         Feed f = feeds.get(feedid);
756         if (f == null) {
757             return (new Target[0]);
758         }
759         return (f.targets);
760     }
761
762     /**
763      * Get the feed ID for a subscription
764      *
765      * @param subid The subscription ID
766      * @return The feed ID
767      */
768     public String getFeedId(String subid) {
769         DestInfo di = subinfo.get(subid);
770         if (di == null) {
771             return (null);
772         }
773         return (di.getLogData());
774     }
775
776     /**
777      * Get the spool directory for a subscription
778      *
779      * @param subid The subscription ID
780      * @return The spool directory
781      */
782     public String getSpoolDir(String subid) {
783         DestInfo di = subinfo.get(subid);
784         if (di == null) {
785             return (null);
786         }
787         return (di.getSpool());
788     }
789
790     /**
791      * Get the Authorization value this node uses
792      *
793      * @return The Authorization header value for this node
794      */
795     public String getMyAuth() {
796         return (myauth);
797     }
798
799 }