Fix Agent and CM Issues
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / configure / Agent.java
index aa9bf13..74f0916 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -28,7 +28,6 @@ import java.io.IOException;
 import java.net.ConnectException;
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
-import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.nio.file.Files;
 import java.security.KeyPair;
@@ -52,6 +51,7 @@ import org.onap.aaf.cadi.CmdLine;
 import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.PropAccess;
 import org.onap.aaf.cadi.Symm;
+import org.onap.aaf.cadi.aaf.TestConnectivity;
 import org.onap.aaf.cadi.aaf.client.ErrMessage;
 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
 import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
@@ -87,17 +87,17 @@ import locate.v1_1.Configuration.Props;
 
 public class Agent {
     private static final String AGENT_LOAD_URLS = "Agent:loadURLs";
-       private static final String HASHES = "################################################################";
+    private static final String HASHES = "################################################################";
     private static final String PRINT = "print";
     private static final String FILE = "file";
     public static final String PKCS12 = "pkcs12";
     public static final String JKS = "jks";
     private static final String SCRIPT="script";
-    
+
     private static final String CM_VER = "1.0";
     public static final int PASS_SIZE = 24;
     private static int TIMEOUT;
-    
+
     private static RosettaDF<CertificateRequest> reqDF;
     private static RosettaDF<CertInfo> certDF;
     private static RosettaDF<Artifacts> artifactsDF;
@@ -106,10 +106,10 @@ public class Agent {
     private static ErrMessage errMsg;
     private static Map<String,PlaceArtifact> placeArtifact;
     private static RosettaEnv env;
-    
+
     private static boolean doExit;
     private static AAFCon<?> aafcon;
-    
+
     private static List<String> CRED_TAGS = Arrays.asList(new String[] {
             Config.CADI_KEYFILE,
             Config.AAF_APPID, Config.AAF_APPPASS,
@@ -118,10 +118,11 @@ public class Agent {
             Config.CADI_ALIAS, Config.CADI_X509_ISSUERS
             });
     private static List<String> LOC_TAGS = Arrays.asList(new String[] {
-               Config.CADI_LATITUDE, Config.CADI_LONGITUDE
-               });
+            Config.CADI_LATITUDE, Config.CADI_LONGITUDE
+            });
     // Note: This is set by loadURLs. Use that function as singleton, not directly.
-       private static Map<String,String> aaf_urls = null;
+    private static Map<String,String> aaf_urls = null;
+    private static boolean configNoPasswd = false;
 
 
     public static void main(String[] args) {
@@ -137,80 +138,89 @@ public class Agent {
                 System.out.println(HASHES);
             }
             CmdLine.main(newArgs);
+        } else if(args.length>0 && "connectivity".equals(args[0])) {
+            String[] newArgs = new String[args.length-1];
+            System.arraycopy(args, 1, newArgs, 0, newArgs.length);
+            if(newArgs.length>0 && newArgs[0].indexOf('@')>=0) {
+                newArgs[0]=FQI.reverseDomain(newArgs[0])+".props";
+            }
+            TestConnectivity.main(newArgs);
         } else {
             try {
                 AAFSSO aafsso=null;
-                PropAccess access=null; 
-                
-               String hasEtc = null;
+                PropAccess access=null;
+
+                String hasEtc = null;
                 for(String a : args) {
-                       if(a.startsWith(Config.CADI_PROP_FILES)) {
-                               access = new PropAccess(args);
-                               break;
-                       } else if(a.startsWith(Config.CADI_ETCDIR)) {
-                               int idx = a.indexOf('=');
-                               if(idx>=0 && idx<a.length()) {
-                                       hasEtc = a.substring(idx+1);
-                               }
-                       }
+                    if(a.startsWith(Config.CADI_PROP_FILES)) {
+                        access = new PropAccess(args);
+                        break;
+                    } else if(a.startsWith(Config.CADI_ETCDIR)) {
+                        int idx = a.indexOf('=');
+                        if(idx>=0 && idx<a.length()) {
+                            hasEtc = a.substring(idx+1);
+                        }
+                    } else if(a.equals("--nopasswd")) {
+                        configNoPasswd=true;
+                    }
                 }
-                
+
                 if(access==null) {
-                       if(args.length>1 && args[1].contains("@")) {
-                               String domain = FQI.reverseDomain(args[1]);
-                               if(domain!=null) {
-                                       if(hasEtc==null) {
-                                               hasEtc = ".";
-                                       }
-                                       File etc = new File(hasEtc);
-                                       if(etc.exists()) {
-                                               File nsprops = new File(etc,domain+".props");
-                                               if(nsprops.exists()) {
-                                                       access = new PropAccess(new String[] {Config.CADI_PROP_FILES+'='+nsprops.getAbsolutePath()});
-                                               }
-                                       }
-                               }
-                       } 
+                    if(args.length>1 && args[1].contains("@")) {
+                        String domain = FQI.reverseDomain(args[1]);
+                        if(domain!=null) {
+                            if(hasEtc==null) {
+                                hasEtc = ".";
+                            }
+                            File etc = new File(hasEtc);
+                            if(etc.exists()) {
+                                File nsprops = new File(etc,domain+".props");
+                                if(nsprops.exists()) {
+                                    access = new PropAccess(new String[] {Config.CADI_PROP_FILES+'='+nsprops.getAbsolutePath()});
+                                }
+                            }
+                        }
+                    }
                 }
-                
+
                 if(access==null) {
-                       for(Entry<Object, Object> es : System.getProperties().entrySet()) {
-                               if(Config.CADI_PROP_FILES.equals(es.getKey())) {
-                                       access = new PropAccess();
-                               }
-                       }
+                    for(Entry<Object, Object> es : System.getProperties().entrySet()) {
+                        if(Config.CADI_PROP_FILES.equals(es.getKey())) {
+                            access = new PropAccess();
+                        }
+                    }
                 }
 
-                               // When using Config file, check if Cred Exists, and if not, work with Deployer.
-                               if(access!=null && !"config".equals(args[0]) && access.getProperty(Config.AAF_APPPASS)==null && access.getProperty(Config.CADI_ALIAS)==null) {
-                                       // not enough credentials to use Props.  Use AAFSSO 
-                                       access = null;
-                               }
+                // When using Config file, check if Cred Exists, and if not, work with Deployer.
+                if(access!=null && !"config".equals(args[0]) && access.getProperty(Config.AAF_APPPASS)==null && access.getProperty(Config.CADI_ALIAS)==null) {
+                    // not enough credentials to use Props.  Use AAFSSO
+                    access = null;
+                }
 
                 if(access==null) {
-                       if (args.length>1 && args[0].equals("validate") ) {
-                           int idx = args[1].indexOf('=');
-                           aafsso = null;
-                           access = new PropAccess(
-                                       (idx<0?Config.CADI_PROP_FILES:args[1].substring(0, idx))+
-                                       '='+
-                                       (idx<0?args[1]:args[1].substring(idx+1)));
-                       } else {
-                           aafsso= new AAFSSO(args, new AAFSSO.ProcessArgs() {
-                               @Override
-                               public Properties process(String[] args, Properties props) {
-                                   if (args.length>1) {
-                                       if (!args[0].equals("keypairgen")) {
-                                           props.put(Config.AAF_APPID, args[1]);
-                                       }    
-                                   }
-                                   return props;
-                               }
-                           });
-                           access = aafsso.access();
-                       }
+                    if (args.length>1 && args[0].equals("validate") ) {
+                        int idx = args[1].indexOf('=');
+                        aafsso = null;
+                        access = new PropAccess(
+                                    (idx<0?Config.CADI_PROP_FILES:args[1].substring(0, idx))+
+                                    '='+
+                                    (idx<0?args[1]:args[1].substring(idx+1)));
+                    } else {
+                        aafsso= new AAFSSO(args, new AAFSSO.ProcessArgs() {
+                            @Override
+                            public Properties process(String[] args, Properties props) {
+                                if (args.length>1) {
+                                    if (!args[0].equals("keypairgen")) {
+                                        props.put(Config.AAF_APPID, args[1]);
+                                    }
+                                }
+                                return props;
+                            }
+                        });
+                        access = aafsso.access();
+                    }
                 }
-                    
+
                 if (aafsso!=null && aafsso.loginOnly()) {
                     aafsso.setLogDefault();
                     aafsso.writeFiles();
@@ -219,59 +229,60 @@ public class Agent {
                     env = new RosettaEnv(access.getProperties());
                     Deque<String> cmds = new ArrayDeque<String>();
                     for (String p : args) {
-                       int eq;
+                        int eq;
                         if ("-noexit".equalsIgnoreCase(p)) {
                             doExit = false;
                         } else if ((eq=p.indexOf('=')) < 0) {
                             cmds.add(p);
                         } else {
-                               access.setProperty(p.substring(0,eq), p.substring(eq+1));
+                            access.setProperty(p.substring(0,eq), p.substring(eq+1));
                         }
                     }
-                    
+
                     if (cmds.size()==0) {
                         if (aafsso!=null) {
                             aafsso.setLogDefault();
                         }
                         // NOTE: CHANGE IN CMDS should be reflected in AAFSSO constructor, to get FQI->aaf-id or not
                         System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");
-                        System.out.println("   create     <FQI> [<machine>]");
-                        System.out.println("   read       <FQI> [<machine>]");
-                        System.out.println("   update     <FQI> [<machine>]");
-                        System.out.println("   delete     <FQI> [<machine>]");
-                        System.out.println("   copy       <FQI> <machine> <newmachine>[,<newmachine>]*");
-                        System.out.println("   place      <FQI> [<machine>]");
-                        System.out.println("   showpass   <FQI> [<machine>]");
-                        System.out.println("   check      <FQI> [<machine>]");
-                        System.out.println("   keypairgen <FQI>");
-                        System.out.println("   config     <FQI>");
-                        System.out.println("   validate   <NS>.props>");
+                        System.out.println("   create       <FQI> [<machine>]");
+                        System.out.println("   read         <FQI> [<machine>]");
+                        System.out.println("   update       <FQI> [<machine>]");
+                        System.out.println("   delete       <FQI> [<machine>]");
+                        System.out.println("   copy         <FQI> <machine> <newmachine>[,<newmachine>]*");
+                        System.out.println("   place        <FQI> [<machine>[,<san>]*");
+                        System.out.println("   showpass     <FQI> [<machine>]");
+                        System.out.println("   check        <FQI> [<machine>]");
+                        System.out.println("   keypairgen   <FQI>");
+                        System.out.println("   config       <FQI> [--nopasswd]");
+                        System.out.println("   validate     <NS>.props>");
+                        System.out.println("   connectivity <NS>.props>");
                         System.out.println("   --- Additional Tool Access ---");
                         System.out.println("     ** Type with no params for Tool Help");
                         System.out.println("     ** If using with Agent, preface with \"cadi\"");
                         System.out.println("   cadi <cadi tool params, see -?>");
-                        
+
                         if (doExit) {
                             System.exit(1);
                         }
                     }
-                    
+
                     TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));
-                
+
                     reqDF = env.newDataFactory(CertificateRequest.class);
                     artifactsDF = env.newDataFactory(Artifacts.class);
                     certDF = env.newDataFactory(CertInfo.class);
                     configDF = env.newDataFactory(Configuration.class);
                     permDF = env.newDataFactory(Perms.class);
                     errMsg = new ErrMessage(env);
-        
+
                     placeArtifact = new HashMap<>();
                     placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));
                     placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));
                     placeArtifact.put(FILE, new PlaceArtifactInFiles());
                     placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));
                     placeArtifact.put(SCRIPT, new PlaceArtifactScripts());
-                    
+
                     Trans trans = env.newTrans();
                     String token;
                     if ((token=access.getProperty("oauth_token"))!=null) {
@@ -282,13 +293,13 @@ public class Agent {
                         // show Std out again
                             aafsso.setLogDefault();
                             aafsso.setStdErrDefault();
-                            
+
                             /*urls=*/loadURLs(access);
                             aafsso.writeFiles();
                         }
-    
-                        
-    
+
+
+
                         String cmd = cmds.removeFirst();
                         switch(cmd) {
                             case "place":
@@ -316,7 +327,7 @@ public class Agent {
                                 keypairGen(trans, access, cmds);
                                 break;
                             case "config":
-                               config(trans,access,args,cmds);
+                                config(trans,access,args,cmds);
                                 break;
                             case "validate":
                                 validate(access);
@@ -353,62 +364,62 @@ public class Agent {
     }
 
     public synchronized static Map<String,String> loadURLs(Access access) throws UnknownHostException, CadiException {
-               if(aaf_urls==null) {
-               Map<String,String> rv = new HashMap<>();
-               RegistrationPropHolder rph = new RegistrationPropHolder(access, 0);
-               String dot_le = access.getProperty(Config.AAF_LOCATOR_CONTAINER,null);
-               dot_le=dot_le==null?"":'.'+dot_le;
-               String version = access.getProperty(Config.AAF_API_VERSION,Config.AAF_DEFAULT_API_VERSION);
-               for(String u : new String[] {"locate","aaf","oauth","cm","gui","fs","hello","token","introspect"}) {
-                       String tag;
-                       String append=null;
-                       switch(u) {
-                               case "aaf":   tag = Config.AAF_URL; break;
-                               case "locate":tag = Config.AAF_LOCATE_URL; break;
-                               case "oauth": tag = Config.AAF_URL_OAUTH; break;
-                               case "token": tag = Config.AAF_OAUTH2_TOKEN_URL; append="/token"; break;
-                               case "introspect": tag = Config.AAF_OAUTH2_INTROSPECT_URL; append="/introspect"; break;
-                               case "cm":    tag = Config.AAF_URL_CM; break;
-                               case "gui":   tag = Config.AAF_URL_GUI; break;
-                               case "fs":    tag = Config.AAF_URL_FS; break;
-                               case "hello": tag = Config.AAF_URL_HELLO; break;
-                               default:
-                                       tag = "aaf_url_" + u;
-                       }
-                       String value;
-                       if((value=access.getProperty(tag,null))==null) {
-                               String proto = "fs".equals(u)?"http://":"https://";
-                               String lhost;
-                               if("locate".equals(u)) {
-                                       lhost=rph.default_fqdn;
-                               } else {
-                                       lhost=Config.AAF_LOCATE_URL_TAG;
-                               }
-                               value = rph.replacements(AGENT_LOAD_URLS,
-                                               proto + lhost + "/%CNS.%AAF_NS." + ("aaf".equals(u)?"service":u) + ':' + version, 
-                                               null,dot_le);
-                               if(append!=null) {
-                                       value+=append;
-                               }
-                       } else {
-                               value = rph.replacements(AGENT_LOAD_URLS, value,null,dot_le);
-                       }
-                       rv.put(tag, value);
-               };
-               aaf_urls = rv;
-               }
-           return aaf_urls;
-       }
-
-       public static void fillMissing(PropAccess access, Map<String, String> map) {
-               for(Entry<String, String> es : map.entrySet()) {
-                       if(access.getProperty(es.getKey())==null) {
-                               access.setProperty(es.getKey(),es.getValue());
-                       }
-               }
-       }
-
-       private static synchronized AAFCon<?> aafcon(Access access) throws APIException, CadiException, LocatorException {
+        if(aaf_urls==null) {
+            Map<String,String> rv = new HashMap<>();
+            RegistrationPropHolder rph = new RegistrationPropHolder(access, 0);
+            String dot_le = access.getProperty(Config.AAF_LOCATOR_CONTAINER,null);
+            dot_le=dot_le==null?"":'.'+dot_le;
+            String version = access.getProperty(Config.AAF_API_VERSION,Config.AAF_DEFAULT_API_VERSION);
+            for(String u : new String[] {"locate","aaf","oauth","cm","gui","fs","hello","token","introspect"}) {
+                String tag;
+                String append=null;
+                switch(u) {
+                    case "aaf":   tag = Config.AAF_URL; break;
+                    case "locate":tag = Config.AAF_LOCATE_URL; break;
+                    case "oauth": tag = Config.AAF_URL_OAUTH; break;
+                    case "token": tag = Config.AAF_OAUTH2_TOKEN_URL; append="/token"; break;
+                    case "introspect": tag = Config.AAF_OAUTH2_INTROSPECT_URL; append="/introspect"; break;
+                    case "cm":    tag = Config.AAF_URL_CM; break;
+                    case "gui":   tag = Config.AAF_URL_GUI; break;
+                    case "fs":    tag = Config.AAF_URL_FS; break;
+                    case "hello": tag = Config.AAF_URL_HELLO; break;
+                    default:
+                        tag = "aaf_url_" + u;
+                }
+                String value;
+                if((value=access.getProperty(tag,null))==null) {
+                    String proto = "fs".equals(u)?"http://":"https://";
+                    String lhost;
+                    if("locate".equals(u)) {
+                        lhost=rph.default_fqdn;
+                    } else {
+                        lhost=Config.AAF_LOCATE_URL_TAG;
+                    }
+                    value = rph.replacements(AGENT_LOAD_URLS,
+                            proto + lhost + "/%CNS.%AAF_NS." + ("aaf".equals(u)?"service":u) + ':' + version,
+                            null,dot_le);
+                    if(append!=null) {
+                        value+=append;
+                    }
+                } else {
+                    value = rph.replacements(AGENT_LOAD_URLS, value,null,dot_le);
+                }
+                rv.put(tag, value);
+            };
+            aaf_urls = rv;
+        }
+        return aaf_urls;
+    }
+
+    public static void fillMissing(PropAccess access, Map<String, String> map) {
+        for(Entry<String, String> es : map.entrySet()) {
+            if(access.getProperty(es.getKey())==null) {
+                access.setProperty(es.getKey(),es.getValue());
+            }
+        }
+    }
+
+    private static synchronized AAFCon<?> aafcon(Access access) throws APIException, CadiException, LocatorException {
         if (aafcon==null) {
             aafcon = new AAFConHttp(access,Config.AAF_URL_CM);
         }
@@ -441,11 +452,11 @@ public class Agent {
         if (cmds.size()<1) {
             String alias = env.getProperty(Config.CADI_ALIAS);
             if(alias==null) {
-               alias = env.getProperty(Config.AAF_APPID);
+                alias = env.getProperty(Config.AAF_APPID);
             }
             return alias!=null?alias:AAFSSO.cons.readLine("AppID: ");
         }
-        return cmds.removeFirst();    
+        return cmds.removeFirst();
     }
 
     private static String machine(Deque<String> cmds) throws UnknownHostException {
@@ -477,7 +488,7 @@ public class Agent {
         arti.setMechid(mechID!=null?mechID:AAFSSO.cons.readLine("AppID: "));
         arti.setMachine(machine!=null?machine:AAFSSO.cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));
         arti.setCa(AAFSSO.cons.readLine("CA: (%s): ","aaf"));
-        
+
         String resp = AAFSSO.cons.readLine("Types [file,pkcs12,jks,script] (%s): ", PKCS12);
         for (String s : Split.splitTrim(',', resp)) {
             arti.getType().add(s);
@@ -494,7 +505,7 @@ public class Agent {
         arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", System.getProperty("user.name")));
         arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renewal Days (%s):", "30")));
         arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (mailto owner):", "")));
-        
+
         TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);
         try {
             Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);
@@ -519,7 +530,7 @@ public class Agent {
         }
         return notification;
     }
-    
+
 
     private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
         String mechID = fqi(cmds);
@@ -529,14 +540,14 @@ public class Agent {
         try {
             Future<Artifacts> future = aafcon.client(CM_VER)
                     .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF,"Authorization","Bearer " + trans.getProperty("oauth_token"));
-    
+
             if (future.get(TIMEOUT)) {
                 boolean printed = false;
                 for (Artifact a : future.value.getArtifact()) {
-                    AAFSSO.cons.printf("AppID:          %s\n",a.getMechid()); 
-                    AAFSSO.cons.printf("  Sponsor:       %s\n",a.getSponsor()); 
-                    AAFSSO.cons.printf("Machine:         %s\n",a.getMachine()); 
-                    AAFSSO.cons.printf("CA:              %s\n",a.getCa()); 
+                    AAFSSO.cons.printf("AppID:          %s\n",a.getMechid());
+                    AAFSSO.cons.printf("  Sponsor:       %s\n",a.getSponsor());
+                    AAFSSO.cons.printf("Machine:         %s\n",a.getMachine());
+                    AAFSSO.cons.printf("CA:              %s\n",a.getCa());
                     StringBuilder sb = new StringBuilder();
                     boolean first = true;
                     for (String t : a.getType()) {
@@ -545,7 +556,7 @@ public class Agent {
                         sb.append(t);
                     }
                     AAFSSO.cons.printf("Types:           %s\n",sb);
-                    AAFSSO.cons.printf("Namespace:       %s\n",a.getNs()); 
+                    AAFSSO.cons.printf("Namespace:       %s\n",a.getNs());
                     AAFSSO.cons.printf("Directory:       %s\n",a.getDir());
                     AAFSSO.cons.printf("O/S User:        %s\n",a.getOsUser());
                     AAFSSO.cons.printf("Renew Days:      %d\n",a.getRenewDays());
@@ -562,7 +573,7 @@ public class Agent {
             tt.done();
         }
     }
-    
+
     private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
         String mechID = fqi(cmds);
         String machine = machine(cmds);
@@ -574,7 +585,7 @@ public class Agent {
             try {
                 Future<Artifacts> future = aafcon.client(CM_VER)
                         .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
-            
+
                 if (future.get(TIMEOUT)) {
                     boolean printed = false;
                     for (Artifact a : future.value.getArtifact()) {
@@ -587,7 +598,7 @@ public class Agent {
                                 trans.error().printf("Call to AAF Certman failed, %s",
                                     errMsg.toMsg(fup));
                             }
-    
+
                             printed = true;
                         }
                     }
@@ -611,13 +622,13 @@ public class Agent {
         try {
             Future<Artifacts> fread = aafcon.client(CM_VER)
                     .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
-    
+
             if (fread.get(TIMEOUT)) {
                 Artifacts artifacts = new Artifacts();
                 for (Artifact a : fread.value.getArtifact()) {
                     Artifact arti = new Artifact();
                     artifacts.getArtifact().add(arti);
-                    
+
                     AAFSSO.cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());
                     arti.setMechid(a.getMechid());
                     arti.setMachine(a.getMachine());
@@ -629,7 +640,7 @@ public class Agent {
                         else{sb.append(',');}
                         sb.append(t);
                     }
-    
+
                     String resp = AAFSSO.cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);
                     for (String s : Split.splitTrim(',', resp)) {
                         arti.getType().add(s);
@@ -645,7 +656,7 @@ public class Agent {
                     arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", a.getOsUser()));
                     arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renew Days (%s):", a.getRenewDays())));
                     arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (%s):", a.getNotification())));
-    
+
                 }
                 if (artifacts.getArtifact().size()==0) {
                     AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
@@ -666,16 +677,16 @@ public class Agent {
             tt.done();
         }
     }
-    
+
     private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
         String mechid = fqi(cmds);
         String machine = machine(cmds);
-        
+
         TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);
         try {
             Future<Void> future = aafcon.client(CM_VER)
                     .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );
-    
+
             if (future.get(TIMEOUT)) {
                 trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);
             } else {
@@ -687,7 +698,7 @@ public class Agent {
         }
     }
 
-    
+
 
     private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
         boolean rv = false;
@@ -700,8 +711,9 @@ public class Agent {
             machine = fqdns[1];
         } else {
             key = machine;
+            fqdns = machines(cmds);
         }
-        
+
         TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);
         try {
             Future<Artifacts> acf = aafcon.client(CM_VER)
@@ -716,8 +728,11 @@ public class Agent {
                             CertificateRequest cr = new CertificateRequest();
                             cr.setMechid(a.getMechid());
                             cr.setSponsor(a.getSponsor());
+                            cr.getFqdns().add(machine);
                             for (int i=0;i<fqdns.length;++i) {
-                                cr.getFqdns().add(fqdns[i]);
+                               if(!machine.equals(fqdns[i])) {
+                                       cr.getFqdns().add(fqdns[i]);
+                               }
                             }
                             Future<String> f = aafcon.client(CM_VER)
                                     .updateRespondString("/cert/" + a.getCa()+"?withTrust",reqDF, cr);
@@ -749,7 +764,7 @@ public class Agent {
         }
         return rv;
     }
-    
+
     private static void notifyPlaced(Artifact a, boolean rv) {
     }
 
@@ -771,10 +786,10 @@ public class Agent {
                     boolean allowed;
                     for (Artifact a : acf.value.getArtifact()) {
                         allowed = id!=null && (id.equals(a.getSponsor()) ||
-                                (id.equals(a.getMechid()) 
+                                (id.equals(a.getMechid())
                                         && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));
                         if (!allowed) {
-                            Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" + 
+                            Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" +
                                     a.getNs()+"|certman|"+a.getCa()+"|showpass","*/*");
                             if (pf.get(TIMEOUT)) {
                                 allowed = true;
@@ -791,17 +806,17 @@ public class Agent {
                                 File chalFile = new File(dir,a.getNs()+".chal");
                                 if(chalFile.exists()) {
                                     fis.close();
-                                       fis = new FileInputStream(chalFile);
-                                       props.load(fis);
+                                    fis = new FileInputStream(chalFile);
+                                    props.load(fis);
                                 }
                             } finally {
                                 fis.close();
                             }
-                            
+
                             File f = new File(dir,a.getNs()+".keyfile");
                             if (f.exists()) {
                                 Symm symm = ArtifactDir.getSymm(f);
-                                
+
                                 for (Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {
                                     Entry<Object,Object> en = iter.next();
                                     if (en.getValue().toString().startsWith("enc:")) {
@@ -823,13 +838,13 @@ public class Agent {
         }
 
     }
-    
+
     private static void keypairGen(final Trans trans, final PropAccess access, final Deque<String> cmds) throws IOException {
         final String fqi = fqi(cmds);
         final String ns = FQI.reverseDomain(fqi);
         File dir = new File(access.getProperty(Config.CADI_ETCDIR,".")); // default to current Directory
         File f = new File(dir,ns+".key");
-        
+
         if (f.exists()) {
             String line = AAFSSO.cons.readLine("%s exists. Overwrite? (y/n): ", f.getCanonicalPath());
             if (!"Y".equalsIgnoreCase(line)) {
@@ -837,7 +852,7 @@ public class Agent {
                 return;
             }
         }
-        
+
         KeyPair kp = Factory.generateKeyPair(trans);
         ArtifactDir.write(f, Chmod.to400, Factory.toString(trans, kp.getPrivate()));
         System.out.printf("Wrote %s\n", f.getCanonicalFile());
@@ -846,70 +861,72 @@ public class Agent {
         ArtifactDir.write(f, Chmod.to644, Factory.toString(trans, kp.getPublic()));
         System.out.printf("Wrote %s\n", f.getCanonicalFile());
     }
-    
+
     private static void config(Trans trans, PropAccess propAccess, String[] args, Deque<String> cmds) throws Exception {
         TimeTaken tt = trans.start("Get Configuration", Env.REMOTE);
         try {
-               final String fqi = fqi(cmds);
-               Artifact arti = new Artifact();
-               arti.setDir(propAccess.getProperty(Config.CADI_ETCDIR, System.getProperty("user.dir")));
-               arti.setNs(FQI.reverseDomain(fqi));
+            final String fqi = fqi(cmds);
+            Artifact arti = new Artifact();
+            arti.setDir(propAccess.getProperty(Config.CADI_ETCDIR, System.getProperty("user.dir")));
+            arti.setNs(FQI.reverseDomain(fqi));
             PropHolder loc = PropHolder.get(arti, "location.props");
             PropHolder cred = PropHolder.get(arti,"cred.props");
             PropHolder app= PropHolder.get(arti,"props");
             for(String c : args) {
-               int idx = c.indexOf('=');
-               if(idx>0) {
-                       app.add(c.substring(0,idx), c.substring(idx+1));
-               }
+                int idx = c.indexOf('=');
+                if(idx>0) {
+                    app.add(c.substring(0,idx), c.substring(idx+1));
+                }
             }
             app.add(Config.CADI_PROP_FILES, loc.getPath()+':'+cred.getPath());
 
             for (String tag : LOC_TAGS) {
-               loc.add(tag, getProperty(propAccess, trans, false, tag, "%s: ",tag));
+                loc.add(tag, getProperty(propAccess, trans, false, tag, "%s: ",tag));
             }
-            
+
             String keyfile = cred.getKeyPath();
             if(keyfile!=null) {
-               File fkeyfile = new File(keyfile);
-               if(!fkeyfile.exists()) {
-                       ArtifactDir.write(fkeyfile,Chmod.to400,Symm.keygen());
-               }
+                File fkeyfile = new File(keyfile);
+                if(!fkeyfile.exists()) {
+                    ArtifactDir.write(fkeyfile,Chmod.to400,Symm.keygen());
+                }
             }
             cred.add(Config.CADI_KEYFILE, cred.getKeyPath());
             final String ssoAppID = propAccess.getProperty(Config.AAF_APPID);
             if(fqi!=null && fqi.equals(ssoAppID)) {
-               cred.addEnc(Config.AAF_APPPASS, propAccess, null);
+                cred.addEnc(Config.AAF_APPPASS, propAccess, null);
             // only Ask for Password when starting scratch
             } else if(propAccess.getProperty(Config.CADI_PROP_FILES)==null) {
-               char[] pwd = AAFSSO.cons.readPassword("Password for %s (leave blank for NO password): ", fqi);
-               if(pwd.length>0) {
-                       cred.addEnc(Config.AAF_APPPASS, new String(pwd));
-               }
+                if(!configNoPasswd) {
+                    char[] pwd = AAFSSO.cons.readPassword("Password for %s (leave blank for NO password): ", fqi);
+                    if(pwd.length>0) {
+                        cred.addEnc(Config.AAF_APPPASS, new String(pwd));
+                    }
+                }
             }
-            
+
             // load all properties that are already setup.
             Map<String, String> aaf_urls = loadURLs(propAccess);
             for(Entry<String, String> es : aaf_urls.entrySet()) {
-               app.add(es.getKey(), es.getValue());
+                app.add(es.getKey(), es.getValue());
             }
-            
+
             app.add(Config.AAF_LOCATE_URL, Config.getAAFLocateUrl(propAccess));
             app.add(Config.AAF_ENV,propAccess, "DEV");
             String release = propAccess.getProperty(Config.AAF_DEPLOYED_VERSION);
             if(release==null) {
-               release = System.getProperty(Config.AAF_DEPLOYED_VERSION,null);
+                release = System.getProperty(Config.AAF_DEPLOYED_VERSION,null);
             }
             if(release!=null) {
-               app.add(Config.AAF_DEPLOYED_VERSION, release);
+                app.add(Config.AAF_DEPLOYED_VERSION, release);
             }
             for(Entry<Object, Object> aaf_loc_prop : propAccess.getProperties().entrySet()) {
-               String key = aaf_loc_prop.getKey().toString();
-               if(key.startsWith("aaf_locator")) {
-                       app.add(key, aaf_loc_prop.getValue().toString());
-               }
+                String key = aaf_loc_prop.getKey().toString();
+                if(key.startsWith("aaf_locator")) {
+                    app.add(key, aaf_loc_prop.getValue().toString());
+                }
             }
-            
+
             app.add(Config.AAF_APPID, fqi);
 
             String cts = propAccess.getProperty(Config.CADI_TRUSTSTORE);
@@ -918,64 +935,64 @@ public class Agent {
                 File origTruststore = new File(cts);
                 File newTruststore = new File(app.getDir(),origTruststore.getName());
                 if(!newTruststore.exists()) {
-                       if (!origTruststore.exists()) {
-                           // Try same directory as cadi_prop_files
-                           String cpf = propAccess.getProperty(Config.CADI_PROP_FILES);
-                           if (cpf!=null) {
-                               for (String f : Split.split(File.pathSeparatorChar, cpf)) {
-                                   File fcpf = new File(f);
-                                   if (fcpf.exists()) {
-                                       int lastSep = cts.lastIndexOf(File.pathSeparator);
-                                       origTruststore = new File(fcpf.getParentFile(),lastSep>=0?cts.substring(lastSep):cts);
-                                       if (origTruststore.exists()) { 
-                                           break;
-                                       }
-                                   }
-                               }
-                               if (!origTruststore.exists()) {
-                                   throw new CadiException(cts + " does not exist");
-                               }
-                           }
-                           
-                       }
-                       if (!newTruststore.exists() && origTruststore.exists()) {
-                           Files.copy(origTruststore.toPath(), newTruststore.toPath());
-                       }
+                    if (!origTruststore.exists()) {
+                        // Try same directory as cadi_prop_files
+                        String cpf = propAccess.getProperty(Config.CADI_PROP_FILES);
+                        if (cpf!=null) {
+                            for (String f : Split.split(File.pathSeparatorChar, cpf)) {
+                                File fcpf = new File(f);
+                                if (fcpf.exists()) {
+                                    int lastSep = cts.lastIndexOf(File.pathSeparator);
+                                    origTruststore = new File(fcpf.getParentFile(),lastSep>=0?cts.substring(lastSep):cts);
+                                    if (origTruststore.exists()) {
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!origTruststore.exists()) {
+                                throw new CadiException(cts + " does not exist");
+                            }
+                        }
+
+                    }
+                    if (!newTruststore.exists() && origTruststore.exists()) {
+                        Files.copy(origTruststore.toPath(), newTruststore.toPath());
+                    }
                 }
 
-               System.out.println("New Truststore is " + newTruststore);
+                System.out.println("New Truststore is " + newTruststore);
                 cred.add(Config.CADI_TRUSTSTORE, newTruststore.getCanonicalPath());
                 cred.add(Config.CADI_TRUSTSTORE_PASSWORD, "changeit" /* Java default */);
-                    
+
                 String cpf = propAccess.getProperty(Config.CADI_PROP_FILES);
                 if (cpf!=null){
-                       String[] propFiles = Split.splitTrim(File.pathSeparatorChar, cpf); 
+                    String[] propFiles = Split.splitTrim(File.pathSeparatorChar, cpf);
                     for (int pfi = propFiles.length-1;pfi>=0;--pfi) {
-                       String f = propFiles[pfi];
+                        String f = propFiles[pfi];
                         System.out.format("Reading %s\n",f);
-                        FileInputStream fis = new FileInputStream(f); 
+                        FileInputStream fis = new FileInputStream(f);
                         try {
                             Properties props = new Properties();
                             props.load(fis);
                             for (Entry<Object, Object> prop : props.entrySet()) {
-                               boolean lower = true;
-                               String key = prop.getKey().toString();
-                               if(LOC_TAGS.contains(key)) {
-                                       break;
-                               }
-                               for(int i=0;lower && i<key.length();++i) {
-                                       if(Character.isUpperCase(key.charAt(i))) {
-                                               lower = false;
-                                       }
-                               }
-                               if(lower) {
-                                       PropHolder ph = CRED_TAGS.contains(key)?cred:app;
-                                       if(key.endsWith("_password")) {
-                                               ph.addEnc(key, prop.getValue().toString());
-                                       } else {
-                                               ph.add(key, prop.getValue().toString());
-                                       }
-                               }
+                                boolean lower = true;
+                                String key = prop.getKey().toString();
+                                if(LOC_TAGS.contains(key)) {
+                                    break;
+                                }
+                                for(int i=0;lower && i<key.length();++i) {
+                                    if(Character.isUpperCase(key.charAt(i))) {
+                                        lower = false;
+                                    }
+                                }
+                                if(lower) {
+                                    PropHolder ph = CRED_TAGS.contains(key)?cred:app;
+                                    if(key.endsWith("_password")) {
+                                        ph.addEnc(key, prop.getValue().toString());
+                                    } else {
+                                        ph.add(key, prop.getValue().toString());
+                                    }
+                                }
                             }
                         } finally {
                             fis.close();
@@ -985,29 +1002,29 @@ public class Agent {
                     aafcon = aafcon(propAccess);
                     if (aafcon!=null) { // get Properties from Remote AAF
                         for (Props props : aafProps(trans,aafcon,getProperty(propAccess,aafcon.env,false,Config.AAF_LOCATE_URL,"AAF Locator URL: "),fqi)) {
-                               PropHolder ph = CRED_TAGS.contains(props.getTag())?cred:app;
-                               if(props.getTag().endsWith("_password")) {
-                                       ph.addEnc(props.getTag(), props.getValue());
-                               } else {
-                                       ph.add(props.getTag(), props.getValue());
-                               }
+                            PropHolder ph = CRED_TAGS.contains(props.getTag())?cred:app;
+                            if(props.getTag().endsWith("_password")) {
+                                ph.addEnc(props.getTag(), props.getValue());
+                            } else {
+                                ph.add(props.getTag(), props.getValue());
+                            }
                         }
 
                     }
                 }
             }
-            
+
             PropHolder.writeAll();
         } finally {
             tt.done();
         }
     }
 
-    public static List<Props> aafProps(Trans trans, AAFCon<?> aafcon, String locator, String fqi) throws CadiException, APIException, URISyntaxException {
-       Future<Configuration> acf = aafcon.client(new SingleEndpointLocator(locator))
+    public static List<Props> aafProps(Trans trans, AAFCon<?> aafcon, String locator, String fqi) throws CadiException, APIException, LocatorException {
+        Future<Configuration> acf = aafcon.client(new SingleEndpointLocator(locator))
                 .read("/configure/"+fqi+"/aaf", configDF);
         if (acf.get(TIMEOUT)) {
-               return acf.value.getProps();
+            return acf.value.getProps();
         } else if (acf.code()==401){
             trans.error().log("Bad Password sent to AAF");
         } else if (acf.code()==404){
@@ -1048,12 +1065,12 @@ public class Agent {
 
     /**
      * Check returns Error Codes, so that Scripts can know what to do
-     * 
+     *
      *   0 - Check Complete, nothing to do
      *   1 - General Error
      *   2 - Error for specific Artifact - read check.msg
      *   10 - Certificate Updated - check.msg is email content
-     *   
+     *
      * @param trans
      * @param aafcon
      * @param cmds
@@ -1064,10 +1081,10 @@ public class Agent {
         int exitCode=1;
         String mechID = fqi(cmds);
         String machine = machine(cmds);
-        
+
         TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);
         try {
-        
+
             Future<Artifacts> acf = aafcon.client(CM_VER)
                     .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
             if (acf.get(TIMEOUT)) {
@@ -1088,10 +1105,10 @@ public class Agent {
                             } finally {
                                 fis.close();
                             }
-                            
-                            String prop;                        
+
+                            String prop;
                             File f;
-    
+
                             if ((prop=trans.getProperty(Config.CADI_KEYFILE))==null ||
                                 !(f=new File(prop)).exists()) {
                                     trans.error().printf("Keyfile must exist to check Certificates for %s on %s",
@@ -1106,7 +1123,7 @@ public class Agent {
                                     Symm symm = ArtifactDir.getSymm(f);
 
                                     KeyStore ks = KeyStore.getInstance("JKS");
-                                    
+
                                     fis = new FileInputStream(ksf);
                                     try {
                                         ks.load(fis,symm.depass(ksps).toCharArray());
@@ -1126,21 +1143,21 @@ public class Agent {
                                         renew.setTime(cert.getNotAfter());
                                         renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());
                                         if (renew.after(now)) {
-                                            msg = String.format("X509Certificate for %s on %s has been checked on %s. It expires on %s; it will not be renewed until %s.\n", 
+                                            msg = String.format("X509Certificate for %s on %s has been checked on %s. It expires on %s; it will not be renewed until %s.\n",
                                                     a.getMechid(), a.getMachine(),Chrono.dateOnlyStamp(now),cert.getNotAfter(),Chrono.dateOnlyStamp(renew));
                                             trans.info().log(msg);
                                             exitCode = 0; // OK
                                         } else {
-                                            trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n", 
+                                            trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n",
                                                     a.getMechid(), a.getMachine(),cert.getNotAfter());
                                             cmds.offerLast(mechID);
                                             cmds.offerLast(machine);
                                             if (placeCerts(trans,aafcon,cmds)) {
-                                                msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n", 
+                                                msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n",
                                                         a.getMechid(), a.getMachine());
                                                 exitCode = 10; // Refreshed
                                             } else {
-                                                msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n", 
+                                                msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n",
                                                         a.getMechid(), a.getMachine());
                                                 exitCode = 1; // Error Renewing
                                             }
@@ -1155,7 +1172,7 @@ public class Agent {
                                         }
                                     }
                                 }
-                                
+
                             }
                         }
                     }
@@ -1171,7 +1188,7 @@ public class Agent {
     }
 
 }
-            
-        
+
+