Add Cert Cred for aafcli
[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 {
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 {
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                 /*
117                  * Create Cmd Tree
118                  */
119                 cmds = new ArrayList<Cmd>();
120
121                 Role role = new Role(this);
122                 cmds.add(new Help(this, cmds));
123                 cmds.add(new Version(this));
124                 cmds.add(new Perm(role));
125                 cmds.add(role);
126                 cmds.add(new User(this));
127                 cmds.add(new NS(this));
128                 cmds.add(new Mgmt(this));
129         }
130
131         public void verbose(boolean v) {
132                 verbose = v;
133         }
134
135         public void close() {
136                 if (hman != null) {
137                         hman.close();
138                         hman = null;
139                 }
140                 if (close) {
141                         pw.close();
142                 }
143         }
144
145         public boolean eval(String line) throws Exception {
146                 if (line.length() == 0) {
147                         return true;
148                 } else if (line.startsWith("#")) {
149                         pw.println(line);
150                         return true;
151                 }
152
153                 String[] largs = argEval(line);
154                 int idx = 0;
155
156                 // Variable replacement
157                 StringBuilder sb = null;
158                 while (idx < largs.length) {
159                         int e = 0;
160                         for (int v = largs[idx].indexOf("@["); v >= 0; v = largs[idx].indexOf("@[", v + 1)) {
161                                 if (sb == null) {
162                                         sb = new StringBuilder();
163                                 }
164                                 sb.append(largs[idx], e, v);
165                                 if ((e = largs[idx].indexOf(']', v)) >= 0) {
166                                         String p = access.getProperty(largs[idx].substring(v + 2, e),null);
167                                         if(p==null) {
168                                                 p = System.getProperty(largs[idx].substring(v+2,e));
169                                         }
170                                         ++e;
171                                         if (p != null) {
172                                                 sb.append(p);
173                                         }
174                                 }
175                         }
176                         if (sb != null && sb.length() > 0) {
177                                 sb.append(largs[idx], e, largs[idx].length());
178                                 largs[idx] = sb.toString();
179                                 sb.setLength(0);
180                         }
181                         ++idx;
182                 }
183
184                 idx = 0;
185                 boolean rv = true;
186                 while (rv && idx < largs.length) {
187                         // Allow Script to change Credential
188                         if (!gui) {
189                                 if("as".equalsIgnoreCase(largs[idx])) {
190                                         if (largs.length > ++idx) {
191                                                 // get Password from Props with ID as Key
192                                                 String user = largs[idx++];
193                                                 int colon = user.indexOf(':');
194                                                 String pass;
195                                                 if (colon > 0) {
196                                                         pass = user.substring(colon + 1);
197                                                         user = user.substring(0, colon);
198                                                 } else {
199                                                         pass = access.getProperty(user, null);
200                                                 }
201                                                 if (pass != null) {
202                                                         pass = access.decrypt(pass, false);
203                                                         access.getProperties().put(user, pass);
204                                                         ss = new HBasicAuthSS(si, user, pass);
205                                                         pw.println("as " + user);
206                                                 } else { // get Pass from System Properties, under name of
207                                                         // Tag
208                                                         pw.println("ERROR: No password set for " + user);
209                                                         rv = false;
210                                                 }
211                                                 continue;
212                                         }
213                                 } else if ("expect".equalsIgnoreCase(largs[idx])) {
214                                         expect.clear();
215                                         if (largs.length > idx++) {
216                                                 if (!"nothing".equals(largs[idx])) {
217                                                         for (String str : largs[idx].split(",")) {
218                                                                 try {
219                                                                         if ("Exception".equalsIgnoreCase(str)) {
220                                                                                 expect.add(-1);
221                                                                         } else {
222                                                                                 expect.add(Integer.parseInt(str));
223                                                                         }
224                                                                 } catch (NumberFormatException e) {
225                                                                         throw new CadiException("\"expect\" should be followed by Number");
226                                                                 }
227                                                         }
228                                                 ++idx;
229                                                 }
230                                         }
231                                         continue;
232                                         // Sleep, typically for reports, to allow DB to update
233                                         // Milliseconds
234                                         
235                                 } else if ("sleep".equalsIgnoreCase(largs[idx])) {
236                                         Integer t = Integer.parseInt(largs[++idx]);
237                                         pw.println("sleep " + t);
238                                         Thread.sleep(t);
239                                         ++idx;
240                                         continue;
241                                 } else if ("delay".equalsIgnoreCase(largs[idx])) {
242                                         delay = Integer.parseInt(largs[++idx]);
243                                         pw.println("delay " + delay);
244                                         ++idx;
245                                         continue;
246                                 } else if ("pause".equalsIgnoreCase(largs[idx])) {
247                                         pw.println("Press <Return> to continue...");
248                                         ++idx;
249                                         // Sonar insists we do something with the string, though it's only a pause.  Not very helpful...
250                                         String sonar = new BufferedReader(new InputStreamReader(System.in)).readLine();
251                                         sonar=""; // this useless code brought to you by Sonar.
252                                         pw.print(sonar);
253                                         continue;
254                                 } else if ("exit".equalsIgnoreCase(largs[idx])) {
255                                         pw.println("Exiting...");
256                                         return false;
257                                 }
258
259                         } 
260                         
261                         if("REQUEST".equalsIgnoreCase(largs[idx])) {
262                                 request=true;
263                                 ++idx;
264                         } else if("FORCE".equalsIgnoreCase(largs[idx])) {
265                                 force="true";
266                                 ++idx;
267                         } else if("DETAILS".equalsIgnoreCase(largs[idx])) {
268                                 showDetails=true;
269                                 ++idx;
270                         } else if ("set".equalsIgnoreCase(largs[idx])) {
271                                 while (largs.length > ++idx) {
272                                         int equals = largs[idx].indexOf('=');
273                                         String tag, value;
274                                         if (equals < 0) {
275                                                 tag = largs[idx];
276                                                 value = access.getProperty(Config.AAF_APPPASS,null);
277                                                 if(value==null) {
278                                                         break;
279                                                 } else {
280                                                         value = access.decrypt(value, false);
281                                                         if(value==null) {
282                                                                 break;
283                                                         }
284                                                         access.getProperties().put(tag, value);
285                                                         pw.println("set " + tag + " <encrypted>");
286                                                 }
287                                         } else {
288                                                 tag = largs[idx].substring(0, equals);
289                                                 value = largs[idx].substring(++equals);
290                                                 pw.println("set " + tag + ' ' + value);
291                                         }
292                                         boolean isTrue = "TRUE".equalsIgnoreCase(value);
293                                         if("FORCE".equalsIgnoreCase(tag)) {
294                                                 force = value;
295                                         } else if("REQUEST".equalsIgnoreCase(tag)) {
296                                                 request = isTrue;
297                                         } else if("DETAILS".equalsIgnoreCase(tag)) {
298                                                 showDetails = isTrue;
299                                         } else {
300                                                 access.getProperties().put(tag, value);
301                                         }
302                                 }
303                                 continue;
304                                 // Allow Script to indicate if Failure is what is expected
305                         }
306
307                         int ret = 0;
308                         for (Cmd c : cmds) {
309                                 if (largs[idx].equalsIgnoreCase(c.getName())) {
310                                         if (verbose) {
311                                                 pw.println(line);
312                                                 if (expect.size() > 0) {
313                                                         pw.print("** Expect ");
314                                                         boolean first = true;
315                                                         for (Integer i : expect) {
316                                                                 if (first) {
317                                                                         first = false;
318                                                                 } else {
319                                                                         pw.print(',');
320                                                                 }
321                                                                 pw.print(i);
322                                                         }
323                                                         pw.println(" **");
324                                                 }
325                                         }
326                                         try {
327                                                 ret = c.exec(++idx, largs);
328                                                 if (delay+globalDelay > 0) {
329                                                         Thread.sleep((long)(delay+globalDelay));
330                                                 }
331                                         } catch (Exception e) {
332                                                 if (expect.contains(-1)) {
333                                                         pw.println(e.getMessage());
334                                                         ret = -1;
335                                                 } else {
336                                                         throw e;
337                                                 }
338                                         } finally {
339                                                 clearSingleLineProperties();
340                                         }
341                                         rv = expect.isEmpty() ? true : expect.contains(ret);
342                                         if (verbose) {
343                                                 if (rv) {
344                                                         pw.println();
345                                                 } else {
346                                                         pw.print("!!! Unexpected Return Code: ");
347                                                         pw.print(ret);
348                                                         pw.println(", VALIDATE OUTPUT!!!");
349                                                 }
350                                         }
351                                         return rv;
352                                 }
353                         }
354                         pw.write("Unknown Instruction \"");
355                         pw.write(largs[idx]);
356                         pw.write("\"\n");
357                         idx = largs.length;// always end after one command
358                 }
359                 return rv;
360         }
361
362         private String[] argEval(String line) {
363                 StringBuilder sb = new StringBuilder();
364                 ArrayList<String> arr = new ArrayList<String>();
365                 boolean start = true;
366                 char quote = 0;
367                 char last = 0;
368                 for (int i = 0; i < line.length(); ++i) {
369                         char ch;
370                         if (Character.isWhitespace(ch = line.charAt(i))) {
371                                 if (start || last==',') {
372                                         continue; // trim
373                                 } else if (quote != 0) {
374                                         sb.append(ch);
375                                 } else {
376                                         arr.add(sb.toString());
377                                         sb.setLength(0);
378                                         start = true;
379                                 }
380                         } else if (ch == '\'' || ch == '"') { // toggle
381                                 if (quote == ch) {
382                                         quote = 0;
383                                 } else {
384                                         quote = ch;
385                                 }
386                         } else if(ch=='|' && quote==0) {
387                                 arr.add(sb.toString());
388                                 sb.setLength(0);
389                                 start = true;
390                         } else {
391                                 start = false;
392                                 sb.append(ch);
393                                 last = ch;
394                         }
395                 }
396                 if (sb.length() > 0) {
397                         arr.add(sb.toString());
398                 }
399
400                 String[] rv = new String[arr.size()];
401                 arr.toArray(rv);
402                 return rv;
403         }
404
405         public static void keyboardHelp() {
406                 System.out.println("'C-' means hold the ctrl key down while pressing the next key.");
407                 System.out.println("'M-' means hold the alt key down while pressing the next key.");
408                 System.out.println("For instance, C-b means hold ctrl key and press b, M-b means hold alt and press b\n");
409
410                 System.out.println("Basic Keybindings:");
411                 System.out.println("\tC-l - clear screen");        
412                 System.out.println("\tC-a - beginning of line");
413                 System.out.println("\tC-e - end of line");
414                 System.out.println("\tC-b - backward character (left arrow also works)");
415                 System.out.println("\tM-b - backward word");
416                 System.out.println("\tC-f - forward character (right arrow also works)");
417                 System.out.println("\tM-f - forward word");
418                 System.out.println("\tC-d - delete character under cursor");
419                 System.out.println("\tM-d - delete word forward");
420                 System.out.println("\tM-backspace - delete word backward");
421                 System.out.println("\tC-k - delete from cursor to end of line");
422                 System.out.println("\tC-u - delete entire line, regardless of cursor position\n");
423
424                 System.out.println("Command History:");
425                 System.out.println("\tC-r - search backward in history (repeating C-r continues the search)");
426                 System.out.println("\tC-p - move backwards through history (up arrow also works)");
427                 System.out.println("\tC-n - move forwards through history (down arrow also works)\n");
428
429         }
430
431         /**
432          * @param args
433          */
434         public static void main(String[] args) {
435                 int rv = 0;
436                 
437                 try {
438                         AAFSSO aafsso = new AAFSSO(args);
439                         try {
440                                 PropAccess access = aafsso.access();
441                                 if(aafsso.ok()) {
442                                         Define.set(access);
443                                         AuthzEnv env = new AuthzEnv(access);
444                                         
445                                         Reader rdr = null;
446                                         boolean exitOnFailure = true;
447                                         /*
448                                          * Check for "-" options anywhere in command line
449                                          */
450                                         StringBuilder sb = new StringBuilder();
451                                         for (int i = 0; i < args.length; ++i) {
452                                                 if ("-i".equalsIgnoreCase(args[i])) {
453                                                         rdr = new InputStreamReader(System.in);
454                                                         // } else if("-o".equalsIgnoreCase(args[i])) {
455                                                         // // shall we do something different? Output stream is
456                                                         // already done...
457                                                 } else if ("-f".equalsIgnoreCase(args[i])) {
458                                                         if (args.length > i + 1) {
459                                                                 rdr = new FileReader(args[++i]);
460                                                         }
461                                                 } else if ("-a".equalsIgnoreCase(args[i])) {
462                                                         exitOnFailure = false;
463                                                 } else if ("-c".equalsIgnoreCase(args[i])) {
464                                                         isConsole = true;
465                                                 } else if ("-s".equalsIgnoreCase(args[i]) && args.length > i + 1) {
466                                                         access.setProperty(Cmd.STARTDATE, args[++i]);
467                                                 } else if ("-e".equalsIgnoreCase(args[i]) && args.length > i + 1) {
468                                                         access.setProperty(Cmd.ENDDATE, args[++i]);
469                                                 } else if ("-t".equalsIgnoreCase(args[i])) {
470                                                         isTest = true;
471                                                 } else if ("-d".equalsIgnoreCase(args[i])) {
472                                                         showDetails = true;
473                                                 } else if ("-n".equalsIgnoreCase(args[i])) {
474                                                         ignoreDelay = true;
475                                                 } else {
476                                                         if (sb.length() > 0) {
477                                                                 sb.append(' ');
478                                                         }
479                                                         sb.append(args[i]);
480                                                 }
481                                         }
482                 
483                                         SecurityInfoC<HttpURLConnection> si = SecurityInfoC.instance(access, HttpURLConnection.class);
484                                         Locator<URI> loc;
485                                         
486                                         aafsso.setLogDefault();
487                                         aafsso.setStdErrDefault();
488         
489                                         // Note, with AAF Locator, this may not longer be necessary 3/2018 Jonathan
490                                         if(!aafsso.loginOnly()) {
491                                                 try {
492                                                         loc = new AAFLocator(si,new URI(access.getProperty(Config.AAF_URL)));
493                                                 } catch (Throwable t) {
494                                                         aafsso.setStdErrDefault();
495                                                         throw t;
496                                                 } finally {
497                                                         // Other Access is done writing to StdOut and StdErr, reset Std out
498                                                         aafsso.setLogDefault();
499                                                 }
500         
501                                                 TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF));
502                                                 HMangr hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion(Config.AAF_DEFAULT_VERSION);
503                                                 
504                                                 if(access.getProperty(Config.AAF_DEFAULT_REALM)==null) {
505                                                         access.setProperty(Config.AAF_DEFAULT_REALM, "people.osaaf.org");
506                                                         aafsso.addProp(Config.AAF_DEFAULT_REALM, "people.osaaf.org");
507                                                 }
508                         
509                                                 
510                                                 AAFcli aafcli = new AAFcli(access,env, new OutputStreamWriter(System.out), hman, si, 
511                                                         new HBasicAuthSS(si,aafsso.user(), access.decrypt(aafsso.enc_pass(),false)));
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 }