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