Collection syntax change because of Sonar
[aaf/authz.git] / auth / auth-cmd / src / main / java / org / onap / aaf / auth / cmd / AAFcli.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 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  */
21
22 package org.onap.aaf.auth.cmd;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileReader;
27 import java.io.InputStreamReader;
28 import java.io.OutputStreamWriter;
29 import java.io.PrintWriter;
30 import java.io.Reader;
31 import java.io.Writer;
32 import java.net.HttpURLConnection;
33 import java.util.ArrayList;
34 import java.util.List;
35
36 import org.onap.aaf.auth.cmd.mgmt.Mgmt;
37 import org.onap.aaf.auth.cmd.ns.NS;
38 import org.onap.aaf.auth.cmd.perm.Perm;
39 import org.onap.aaf.auth.cmd.role.Role;
40 import org.onap.aaf.auth.cmd.user.User;
41 import org.onap.aaf.auth.common.Define;
42 import org.onap.aaf.auth.env.AuthzEnv;
43 import org.onap.aaf.cadi.Access;
44 import org.onap.aaf.cadi.Access.Level;
45 import org.onap.aaf.cadi.CadiException;
46 import org.onap.aaf.cadi.PropAccess;
47 import org.onap.aaf.cadi.SecuritySetter;
48 import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
49 import org.onap.aaf.cadi.client.Retryable;
50 import org.onap.aaf.cadi.config.Config;
51 import org.onap.aaf.cadi.config.SecurityInfoC;
52 import org.onap.aaf.cadi.http.HBasicAuthSS;
53 import org.onap.aaf.cadi.http.HMangr;
54 import org.onap.aaf.cadi.sso.AAFSSO;
55 import org.onap.aaf.misc.env.APIException;
56
57 import jline.console.ConsoleReader;
58
59 public class AAFcli {
60         protected static PrintWriter pw;
61         protected HMangr hman;
62         // Storage for last reused client. We can do this
63         // because we're technically "single" threaded calls.
64         public Retryable<?> prevCall;
65
66         protected SecuritySetter<HttpURLConnection> ss;
67 //      protected AuthzEnv env;
68         private boolean close;
69         private List<Cmd> cmds;
70
71         // Lex State
72         private ArrayList<Integer> expect = new ArrayList<>();
73         private boolean verbose = true;
74         private int delay;
75         private SecurityInfoC<HttpURLConnection> si;
76         private boolean request = false;
77         private String force = null;
78         private boolean gui = false;
79         // Package on purpose
80         Access access;
81         AuthzEnv env;
82
83         private static int TIMEOUT = Integer.parseInt(Config.AAF_CONN_TIMEOUT_DEF);
84         private static boolean isConsole = false;
85         private static boolean isTest = false;
86         private static boolean showDetails = false;
87         private static boolean ignoreDelay = false;
88         private static int globalDelay=0;
89         
90         public static int timeout() {
91                 return TIMEOUT;
92         }
93
94         // Create when only have Access
95         public AAFcli(Access access, Writer wtr, HMangr hman, SecurityInfoC<HttpURLConnection> si, SecuritySetter<HttpURLConnection> ss) throws APIException, CadiException {
96                 this(access,new AuthzEnv(access.getProperties()),wtr,hman, si,ss);
97         }
98
99         public AAFcli(Access access, AuthzEnv env, Writer wtr, HMangr hman, SecurityInfoC<HttpURLConnection> si, SecuritySetter<HttpURLConnection> ss) throws APIException, CadiException {
100                 this.env = env;
101                 this.access = access;
102                 this.ss = ss;
103                 this.hman = hman;
104                 this.si = si;
105                 if (wtr instanceof PrintWriter) {
106                         pw = (PrintWriter) wtr;
107                         close = false;
108                 } else {
109                         pw = new PrintWriter(wtr);
110                         close = true;
111                 }
112
113                 /*
114                  * Create Cmd Tree
115                  */
116                 cmds = new ArrayList<>();
117
118                 Role role = new Role(this);
119                 cmds.add(new Help(this, cmds));
120                 cmds.add(new Version(this));
121                 cmds.add(new Perm(role));
122                 cmds.add(role);
123                 cmds.add(new User(this));
124                 cmds.add(new NS(this));
125                 cmds.add(new Mgmt(this));
126         }
127
128         public void verbose(boolean v) {
129                 verbose = v;
130         }
131
132         public void close() {
133 //              if (hman != null) {
134 //                      hman.close();
135 //                      hman = null;
136 //              }
137                 if (close) {
138                         pw.close();
139                 }
140         }
141
142         public boolean eval(String line) throws Exception {
143                 if (line.length() == 0) {
144                         return true;
145                 } else if (line.startsWith("#")) {
146                         pw.println(line);
147                         return true;
148                 }
149
150                 String[] largs = argEval(line);
151                 int idx = 0;
152
153                 // Variable replacement
154                 StringBuilder sb = null;
155                 while (idx < largs.length) {
156                         int e = 0;
157                         for (int v = largs[idx].indexOf("@["); v >= 0; v = largs[idx].indexOf("@[", v + 1)) {
158                                 if (sb == null) {
159                                         sb = new StringBuilder();
160                                 }
161                                 sb.append(largs[idx], e, v);
162                                 if ((e = largs[idx].indexOf(']', v)) >= 0) {
163                                         String p = access.getProperty(largs[idx].substring(v + 2, e),null);
164                                         if(p==null) {
165                                                 p = System.getProperty(largs[idx].substring(v+2,e));
166                                         }
167                                         ++e;
168                                         if (p != null) {
169                                                 sb.append(p);
170                                         }
171                                 }
172                         }
173                         if (sb != null && sb.length() > 0) {
174                                 sb.append(largs[idx], e, largs[idx].length());
175                                 largs[idx] = sb.toString();
176                                 sb.setLength(0);
177                         }
178                         ++idx;
179                 }
180
181                 idx = 0;
182                 boolean rv = true;
183                 while (rv && idx < largs.length) {
184                         // Allow Script to change Credential
185                         if (!gui) {
186                                 if("as".equalsIgnoreCase(largs[idx])) {
187                                         if (largs.length > ++idx) {
188                                                 // get Password from Props with ID as Key
189                                                 String user = largs[idx++];
190                                                 int colon = user.indexOf(':');
191                                                 String pass;
192                                                 if (colon > 0) {
193                                                         pass = user.substring(colon + 1);
194                                                         user = user.substring(0, colon);
195                                                 } else {
196                                                         pass = access.getProperty(user, null);
197                                                 }
198                                                 if (pass != null) {
199                                                         pass = access.decrypt(pass, false);
200                                                         access.getProperties().put(user, pass);
201                                                         ss=new HBasicAuthSS(si, user, pass);
202                                                         pw.println("as " + user);
203                                                 } else { // get Pass from System Properties, under name of
204                                                         // Tag
205                                                         pw.println("ERROR: No password set for " + user);
206                                                         rv = false;
207                                                 }
208                                                 continue;
209                                         }
210                                 } else if ("expect".equalsIgnoreCase(largs[idx])) {
211                                         expect.clear();
212                                         if (largs.length > idx++) {
213                                                 if (!"nothing".equals(largs[idx])) {
214                                                         for (String str : largs[idx].split(",")) {
215                                                                 try {
216                                                                         if ("Exception".equalsIgnoreCase(str)) {
217                                                                                 expect.add(-1);
218                                                                         } else {
219                                                                                 expect.add(Integer.parseInt(str));
220                                                                         }
221                                                                 } catch (NumberFormatException e) {
222                                                                         throw new CadiException("\"expect\" should be followed by Number");
223                                                                 }
224                                                         }
225                                                 ++idx;
226                                                 }
227                                         }
228                                         continue;
229                                         // Sleep, typically for reports, to allow DB to update
230                                         // Milliseconds
231                                         
232                                 } else if ("sleep".equalsIgnoreCase(largs[idx])) {
233                                         Integer t = Integer.parseInt(largs[++idx]);
234                                         pw.println("sleep " + t);
235                                         Thread.sleep(t);
236                                         ++idx;
237                                         continue;
238                                 } else if ("delay".equalsIgnoreCase(largs[idx])) {
239                                         delay = Integer.parseInt(largs[++idx]);
240                                         pw.println("delay " + delay);
241                                         ++idx;
242                                         continue;
243                                 } else if ("pause".equalsIgnoreCase(largs[idx])) {
244                                         pw.println("Press <Return> to continue...");
245                                         ++idx;
246                                         // Sonar insists we do something with the string, though it's only a pause.  Not very helpful...
247                                         String sonar = new BufferedReader(new InputStreamReader(System.in)).readLine();
248                                         sonar=""; // this useless code brought to you by Sonar.
249                                         pw.print(sonar);
250                                         continue;
251                                 } else if ("exit".equalsIgnoreCase(largs[idx])) {
252                                         pw.println("Exiting...");
253                                         return false;
254                                 }
255
256                         } 
257                         
258                         if("REQUEST".equalsIgnoreCase(largs[idx])) {
259                                 request=true;
260                                 ++idx;
261                         } else if("FORCE".equalsIgnoreCase(largs[idx])) {
262                                 force="true";
263                                 ++idx;
264                         } else if("DETAILS".equalsIgnoreCase(largs[idx])) {
265                                 showDetails=true;
266                                 ++idx;
267                         } else if ("set".equalsIgnoreCase(largs[idx])) {
268                                 while (largs.length > ++idx) {
269                                         int equals = largs[idx].indexOf('=');
270                                         String tag, value;
271                                         if (equals < 0) {
272                                                 tag = largs[idx];
273                                                 value = access.getProperty(Config.AAF_APPPASS,null);
274                                                 if(value==null) {
275                                                         break;
276                                                 } else {
277                                                         value = access.decrypt(value, false);
278                                                         if(value==null) {
279                                                                 break;
280                                                         }
281                                                         access.getProperties().put(tag, value);
282                                                         pw.println("set " + tag + " <encrypted>");
283                                                 }
284                                         } else {
285                                                 tag = largs[idx].substring(0, equals);
286                                                 value = largs[idx].substring(++equals);
287                                                 pw.println("set " + tag + ' ' + value);
288                                         }
289                                         boolean isTrue = "TRUE".equalsIgnoreCase(value);
290                                         if("FORCE".equalsIgnoreCase(tag)) {
291                                                 force = value;
292                                         } else if("REQUEST".equalsIgnoreCase(tag)) {
293                                                 request = isTrue;
294                                         } else if("DETAILS".equalsIgnoreCase(tag)) {
295                                                 showDetails = isTrue;
296                                         } else {
297                                                 access.getProperties().put(tag, value);
298                                         }
299                                 }
300                                 continue;
301                                 // Allow Script to indicate if Failure is what is expected
302                         }
303
304                         int ret = 0;
305                         for (Cmd c : cmds) {
306                                 if (largs[idx].equalsIgnoreCase(c.getName())) {
307                                         if (verbose) {
308                                                 pw.println(line);
309                                                 if (expect.size() > 0) {
310                                                         pw.print("** Expect ");
311                                                         boolean first = true;
312                                                         for (Integer i : expect) {
313                                                                 if (first) {
314                                                                         first = false;
315                                                                 } else {
316                                                                         pw.print(',');
317                                                                 }
318                                                                 pw.print(i);
319                                                         }
320                                                         pw.println(" **");
321                                                 }
322                                         }
323                                         try {
324                                                 ret = c.exec(++idx, largs);
325                                                 if (delay+globalDelay > 0) {
326                                                         Thread.sleep((long)(delay+globalDelay));
327                                                 }
328                                         } catch (Exception e) {
329                                                 if (expect.contains(-1)) {
330                                                         pw.println(e.getMessage());
331                                                         ret = -1;
332                                                 } else {
333                                                         throw e;
334                                                 }
335                                         } finally {
336                                                 clearSingleLineProperties();
337                                         }
338                                         rv = expect.isEmpty() ? true : expect.contains(ret);
339                                         if (verbose) {
340                                                 if (rv) {
341                                                         pw.println();
342                                                 } else {
343                                                         pw.print("!!! Unexpected Return Code: ");
344                                                         pw.print(ret);
345                                                         pw.println(", VALIDATE OUTPUT!!!");
346                                                 }
347                                         }
348                                         return rv;
349                                 }
350                         }
351                         pw.write("Unknown Instruction \"");
352                         pw.write(largs[idx]);
353                         pw.write("\"\n");
354                         idx = largs.length;// always end after one command
355                 }
356                 return rv;
357         }
358
359         private String[] argEval(String line) {
360                 StringBuilder sb = new StringBuilder();
361                 ArrayList<String> arr = new ArrayList<>();
362                 boolean start = true;
363                 char quote = 0;
364                 char last = 0;
365                 for (int i = 0; i < line.length(); ++i) {
366                         char ch;
367                         if (Character.isWhitespace(ch = line.charAt(i))) {
368                                 if (start || last==',') {
369                                         continue; // trim
370                                 } else if (quote != 0) {
371                                         sb.append(ch);
372                                 } else {
373                                         arr.add(sb.toString());
374                                         sb.setLength(0);
375                                         start = true;
376                                 }
377                         } else if (ch == '\'' || ch == '"') { // toggle
378                                 if (quote == ch) {
379                                         quote = 0;
380                                 } else {
381                                         quote = ch;
382                                 }
383                         } else if(ch=='|' && quote==0) {
384                                 arr.add(sb.toString());
385                                 sb.setLength(0);
386                                 start = true;
387                         } else {
388                                 start = false;
389                                 sb.append(ch);
390                                 last = ch;
391                         }
392                 }
393                 if (sb.length() > 0) {
394                         arr.add(sb.toString());
395                 }
396
397                 String[] rv = new String[arr.size()];
398                 arr.toArray(rv);
399                 return rv;
400         }
401
402         public static void keyboardHelp() {
403                 System.out.println("'C-' means hold the ctrl key down while pressing the next key.");
404                 System.out.println("'M-' means hold the alt key down while pressing the next key.");
405                 System.out.println("For instance, C-b means hold ctrl key and press b, M-b means hold alt and press b\n");
406
407                 System.out.println("Basic Keybindings:");
408                 System.out.println("\tC-l - clear screen");        
409                 System.out.println("\tC-a - beginning of line");
410                 System.out.println("\tC-e - end of line");
411                 System.out.println("\tC-b - backward character (left arrow also works)");
412                 System.out.println("\tM-b - backward word");
413                 System.out.println("\tC-f - forward character (right arrow also works)");
414                 System.out.println("\tM-f - forward word");
415                 System.out.println("\tC-d - delete character under cursor");
416                 System.out.println("\tM-d - delete word forward");
417                 System.out.println("\tM-backspace - delete word backward");
418                 System.out.println("\tC-k - delete from cursor to end of line");
419                 System.out.println("\tC-u - delete entire line, regardless of cursor position\n");
420
421                 System.out.println("Command History:");
422                 System.out.println("\tC-r - search backward in history (repeating C-r continues the search)");
423                 System.out.println("\tC-p - move backwards through history (up arrow also works)");
424                 System.out.println("\tC-n - move forwards through history (down arrow also works)\n");
425
426         }
427
428         /**
429          * @param args
430          */
431         public static void main(String[] args) {
432                 int rv = 0;
433                 
434                 try {
435                         AAFSSO aafsso = new AAFSSO(args);
436                         try {
437                                 PropAccess access = aafsso.access();
438                                 if(aafsso.ok()) {
439                                         Define.set(access);
440                                         AuthzEnv env = new AuthzEnv(access);
441                                         
442                                         Reader rdr = null;
443                                         boolean exitOnFailure = true;
444                                         /*
445                                          * Check for "-" options anywhere in command line
446                                          */
447                                         StringBuilder sb = new StringBuilder();
448                                         for (int i = 0; i < args.length; ++i) {
449                                                 if ("-i".equalsIgnoreCase(args[i])) {
450                                                         rdr = new InputStreamReader(System.in);
451                                                         // } else if("-o".equalsIgnoreCase(args[i])) {
452                                                         // // shall we do something different? Output stream is
453                                                         // already done...
454                                                 } else if ("-f".equalsIgnoreCase(args[i])) {
455                                                         if (args.length > i + 1) {
456                                                                 rdr = new FileReader(args[++i]);
457                                                         }
458                                                 } else if ("-a".equalsIgnoreCase(args[i])) {
459                                                         exitOnFailure = false;
460                                                 } else if ("-c".equalsIgnoreCase(args[i])) {
461                                                         isConsole = true;
462                                                 } else if ("-s".equalsIgnoreCase(args[i]) && args.length > i + 1) {
463                                                         access.setProperty(Cmd.STARTDATE, args[++i]);
464                                                 } else if ("-e".equalsIgnoreCase(args[i]) && args.length > i + 1) {
465                                                         access.setProperty(Cmd.ENDDATE, args[++i]);
466                                                 } else if ("-t".equalsIgnoreCase(args[i])) {
467                                                         isTest = true;
468                                                 } else if ("-d".equalsIgnoreCase(args[i])) {
469                                                         showDetails = true;
470                                                 } else if ("-n".equalsIgnoreCase(args[i])) {
471                                                         ignoreDelay = true;
472                                                 } else {
473                                                         if (sb.length() > 0) {
474                                                                 sb.append(' ');
475                                                         }
476                                                         sb.append(args[i]);
477                                                 }
478                                         }
479                                         
480                                         AAFConHttp aafcon = new AAFConHttp(access);
481 //                                      
482 //                                      SecurityInfoC<?> si = aafcon.securityInfo();
483 //                                      Locator<URI> loc;
484                                         
485                                         aafsso.setLogDefault();
486                                         aafsso.setStdErrDefault();
487         
488                                         // Note, with AAF Locator, this may not longer be necessary 3/2018 Jonathan
489                                         if(!aafsso.loginOnly()) {
490 //                                              try {
491 //                                                      loc = new AAFLocator(si,new URI(access.getProperty(Config.AAF_URL)));
492 //                                              } catch (Throwable t) {
493 //                                                      aafsso.setStdErrDefault();
494 //                                                      throw t;
495 //                                              } finally {
496 //                                                      // Other Access is done writing to StdOut and StdErr, reset Std out
497 //                                                      aafsso.setLogDefault();
498 //                                              }
499         
500                                                 TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF));
501 //                                              HMangr hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion(Config.AAF_DEFAULT_VERSION);
502                                                 
503                                                 if(access.getProperty(Config.AAF_DEFAULT_REALM)==null) {
504                                                         access.setProperty(Config.AAF_DEFAULT_REALM, "people.osaaf.org");
505                                                         aafsso.addProp(Config.AAF_DEFAULT_REALM, "people.osaaf.org");
506                                                 }
507                         
508                                                 AAFcli aafcli = new AAFcli(access,env, new OutputStreamWriter(System.out),  
509                                                                 aafcon.hman(), aafcon.securityInfo(), aafcon.securityInfo().defSS);
510 //                                                      new HBasicAuthSS(si,aafsso.user(), access.decrypt(aafsso.enc_pass(),false)));
511 //                                              }
512                                                 if(!ignoreDelay) {
513                                                         File delay = new File("aafcli.delay");
514                                                         if(delay.exists()) {
515                                                                 BufferedReader br = new BufferedReader(new FileReader(delay));
516                                                                 try {
517                                                                         globalDelay = Integer.parseInt(br.readLine());
518                                                                 } catch(Exception e) {
519                                                                         access.log(Level.DEBUG,e);
520                                                                 } finally {
521                                                                         br.close();
522                                                                 }
523                                                         }
524                                                 }
525                                                 try {
526                                                         if (isConsole) {
527                                                                 System.out.println("Type 'help' for short help or 'help -d' for detailed help with aafcli commands");
528                                                                 System.out.println("Type '?' for help with command line editing");
529                                                                 System.out.println("Type 'q', 'quit', or 'exit' to quit aafcli\n");
530                         
531                                                                 ConsoleReader reader = new ConsoleReader();
532                                                                 try {
533                                                                         reader.setPrompt("aafcli > ");
534                                 
535                                                                         String line;
536                                                                         while ((line = reader.readLine()) != null) {
537                                                                                 showDetails = (line.contains("-d"))?true:false;
538                                 
539                                                                                 if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("q") || line.equalsIgnoreCase("exit")) {
540                                                                                         break;
541                                                                                 } else if (line.equalsIgnoreCase("--help -d") || line.equalsIgnoreCase("help -d") 
542                                                                                                 || line.equalsIgnoreCase("help")) {
543                                                                                         line = "--help";
544                                                                                 } else if (line.equalsIgnoreCase("cls")) {
545                                                                                         reader.clearScreen();
546                                                                                         continue;
547                                                                                 } else if (line.equalsIgnoreCase("?")) {
548                                                                                         keyboardHelp();
549                                                                                         continue;
550                                                                                 }
551                                                                                 try {
552                                                                                         aafcli.eval(line);
553                                                                                         pw.flush();
554                                                                                 } catch (Exception e) {
555                                                                                         pw.println(e.getMessage());
556                                                                                         pw.flush();
557                                                                                 }
558                                                                         }
559                                                                 } finally {
560                                                                         reader.close();
561                                                                 }
562                                                         } else if (rdr != null) {
563                                                                 BufferedReader br = new BufferedReader(rdr);
564                                                                 String line;
565                                                                 while ((line = br.readLine()) != null) {
566                                                                         if (!aafcli.eval(line) && exitOnFailure) {
567                                                                                 rv = 1;
568                                                                                 break;
569                                                                         }
570                                                                 }
571                                                         } else { // just run the command line
572                                                                 aafcli.verbose(false);
573                                                                 if (sb.length() == 0) {
574                                                                         sb.append("--help");
575                                                                 }
576                                                                 rv = aafcli.eval(sb.toString()) ? 0 : 1;
577                                                         }
578                                                         
579                                                 } finally {
580                                                         aafcli.close();
581                         
582                                                         // Don't close if No Reader, or it's a Reader of Standard In
583                                                         if (rdr != null && !(rdr instanceof InputStreamReader)) {
584                                                                 rdr.close();
585                                                         }
586                                                 }
587                                         }
588                                 }
589                         } finally {
590                                 aafsso.close();
591                                 StringBuilder err = aafsso.err();
592                                 String noexit = aafsso.access().getProperty("no_exit");
593                                 if (err != null) {
594                                         err.append("to continue...");
595                                         System.err.println(err);
596                                 }
597                                 if(noexit==null) {
598                                         return;
599                                 }
600
601                         }
602                 } catch (MessageException e) {
603                         System.out.println("MessageException caught");
604
605                         System.err.println(e.getMessage());
606                 } catch (Throwable e) {
607                         e.printStackTrace(System.err);
608                 }
609                 System.exit(rv);
610         }
611
612         public boolean isTest() {
613                 return AAFcli.isTest;
614         }
615         
616         public boolean isDetailed() {
617                 return AAFcli.showDetails;
618         }
619
620         public String typeString(Class<?> cls, boolean json) {
621                 return "application/" + cls.getSimpleName() + "+" + (json ? "json" : "xml");//+ ";version=" + hman.apiVersion();
622         }
623
624         public String forceString() {
625                 return force;
626         }
627
628         public boolean addRequest() {
629                 return request;
630         }
631
632         public void clearSingleLineProperties() {
633                 force  = null;
634                 request = false;
635                 showDetails = false;
636         }
637
638         public void gui(boolean b) {
639                 gui  = b;
640         }
641
642 }