2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.auth.cmd;
24 import java.io.BufferedReader;
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;
34 import java.util.ArrayList;
35 import java.util.List;
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;
59 import jline.console.ConsoleReader;
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;
69 protected SecuritySetter<HttpURLConnection> ss;
70 // protected AuthzEnv env;
71 private boolean close;
72 private List<Cmd> cmds;
75 private ArrayList<Integer> expect = new ArrayList<Integer>();
76 private boolean verbose = true;
78 private SecurityInfoC<HttpURLConnection> si;
79 private boolean request = false;
80 private String force = null;
81 private boolean gui = false;
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;
93 public static int timeout() {
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);
102 public AAFcli(Access access, AuthzEnv env, Writer wtr, HMangr hman, SecurityInfoC<HttpURLConnection> si, SecuritySetter<HttpURLConnection> ss) throws APIException {
104 this.access = access;
108 if (wtr instanceof PrintWriter) {
109 pw = (PrintWriter) wtr;
112 pw = new PrintWriter(wtr);
120 cmds = new ArrayList<Cmd>();
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));
127 cmds.add(new User(this));
128 cmds.add(new NS(this));
129 cmds.add(new Mgmt(this));
132 public void verbose(boolean v) {
136 public void close() {
146 public boolean eval(String line) throws Exception {
147 if (line.length() == 0) {
149 } else if (line.startsWith("#")) {
154 String[] largs = argEval(line);
157 // Variable replacement
158 StringBuilder sb = null;
159 while (idx < largs.length) {
161 for (int v = largs[idx].indexOf("@["); v >= 0; v = largs[idx].indexOf("@[", v + 1)) {
163 sb = new StringBuilder();
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);
169 p = System.getProperty(largs[idx].substring(v+2,e));
177 if (sb != null && sb.length() > 0) {
178 sb.append(largs[idx], e, largs[idx].length());
179 largs[idx] = sb.toString();
187 while (rv && idx < largs.length) {
188 // Allow Script to change Credential
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(':');
197 pass = user.substring(colon + 1);
198 user = user.substring(0, colon);
200 pass = access.getProperty(user, 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
209 pw.println("ERROR: No password set for " + user);
214 } else if ("expect".equalsIgnoreCase(largs[idx])) {
216 if (largs.length > idx++) {
217 if (!"nothing".equals(largs[idx])) {
218 for (String str : largs[idx].split(",")) {
220 if ("Exception".equalsIgnoreCase(str)) {
223 expect.add(Integer.parseInt(str));
225 } catch (NumberFormatException e) {
226 throw new CadiException("\"expect\" should be followed by Number");
233 // Sleep, typically for reports, to allow DB to update
236 } else if ("sleep".equalsIgnoreCase(largs[idx])) {
237 Integer t = Integer.parseInt(largs[++idx]);
238 pw.println("sleep " + t);
242 } else if ("delay".equalsIgnoreCase(largs[idx])) {
243 delay = Integer.parseInt(largs[++idx]);
244 pw.println("delay " + delay);
247 } else if ("pause".equalsIgnoreCase(largs[idx])) {
248 pw.println("Press <Return> to continue...");
250 // Sonar insists we do something with the string, though it's only a pause. Not very helpful...
251 String sonar = new BufferedReader(new InputStreamReader(System.in)).readLine();
252 sonar=""; // this useless code brought to you by Sonar.
255 } else if ("exit".equalsIgnoreCase(largs[idx])) {
256 pw.println("Exiting...");
262 if("REQUEST".equalsIgnoreCase(largs[idx])) {
265 } else if("FORCE".equalsIgnoreCase(largs[idx])) {
268 } else if("DETAILS".equalsIgnoreCase(largs[idx])) {
271 } else if ("set".equalsIgnoreCase(largs[idx])) {
272 while (largs.length > ++idx) {
273 int equals = largs[idx].indexOf('=');
277 value = access.getProperty(Config.AAF_APPPASS,null);
281 value = access.decrypt(value, false);
285 access.getProperties().put(tag, value);
286 pw.println("set " + tag + " <encrypted>");
289 tag = largs[idx].substring(0, equals);
290 value = largs[idx].substring(++equals);
291 pw.println("set " + tag + ' ' + value);
293 boolean isTrue = "TRUE".equalsIgnoreCase(value);
294 if("FORCE".equalsIgnoreCase(tag)) {
296 } else if("REQUEST".equalsIgnoreCase(tag)) {
298 } else if("DETAILS".equalsIgnoreCase(tag)) {
299 showDetails = isTrue;
301 access.getProperties().put(tag, value);
305 // Allow Script to indicate if Failure is what is expected
310 if (largs[idx].equalsIgnoreCase(c.getName())) {
313 if (expect.size() > 0) {
314 pw.print("** Expect ");
315 boolean first = true;
316 for (Integer i : expect) {
328 ret = c.exec(++idx, largs);
329 if (delay+globalDelay > 0) {
330 Thread.sleep((long)(delay+globalDelay));
332 } catch (Exception e) {
333 if (expect.contains(-1)) {
334 pw.println(e.getMessage());
340 clearSingleLineProperties();
342 rv = expect.isEmpty() ? true : expect.contains(ret);
347 pw.print("!!! Unexpected Return Code: ");
349 pw.println(", VALIDATE OUTPUT!!!");
355 pw.write("Unknown Instruction \"");
356 pw.write(largs[idx]);
358 idx = largs.length;// always end after one command
363 private String[] argEval(String line) {
364 StringBuilder sb = new StringBuilder();
365 ArrayList<String> arr = new ArrayList<String>();
366 boolean start = true;
369 for (int i = 0; i < line.length(); ++i) {
371 if (Character.isWhitespace(ch = line.charAt(i))) {
372 if (start || last==',') {
374 } else if (quote != 0) {
377 arr.add(sb.toString());
381 } else if (ch == '\'' || ch == '"') { // toggle
387 } else if(ch=='|' && quote==0) {
388 arr.add(sb.toString());
397 if (sb.length() > 0) {
398 arr.add(sb.toString());
401 String[] rv = new String[arr.size()];
406 public static void keyboardHelp() {
407 System.out.println("'C-' means hold the ctrl key down while pressing the next key.");
408 System.out.println("'M-' means hold the alt key down while pressing the next key.");
409 System.out.println("For instance, C-b means hold ctrl key and press b, M-b means hold alt and press b\n");
411 System.out.println("Basic Keybindings:");
412 System.out.println("\tC-l - clear screen");
413 System.out.println("\tC-a - beginning of line");
414 System.out.println("\tC-e - end of line");
415 System.out.println("\tC-b - backward character (left arrow also works)");
416 System.out.println("\tM-b - backward word");
417 System.out.println("\tC-f - forward character (right arrow also works)");
418 System.out.println("\tM-f - forward word");
419 System.out.println("\tC-d - delete character under cursor");
420 System.out.println("\tM-d - delete word forward");
421 System.out.println("\tM-backspace - delete word backward");
422 System.out.println("\tC-k - delete from cursor to end of line");
423 System.out.println("\tC-u - delete entire line, regardless of cursor position\n");
425 System.out.println("Command History:");
426 System.out.println("\tC-r - search backward in history (repeating C-r continues the search)");
427 System.out.println("\tC-p - move backwards through history (up arrow also works)");
428 System.out.println("\tC-n - move forwards through history (down arrow also works)\n");
435 public static void main(String[] args) {
439 AAFSSO aafsso = new AAFSSO(args);
441 PropAccess access = aafsso.access();
443 AuthzEnv env = new AuthzEnv(access);
445 StringBuilder err = aafsso.err();
446 String noexit = access.getProperty("no_exit");
448 err.append("to continue...");
449 System.err.println(err);
456 boolean exitOnFailure = true;
458 * Check for "-" options anywhere in command line
460 StringBuilder sb = new StringBuilder();
461 for (int i = 0; i < args.length; ++i) {
462 if ("-i".equalsIgnoreCase(args[i])) {
463 rdr = new InputStreamReader(System.in);
464 // } else if("-o".equalsIgnoreCase(args[i])) {
465 // // shall we do something different? Output stream is
467 } else if ("-f".equalsIgnoreCase(args[i])) {
468 if (args.length > i + 1) {
469 rdr = new FileReader(args[++i]);
471 } else if ("-a".equalsIgnoreCase(args[i])) {
472 exitOnFailure = false;
473 } else if ("-c".equalsIgnoreCase(args[i])) {
475 } else if ("-s".equalsIgnoreCase(args[i]) && args.length > i + 1) {
476 access.setProperty(Cmd.STARTDATE, args[++i]);
477 } else if ("-e".equalsIgnoreCase(args[i]) && args.length > i + 1) {
478 access.setProperty(Cmd.ENDDATE, args[++i]);
479 } else if ("-t".equalsIgnoreCase(args[i])) {
481 } else if ("-d".equalsIgnoreCase(args[i])) {
483 } else if ("-n".equalsIgnoreCase(args[i])) {
486 if (sb.length() > 0) {
493 SecurityInfoC<HttpURLConnection> si = SecurityInfoC.instance(access, HttpURLConnection.class);
495 String aafUrl = access.getProperty(Config.AAF_URL);
497 aafsso.setLogDefault();
498 aafsso.setStdErrDefault();
499 aafUrl=AAFSSO.cons.readLine("aaf_url=%s", HTTPS);
500 if(aafUrl.length()==0) {
502 } else if(!aafUrl.startsWith(HTTPS)) {
505 aafsso.addProp(Config.AAF_URL, aafUrl);
507 // Note, with AAF Locator, this may not longer be necessary 3/2018 Jonathan
508 if(!aafsso.loginOnly()) {
510 loc = new AAFLocator(si,new URI(aafUrl));
511 } catch (Throwable t) {
512 aafsso.setStdErrDefault();
515 // Other Access is done writing to StdOut and StdErr, reset Std out
516 aafsso.setLogDefault();
519 TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF));
520 HMangr hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");
522 if(access.getProperty(Config.AAF_DEFAULT_REALM)==null) {
523 access.log(Level.ERROR, Config.AAF_DEFAULT_REALM,"is required");
527 AAFcli aafcli = new AAFcli(access,env, new OutputStreamWriter(System.out), hman, si,
528 new HBasicAuthSS(si,aafsso.user(), access.decrypt(aafsso.enc_pass(),false)));
530 File delay = new File("aafcli.delay");
532 BufferedReader br = new BufferedReader(new FileReader(delay));
534 globalDelay = Integer.parseInt(br.readLine());
535 } catch(Exception e) {
536 access.log(Level.DEBUG,e);
544 System.out.println("Type 'help' for short help or 'help -d' for detailed help with aafcli commands");
545 System.out.println("Type '?' for help with command line editing");
546 System.out.println("Type 'q', 'quit', or 'exit' to quit aafcli\n");
548 ConsoleReader reader = new ConsoleReader();
550 reader.setPrompt("aafcli > ");
553 while ((line = reader.readLine()) != null) {
554 showDetails = (line.contains("-d"))?true:false;
556 if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("q") || line.equalsIgnoreCase("exit")) {
558 } else if (line.equalsIgnoreCase("--help -d") || line.equalsIgnoreCase("help -d")
559 || line.equalsIgnoreCase("help")) {
561 } else if (line.equalsIgnoreCase("cls")) {
562 reader.clearScreen();
564 } else if (line.equalsIgnoreCase("?")) {
571 } catch (Exception e) {
572 pw.println(e.getMessage());
579 } else if (rdr != null) {
580 BufferedReader br = new BufferedReader(rdr);
582 while ((line = br.readLine()) != null) {
583 if (!aafcli.eval(line) && exitOnFailure) {
588 } else { // just run the command line
589 aafcli.verbose(false);
590 if (sb.length() == 0) {
593 rv = aafcli.eval(sb.toString()) ? 0 : 1;
599 // Don't close if No Reader, or it's a Reader of Standard In
600 if (rdr != null && !(rdr instanceof InputStreamReader)) {
610 } catch (MessageException e) {
611 System.out.println("MessageException caught");
613 System.err.println(e.getMessage());
614 } catch (Throwable e) {
615 e.printStackTrace(System.err);
620 public boolean isTest() {
621 return AAFcli.isTest;
624 public boolean isDetailed() {
625 return AAFcli.showDetails;
628 public String typeString(Class<?> cls, boolean json) {
629 return "application/" + cls.getSimpleName() + "+" + (json ? "json" : "xml") + ";version=" + hman.apiVersion();
632 public String forceString() {
636 public boolean addRequest() {
640 public void clearSingleLineProperties() {
646 public void gui(boolean b) {