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