Configuration Agent and MS for AAF
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / configure / Agent.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.cadi.configure;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.PrintStream;
29 import java.net.ConnectException;
30 import java.net.HttpURLConnection;
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.nio.file.Files;
34 import java.security.KeyPair;
35 import java.security.KeyStore;
36 import java.security.cert.X509Certificate;
37 import java.util.ArrayDeque;
38 import java.util.Date;
39 import java.util.Deque;
40 import java.util.GregorianCalendar;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.Map;
44 import java.util.Map.Entry;
45 import java.util.Properties;
46
47 import org.onap.aaf.cadi.CadiException;
48 import org.onap.aaf.cadi.CmdLine;
49 import org.onap.aaf.cadi.LocatorException;
50 import org.onap.aaf.cadi.PropAccess;
51 import org.onap.aaf.cadi.Symm;
52 import org.onap.aaf.cadi.aaf.client.ErrMessage;
53 import org.onap.aaf.cadi.aaf.v2_0.AAFCon;
54 import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
55 import org.onap.aaf.cadi.client.Future;
56 import org.onap.aaf.cadi.client.Rcli;
57 import org.onap.aaf.cadi.client.Retryable;
58 import org.onap.aaf.cadi.config.Config;
59 import org.onap.aaf.cadi.config.SecurityInfoC;
60 import org.onap.aaf.cadi.http.HBasicAuthSS;
61 import org.onap.aaf.cadi.locator.SingleEndpointLocator;
62 import org.onap.aaf.cadi.sso.AAFSSO;
63 import org.onap.aaf.cadi.util.Chmod;
64 import org.onap.aaf.cadi.util.FQI;
65 import org.onap.aaf.misc.env.APIException;
66 import org.onap.aaf.misc.env.Data.TYPE;
67 import org.onap.aaf.misc.env.Env;
68 import org.onap.aaf.misc.env.TimeTaken;
69 import org.onap.aaf.misc.env.Trans;
70 import org.onap.aaf.misc.env.util.Chrono;
71 import org.onap.aaf.misc.env.util.Split;
72 import org.onap.aaf.misc.rosetta.env.RosettaDF;
73 import org.onap.aaf.misc.rosetta.env.RosettaEnv;
74
75 import aaf.v2_0.Perm;
76 import aaf.v2_0.Perms;
77 import certman.v1_0.Artifacts;
78 import certman.v1_0.Artifacts.Artifact;
79 import certman.v1_0.CertInfo;
80 import certman.v1_0.CertificateRequest;
81 import locate.v1_1.Configuration;
82 import locate.v1_1.Configuration.Props;
83
84 public class Agent {
85         private static final String HASHES = "################################################################";
86         private static final String PRINT = "print";
87         private static final String FILE = "file";
88         private static final String PKCS12 = "pkcs12";
89         private static final String JKS = "jks";
90         private static final String SCRIPT="script";
91         
92         private static final String CM_VER = "1.0";
93         public static final int PASS_SIZE = 24;
94         private static int TIMEOUT;
95         
96         private static RosettaDF<CertificateRequest> reqDF;
97         private static RosettaDF<CertInfo> certDF;
98         private static RosettaDF<Artifacts> artifactsDF;
99         private static RosettaDF<Configuration> configDF;
100         private static RosettaDF<Perms> permDF;
101         private static ErrMessage errMsg;
102         private static Map<String,PlaceArtifact> placeArtifact;
103         private static RosettaEnv env;
104         
105         private static boolean doExit;
106         private static AAFCon<?> aafcon;
107
108         public static void main(String[] args) {
109                 int exitCode = 0;
110                 doExit = true;
111                 if(args.length>0 && "cadi".equals(args[0])) {
112                         String[] newArgs = new String[args.length-1];
113                         System.arraycopy(args, 1, newArgs, 0, newArgs.length);
114                         if(newArgs.length==0) {
115                                 System.out.println(HASHES);
116                                 System.out.println("Note: Cadi CmdLine is a separate component.  When running with\n\t"
117                                                 + "Agent, always preface with \"cadi\",\n\tex: cadi keygen [<keyfile>]");
118                                 System.out.println(HASHES);
119                         }
120                         CmdLine.main(newArgs);
121                 } else {
122                         try {
123                                 AAFSSO aafsso=null;
124                                 PropAccess access;
125                                 
126                                 if(args.length>0 && args[0].equals("validate")) {
127                                         int idx = args[1].indexOf('=');
128                                         aafsso = null;
129                                         access = new PropAccess(
130                                                                 (idx<0?Config.CADI_PROP_FILES:args[1].substring(0, idx))+
131                                                                 '='+
132                                                             (idx<0?args[1]:args[1].substring(idx+1)));
133                                 } else {
134                                         aafsso= new AAFSSO(args, new AAFSSO.ProcessArgs() {
135                                                 @Override
136                                                 public Properties process(String[] args, Properties props) {
137                                                         if(args.length>1) {
138                                                                 if (!args[0].equals("keypairgen")) {
139                                                                         props.put("aaf_id", args[1]);
140                                                                 }       
141                                                         }
142                                                         return props;
143                                                 }
144                                         });
145                                         access = aafsso.access();
146                                 }
147                                         
148                                 if(aafsso!=null && aafsso.loginOnly()) {
149                                         aafsso.setLogDefault();
150                                         aafsso.writeFiles();
151                                         System.out.println("AAF SSO information created in ~/.aaf");
152                                 } else {
153                                         env = new RosettaEnv(access.getProperties());
154                                         Deque<String> cmds = new ArrayDeque<String>();
155                                         for(String p : args) {
156                                                 if("-noexit".equalsIgnoreCase(p)) {
157                                                         doExit = false;
158                                                 } else if(p.indexOf('=') < 0) {
159                                                         cmds.add(p);
160                                                 }
161                                         }
162                                         
163                                         if(cmds.size()==0) {
164                                                 if(aafsso!=null) {
165                                                         aafsso.setLogDefault();
166                                                 }
167                                                 // NOTE: CHANGE IN CMDS should be reflected in AAFSSO constructor, to get FQI->aaf-id or not
168                                                 System.out.println("Usage: java -jar <cadi-aaf-*-full.jar> cmd [<tag=value>]*");
169                                                 System.out.println("   create     <FQI> [<machine>]");
170                                                 System.out.println("   read       <FQI> [<machine>]");
171                                                 System.out.println("   update     <FQI> [<machine>]");
172                                                 System.out.println("   delete     <FQI> [<machine>]");
173                                                 System.out.println("   copy       <FQI> <machine> <newmachine>[,<newmachine>]*");
174                                                 System.out.println("   place      <FQI> [<machine>]");
175                                                 System.out.println("   showpass   <FQI> [<machine>]");
176                                                 System.out.println("   check      <FQI> [<machine>]");
177                                                 System.out.println("   keypairgen <FQI>");
178                                                 System.out.println("   config     <FQI>");
179                                                 System.out.println("   validate   <NS>.props>");
180                                                 System.out.println("   --- Additional Tool Access ---");
181                                                 System.out.println("     ** Type with no params for Tool Help");
182                                                 System.out.println("     ** If using with Agent, preface with \"cadi\"");
183                                                 System.out.println("   cadi <cadi tool params, see -?>");
184                                                 
185                                                 if (doExit) {
186                                                         System.exit(1);
187                                                 }
188                                         }
189                                         
190                                         TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, "5000"));
191                                 
192                                         reqDF = env.newDataFactory(CertificateRequest.class);
193                                         artifactsDF = env.newDataFactory(Artifacts.class);
194                                         certDF = env.newDataFactory(CertInfo.class);
195                                         configDF = env.newDataFactory(Configuration.class);
196                                         permDF = env.newDataFactory(Perms.class);
197                                         errMsg = new ErrMessage(env);
198                 
199                                         placeArtifact = new HashMap<>();
200                                         placeArtifact.put(JKS, new PlaceArtifactInKeystore(JKS));
201                                         placeArtifact.put(PKCS12, new PlaceArtifactInKeystore(PKCS12));
202                                         placeArtifact.put(FILE, new PlaceArtifactInFiles());
203                                         placeArtifact.put(PRINT, new PlaceArtifactOnStream(System.out));
204                                         placeArtifact.put(SCRIPT, new PlaceArtifactScripts());
205                                         
206                                         Trans trans = env.newTrans();
207                                         String token;
208                                         if((token=access.getProperty("oauth_token"))!=null) {
209                                                 trans.setProperty("oauth_token", token);
210                                         }
211                                         try {
212                                                 if(aafsso!=null) {
213                                                 // show Std out again
214                                                         aafsso.setLogDefault();
215                                                         aafsso.setStdErrDefault();
216                                                         
217                                                         // if CM_URL can be obtained, add to sso.props, if written
218                                                         String cm_url = getProperty(access,env,false, Config.CM_URL,Config.CM_URL+": ");
219                                                         if(cm_url!=null) {
220                                                                 aafsso.addProp(Config.CM_URL, cm_url);
221                                                         }
222                                                         aafsso.writeFiles();
223                                                 }
224         
225                                                 
226         
227                                                 String cmd = cmds.removeFirst();
228                                                 switch(cmd) {
229                                                         case "place":
230                                                                 placeCerts(trans,aafcon(access),cmds);
231                                                                 break;
232                                                         case "create":
233                                                                 createArtifact(trans, aafcon(access),cmds);
234                                                                 break;
235                                                         case "read":
236                                                                 readArtifact(trans, aafcon(access), cmds);
237                                                                 break;
238                                                         case "copy":
239                                                                 copyArtifact(trans, aafcon(access), cmds);
240                                                                 break;
241                                                         case "update":
242                                                                 updateArtifact(trans, aafcon(access), cmds);
243                                                                 break;
244                                                         case "delete":
245                                                                 deleteArtifact(trans, aafcon(access), cmds);
246                                                                 break;
247                                                         case "showpass":
248                                                                 showPass(trans, aafcon(access), cmds);
249                                                                 break;
250                                                         case "keypairgen":
251                                                                 keypairGen(trans, access, cmds);
252                                                                 break;
253                                                         case "config":
254                                                                 if(access.getProperty(Config.CADI_PROP_FILES)!=null) {
255                                                                         // Get Properties from initialization Prop Files
256                                                                         config(trans,access,null,cmds);
257                                                                 } else {
258                                                                         // Get Properties from existing AAF Instance
259                                                                         config(trans,access,aafcon(access),cmds);
260                                                                 }
261                                                                 break;
262                                                         case "validate":
263                                                                 validate(access);
264                                                                 break;
265                                                         case "check":
266                                                                 try {
267                                                                         exitCode = check(trans,aafcon(access),cmds);
268                                                                 } catch (Exception e) {
269                                                                         exitCode = 1;
270                                                                         throw e;
271                                                                 }
272                                                                 break;
273                                                         default:
274                                                                 AAFSSO.cons.printf("Unknown command \"%s\"\n", cmd);
275                                                 }
276                                         } finally {
277                                                 StringBuilder sb = new StringBuilder();
278                                 trans.auditTrail(4, sb, Trans.REMOTE);
279                                 if(sb.length()>0) {
280                                         trans.info().log("Trans Info\n",sb);
281                                 }
282                                         }
283                                         if(aafsso!=null) {
284                                                 aafsso.close();
285                                         }
286                                 }
287                         } catch (Exception e) {
288                                 e.printStackTrace();
289                         }
290                 }
291                 if(exitCode != 0 && doExit) {
292                         System.exit(exitCode);
293                 }
294         }
295
296         private static synchronized AAFCon<?> aafcon(PropAccess access) throws APIException, CadiException, LocatorException {
297                 if(aafcon==null) {
298                         aafcon = new AAFConHttp(access,Config.CM_URL);
299                 }
300                 return aafcon;
301         }
302
303         private static String getProperty(PropAccess pa, Env env, boolean secure, String tag, String prompt, Object ... def) {
304                 String value;
305                 if((value=pa.getProperty(tag))==null) {
306                         if(secure) {
307                                 value = new String(AAFSSO.cons.readPassword(prompt, def));
308                         } else {
309                                 value = AAFSSO.cons.readLine(prompt,def).trim();
310                         }
311                         if(value!=null) {
312                                 if(value.length()>0) {
313                                         pa.setProperty(tag,value);
314                                         env.setProperty(tag,value);
315                                 } else if(def.length==1) {
316                                         value=def[0].toString();
317                                         pa.setProperty(tag,value);
318                                         env.setProperty(tag,value);
319                                 }
320                         }
321                 }
322                 return value;
323         }
324
325         private static String fqi(Deque<String> cmds) {
326                 if(cmds.size()<1) {
327                         String alias = env.getProperty(Config.CADI_ALIAS);
328                         return alias!=null?alias:AAFSSO.cons.readLine("MechID: ");
329                 }
330                 return cmds.removeFirst();      
331         }
332
333         private static String machine(Deque<String> cmds) throws UnknownHostException {
334                 if(cmds.size()>0) {
335                         return cmds.removeFirst();
336                 } else {
337                         String mach = env.getProperty(Config.HOSTNAME);
338                         return mach!=null?mach:InetAddress.getLocalHost().getHostName();
339                 }
340         }
341
342         private static String[] machines(Deque<String> cmds)  {
343                 String machines;
344                 if(cmds.size()>0) {
345                         machines = cmds.removeFirst();
346                 } else {
347                         machines = AAFSSO.cons.readLine("Machines (sep by ','): ");
348                 }
349                 return Split.split(',', machines);
350         }
351
352         private static void createArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
353                 String mechID = fqi(cmds);
354                 String machine = machine(cmds);
355
356                 Artifacts artifacts = new Artifacts();
357                 Artifact arti = new Artifact();
358                 artifacts.getArtifact().add(arti);
359                 arti.setMechid(mechID!=null?mechID:AAFSSO.cons.readLine("MechID: "));
360                 arti.setMachine(machine!=null?machine:AAFSSO.cons.readLine("Machine (%s): ",InetAddress.getLocalHost().getHostName()));
361                 arti.setCa(AAFSSO.cons.readLine("CA: (%s): ","aaf"));
362                 
363                 String resp = AAFSSO.cons.readLine("Types [file,jks,script] (%s): ", "jks");
364                 for(String s : Split.splitTrim(',', resp)) {
365                         arti.getType().add(s);
366                 }
367                 // Always do Script
368                 if(!resp.contains(SCRIPT)) {
369                         arti.getType().add(SCRIPT);
370                 }
371
372                 // Note: Sponsor is set on Creation by CM
373                 String configRootName = FQI.reverseDomain(arti.getMechid());
374                 arti.setNs(AAFSSO.cons.readLine("Namespace (%s): ",configRootName));
375                 arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", System.getProperty("user.dir")));
376                 arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", System.getProperty("user.name")));
377                 arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renewal Days (%s):", "30")));
378                 arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (mailto owner):", "")));
379                 
380                 TimeTaken tt = trans.start("Create Artifact", Env.REMOTE);
381                 try {
382                         Future<Artifacts> future = aafcon.client(CM_VER).create("/cert/artifacts", artifactsDF, artifacts);
383                         if(future.get(TIMEOUT)) {
384                                 trans.info().printf("Call to AAF Certman successful %s, %s",arti.getMechid(), arti.getMachine());
385                         } else {
386                                 trans.error().printf("Call to AAF Certman failed, %s",
387                                         errMsg.toMsg(future));
388                         }
389                 } finally {
390                         tt.done();
391                 }
392         }
393
394         private static String toNotification(String notification) {
395                 if(notification==null) {
396                         notification="";
397                 } else if(notification.length()>0) {
398                         if(notification.indexOf(':')<0) {
399                                 notification = "mailto:" + notification;
400                         }
401                 }
402                 return notification;
403         }
404         
405
406         private static void readArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
407                 String mechID = fqi(cmds);
408                 String machine = machine(cmds);
409
410                 TimeTaken tt = trans.start("Read Artifact", Env.SUB);
411                 try {
412                         Future<Artifacts> future = aafcon.client(CM_VER)
413                                         .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF,"Authorization","Bearer " + trans.getProperty("oauth_token"));
414         
415                         if(future.get(TIMEOUT)) {
416                                 boolean printed = false;
417                                 for(Artifact a : future.value.getArtifact()) {
418                                         AAFSSO.cons.printf("MechID:          %s\n",a.getMechid()); 
419                                         AAFSSO.cons.printf("  Sponsor:       %s\n",a.getSponsor()); 
420                                         AAFSSO.cons.printf("Machine:         %s\n",a.getMachine()); 
421                                         AAFSSO.cons.printf("CA:              %s\n",a.getCa()); 
422                                         StringBuilder sb = new StringBuilder();
423                                         boolean first = true;
424                                         for(String t : a.getType()) {
425                                                 if(first) {first=false;}
426                                                 else{sb.append(',');}
427                                                 sb.append(t);
428                                         }
429                                         AAFSSO.cons.printf("Types:           %s\n",sb);
430                                         AAFSSO.cons.printf("Namespace:       %s\n",a.getNs()); 
431                                         AAFSSO.cons.printf("Directory:       %s\n",a.getDir());
432                                         AAFSSO.cons.printf("O/S User:        %s\n",a.getOsUser());
433                                         AAFSSO.cons.printf("Renew Days:      %d\n",a.getRenewDays());
434                                         AAFSSO.cons.printf("Notification     %s\n",a.getNotification());
435                                         printed = true;
436                                 }
437                                 if(!printed) {
438                                         AAFSSO.cons.printf("Artifact for %s %s does not exist\n", mechID, machine);
439                                 }
440                         } else {
441                                 trans.error().log(errMsg.toMsg(future));
442                         }
443                 } finally {
444                         tt.done();
445                 }
446         }
447         
448         private static void copyArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
449                 String mechID = fqi(cmds);
450                 String machine = machine(cmds);
451                 String[] newmachs = machines(cmds);
452                 if(machine==null || newmachs == null) {
453                         trans.error().log("No machines listed to copy to");
454                 } else {
455                         TimeTaken tt = trans.start("Copy Artifact", Env.REMOTE);
456                         try {
457                                 Future<Artifacts> future = aafcon.client(CM_VER)
458                                                 .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
459                         
460                                 if(future.get(TIMEOUT)) {
461                                         boolean printed = false;
462                                         for(Artifact a : future.value.getArtifact()) {
463                                                 for(String m : newmachs) {
464                                                         a.setMachine(m);
465                                                         Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, future.value);
466                                                         if(fup.get(TIMEOUT)) {
467                                                                 trans.info().printf("Copy of %s %s successful to %s",mechID,machine,m);
468                                                         } else {
469                                                                 trans.error().printf("Call to AAF Certman failed, %s",
470                                                                         errMsg.toMsg(fup));
471                                                         }
472         
473                                                         printed = true;
474                                                 }
475                                         }
476                                         if(!printed) {
477                                                 AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
478                                         }
479                                 } else {
480                                         trans.error().log(errMsg.toMsg(future));
481                                 }
482                         } finally {
483                                 tt.done();
484                         }
485                 }
486         }
487
488         private static void updateArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
489                 String mechID = fqi(cmds);
490                 String machine = machine(cmds);
491
492                 TimeTaken tt = trans.start("Update Artifact", Env.REMOTE);
493                 try {
494                         Future<Artifacts> fread = aafcon.client(CM_VER)
495                                         .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
496         
497                         if(fread.get(TIMEOUT)) {
498                                 Artifacts artifacts = new Artifacts();
499                                 for(Artifact a : fread.value.getArtifact()) {
500                                         Artifact arti = new Artifact();
501                                         artifacts.getArtifact().add(arti);
502                                         
503                                         AAFSSO.cons.printf("For %s on %s\n", a.getMechid(),a.getMachine());
504                                         arti.setMechid(a.getMechid());
505                                         arti.setMachine(a.getMachine());
506                                         arti.setCa(AAFSSO.cons.readLine("CA: (%s): ",a.getCa()));
507                                         StringBuilder sb = new StringBuilder();
508                                         boolean first = true;
509                                         for(String t : a.getType()) {
510                                                 if(first) {first=false;}
511                                                 else{sb.append(',');}
512                                                 sb.append(t);
513                                         }
514         
515                                         String resp = AAFSSO.cons.readLine("Types [file,jks,pkcs12] (%s): ", sb);
516                                         for(String s : Split.splitTrim(',', resp)) {
517                                                 arti.getType().add(s);
518                                         }
519                                         // Always do Script
520                                         if(!resp.contains(SCRIPT)) {
521                                                 arti.getType().add(SCRIPT);
522                                         }
523
524                                         // Note: Sponsor is set on Creation by CM
525                                         arti.setNs(AAFSSO.cons.readLine("Namespace (%s): ",a.getNs()));
526                                         arti.setDir(AAFSSO.cons.readLine("Directory (%s): ", a.getDir()));
527                                         arti.setOsUser(AAFSSO.cons.readLine("OS User (%s): ", a.getOsUser()));
528                                         arti.setRenewDays(Integer.parseInt(AAFSSO.cons.readLine("Renew Days (%s):", a.getRenewDays())));
529                                         arti.setNotification(toNotification(AAFSSO.cons.readLine("Notification (%s):", a.getNotification())));
530         
531                                 }
532                                 if(artifacts.getArtifact().size()==0) {
533                                         AAFSSO.cons.printf("Artifact for %s %s does not exist", mechID, machine);
534                                 } else {
535                                         Future<Artifacts> fup = aafcon.client(CM_VER).update("/cert/artifacts", artifactsDF, artifacts);
536                                         if(fup.get(TIMEOUT)) {
537                                                 trans.info().printf("Call to AAF Certman successful %s, %s",mechID,machine);
538                                         } else {
539                                                 trans.error().printf("Call to AAF Certman failed, %s",
540                                                         errMsg.toMsg(fup));
541                                         }
542                                 }
543                         } else {
544                                 trans.error().printf("Call to AAF Certman failed, %s %s, %s",
545                                                 errMsg.toMsg(fread),mechID,machine);
546                         }
547                 } finally {
548                         tt.done();
549                 }
550         }
551         
552         private static void deleteArtifact(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
553                 String mechid = fqi(cmds);
554                 String machine = machine(cmds);
555                 
556                 TimeTaken tt = trans.start("Delete Artifact", Env.REMOTE);
557                 try {
558                         Future<Void> future = aafcon.client(CM_VER)
559                                         .delete("/cert/artifacts/"+mechid+"/"+machine,"application/json" );
560         
561                         if(future.get(TIMEOUT)) {
562                                 trans.info().printf("Call to AAF Certman successful %s, %s",mechid,machine);
563                         } else {
564                                 trans.error().printf("Call to AAF Certman failed, %s %s, %s",
565                                         errMsg.toMsg(future),mechid,machine);
566                         }
567                 } finally {
568                         tt.done();
569                 }
570         }
571
572         
573
574         private static boolean placeCerts(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
575                 boolean rv = false;
576                 String mechID = fqi(cmds);
577                 String machine = machine(cmds);
578                 String[] fqdns = Split.split(':', machine);
579                 String key;
580                 if(fqdns.length>1) {
581                         key = fqdns[0];
582                         machine = fqdns[1];
583                 } else {
584                         key = machine;
585                 }
586                 
587                 TimeTaken tt = trans.start("Place Artifact", Env.REMOTE);
588                 try {
589                         Future<Artifacts> acf = aafcon.client(CM_VER)
590                                         .read("/cert/artifacts/"+mechID+'/'+key, artifactsDF);
591                         if(acf.get(TIMEOUT)) {
592                                 if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
593                                         AAFSSO.cons.printf("===> There are no artifacts for %s on machine '%s'\n", mechID, key);
594                                 } else {
595                                         for(Artifact a : acf.value.getArtifact()) {
596                                                 String osID = System.getProperty("user.name");
597                                                 if(a.getOsUser().equals(osID)) {
598                                                         CertificateRequest cr = new CertificateRequest();
599                                                         cr.setMechid(a.getMechid());
600                                                         cr.setSponsor(a.getSponsor());
601                                                         for(int i=0;i<fqdns.length;++i) {
602                                                                 cr.getFqdns().add(fqdns[i]);
603                                                         }
604                                                         Future<String> f = aafcon.client(CM_VER)
605                                                                         .updateRespondString("/cert/" + a.getCa()+"?withTrust",reqDF, cr);
606                                                         if(f.get(TIMEOUT)) {
607                                                                 CertInfo capi = certDF.newData().in(TYPE.JSON).load(f.body()).asObject();
608                                                                 for(String type : a.getType()) {
609                                                                         PlaceArtifact pa = placeArtifact.get(type);
610                                                                         if(pa!=null) {
611                                                                                 if(rv = pa.place(trans, capi, a,machine)) {
612                                                                                         notifyPlaced(a,rv);
613                                                                                 }
614                                                                         }
615                                                                 }
616                                                                 // Cover for the above multiple pass possibilities with some static Data, then clear per Artifact
617                                                         } else {
618                                                                 trans.error().log(errMsg.toMsg(f));
619                                                         }
620                                                 } else {
621                                                         trans.error().log("You must be OS User \"" + a.getOsUser() +"\" to place Certificates on this box");
622                                                 }
623                                         }
624                                 }
625                         } else {
626                                 trans.error().log(errMsg.toMsg(acf));
627                         }
628                 } finally {
629                         tt.done();
630                 }
631                 return rv;
632         }
633         
634         private static void notifyPlaced(Artifact a, boolean rv) {
635         }
636
637         private static void showPass(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
638                 String mechID = fqi(cmds);
639                 String machine = machine(cmds);
640
641                 TimeTaken tt = trans.start("Show Password", Env.REMOTE);
642                 try {
643                         Future<Artifacts> acf = aafcon.client(CM_VER)
644                                         .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
645                         if(acf.get(TIMEOUT)) {
646                                 // Have to wait for JDK 1.7 source...
647                                 //switch(artifact.getType()) {
648                                 if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
649                                         AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
650                                 } else {
651                                         String id = aafcon.defID();
652                                         boolean allowed;
653                                         for(Artifact a : acf.value.getArtifact()) {
654                                                 allowed = id!=null && (id.equals(a.getSponsor()) ||
655                                                                 (id.equals(a.getMechid()) 
656                                                                                 && aafcon.securityInfo().defSS.getClass().isAssignableFrom(HBasicAuthSS.class)));
657                                                 if(!allowed) {
658                                                         Future<String> pf = aafcon.client(CM_VER).read("/cert/may/" + 
659                                                                         a.getNs() + ".certman|"+a.getCa()+"|showpass","*/*");
660                                                         if(pf.get(TIMEOUT)) {
661                                                                 allowed = true;
662                                                         } else {
663                                                                 trans.error().log(errMsg.toMsg(pf));
664                                                         }
665                                                 }
666                                                 if(allowed) {
667                                                         File dir = new File(a.getDir());
668                                                         Properties props = new Properties();
669                                                         FileInputStream fis = new FileInputStream(new File(dir,a.getNs()+".cred.props"));
670                                                         try {
671                                                                 props.load(fis);
672                                                                 fis.close();
673                                                                 fis = new FileInputStream(new File(dir,a.getNs()+".chal"));
674                                                                 props.load(fis);
675                                                         } finally {
676                                                                 fis.close();
677                                                         }
678                                                         
679                                                         File f = new File(dir,a.getNs()+".keyfile");
680                                                         if(f.exists()) {
681                                                                 Symm symm = Symm.obtain(f);
682                                                                 
683                                                                 for(Iterator<Entry<Object,Object>> iter = props.entrySet().iterator(); iter.hasNext();) {
684                                                                         Entry<Object,Object> en = iter.next();
685                                                                         if(en.getValue().toString().startsWith("enc:")) {
686                                                                                 System.out.printf("%s=%s\n", en.getKey(), symm.depass(en.getValue().toString()));
687                                                                         }
688                                                                 }
689                                                         } else {
690                                                                 trans.error().printf("%s.keyfile must exist to read passwords for %s on %s",
691                                                                                 f.getAbsolutePath(),a.getMechid(), a.getMachine());
692                                                         }
693                                                 }
694                                         }
695                                 }
696                         } else {
697                                 trans.error().log(errMsg.toMsg(acf));
698                         }
699                 } finally {
700                         tt.done();
701                 }
702
703         }
704         
705         private static void keypairGen(final Trans trans, final PropAccess access, final Deque<String> cmds) throws IOException {
706                 final String fqi = fqi(cmds);
707                 final String ns = FQI.reverseDomain(fqi);
708                 File dir = new File(access.getProperty(Config.CADI_ETCDIR,".")); // default to current Directory
709                 File f = new File(dir,ns+".key");
710                 
711                 if(f.exists()) {
712                         String line = AAFSSO.cons.readLine("%s exists. Overwrite? (y/n): ", f.getCanonicalPath());
713                         if(!"Y".equalsIgnoreCase(line)) {
714                                 System.out.println("Canceling...");
715                                 return;
716                         }
717                 }
718                 
719                 KeyPair kp = Factory.generateKeyPair(trans);
720                 ArtifactDir.write(f, Chmod.to400, Factory.toString(trans, kp.getPrivate()));
721                 System.out.printf("Wrote %s\n", f.getCanonicalFile());
722
723                 f=new File(dir,ns+".pubkey");
724                 ArtifactDir.write(f, Chmod.to644, Factory.toString(trans, kp.getPublic()));
725                 System.out.printf("Wrote %s\n", f.getCanonicalFile());
726         }
727         
728         private static void config(Trans trans, PropAccess pa, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
729                 final String fqi = fqi(cmds);
730                 final String rootFile = FQI.reverseDomain(fqi);
731                 final File dir = new File(pa.getProperty(Config.CADI_ETCDIR, "."));
732                 if(dir.exists()) {
733                         System.out.println("Writing to " + dir.getCanonicalFile());
734                 } else if(dir.mkdirs()) {
735                         System.out.println("Created directory " + dir.getCanonicalFile());
736                 } else {
737                         System.err.println("Unable to create or write to " + dir.getCanonicalPath());
738                         return;
739                 }
740                 
741                 TimeTaken tt = trans.start("Get Configuration", Env.REMOTE);
742                 try {
743                         boolean ok=false;
744                         File fProps = File.createTempFile(rootFile, ".tmp",dir);
745                         File fSecureTempProps = File.createTempFile(rootFile, ".cred.tmp",dir);
746                         File fSecureProps = new File(dir,rootFile+".cred.props");
747                         PrintStream psProps;
748
749                         File fLocProps = new File(dir,rootFile + ".location.props");
750                         if(!fLocProps.exists()) {
751                                 psProps = new PrintStream(new FileOutputStream(fLocProps));
752                                 try {
753                                         psProps.println(HASHES);
754                                         psProps.print("# Configuration File generated on ");
755                                         psProps.println(new Date().toString());
756                                         psProps.println(HASHES);
757                                         for(String tag : new String[] {Config.CADI_LATITUDE,Config.CADI_LONGITUDE}) {
758                                                 psProps.print(tag);
759                                                 psProps.print('=');
760                                                 psProps.println(getProperty(pa, trans, false, tag, "%s: ",tag));
761                                         }
762                                 } finally {
763                                         psProps.close();
764                                 }
765                         }
766
767                         psProps = new PrintStream(new FileOutputStream(fProps));
768                         try {
769                                 PrintStream psCredProps = new PrintStream(new FileOutputStream(fSecureTempProps));
770                                 try {
771                                         psCredProps.println(HASHES);
772                                         psCredProps.print("# Configuration File generated on ");
773                                         psCredProps.println(new Date().toString());
774                                         psCredProps.println(HASHES);
775
776                                         psProps.println(HASHES);
777                                         psProps.print("# Configuration File generated on ");
778                                         psProps.println(new Date().toString());
779                                         psProps.println(HASHES);
780                                         
781                                         psProps.print(Config.CADI_PROP_FILES);
782                                         psProps.print('=');
783                                         psProps.print(fSecureProps.getCanonicalPath());
784                                         psProps.print(File.pathSeparatorChar);
785                                         psProps.println(fLocProps.getCanonicalPath());
786                                         
787                                         File fkf = new File(dir,rootFile+".keyfile");
788                                         if(!fkf.exists()) {
789                                                 CmdLine.main(new String[] {"keygen",fkf.toString()});
790                                         }
791                                         psCredProps.print("cadi_keyfile=");
792                                         psCredProps.println(fkf.getCanonicalPath());
793                                         
794                                         psCredProps.print(Config.AAF_APPID);
795                                         psCredProps.print('=');
796                                         psCredProps.println(fqi);
797                                         
798                                         Symm filesymm = Symm.obtain(fkf);
799                                         psCredProps.print(Config.AAF_APPPASS);
800                                         psCredProps.print("=enc:");
801                                         String ps = pa.decrypt(pa.getProperty(Config.AAF_APPPASS), false);
802                                         ps = filesymm.enpass(ps);
803                                         psCredProps.println(ps);
804
805                                         String cts = pa.getProperty(Config.CADI_TRUSTSTORE);
806                                         if(cts!=null) {
807                                                 File origTruststore = new File(cts);
808                                                 if(!origTruststore.exists()) {
809                                                         // Try same directory as cadi_prop_files
810                                                         String cpf = pa.getProperty(Config.CADI_PROP_FILES);
811                                                         if(cpf!=null) {
812                                                                 for(String f : Split.split(File.pathSeparatorChar, cpf)) {
813                                                                         File fcpf = new File(f);
814                                                                         if(fcpf.exists()) {
815                                                                                 int lastSep = cts.lastIndexOf(File.pathSeparator);
816                                                                                 origTruststore = new File(fcpf.getParentFile(),lastSep>=0?cts.substring(lastSep):cts);
817                                                                                 if(origTruststore.exists()) { 
818                                                                                         break;
819                                                                                 }
820                                                                         }
821                                                                 }
822                                                                 if(!origTruststore.exists()) {
823                                                                         throw new CadiException(cts + "does not exist");
824                                                                 }
825                                                         }
826                                                         
827                                                 }
828                                                 File newTruststore = new File(dir,origTruststore.getName());
829                                                 if(!newTruststore.exists()) {
830                                                         Files.copy(origTruststore.toPath(), newTruststore.toPath());
831                                                 }
832                                                 psCredProps.print(Config.CADI_TRUSTSTORE);
833                                                 psCredProps.print("=");
834                                                 psCredProps.println(newTruststore.getCanonicalPath());
835                 
836                                                 psCredProps.print(Config.CADI_TRUSTSTORE_PASSWORD);
837                                                 psCredProps.print("=enc:");
838                                                 ps = pa.decrypt(pa.getProperty(Config.CADI_TRUSTSTORE_PASSWORD), false);
839                                                 ps = filesymm.enpass(ps);
840                                                 psCredProps.println(ps);
841                                         }
842                                         
843 //                                      String cadi_x509_issuers = pa.getProperty(Config.CADI_X509_ISSUERS);
844 //                                      if(cadi_x509_issuers!=null) {
845 //                                              psCredProps.print(Config.CADI_X509_ISSUERS);
846 //                                              psCredProps.print('=');
847 //                                              psCredProps.println(cadi_x509_issuers);
848 //                                      }
849
850                                         
851                                         try {
852                                                 if(aafcon!=null) { // get Properties from Remote AAF
853                                                         final String locator = getProperty(pa,aafcon.env,false,Config.AAF_LOCATE_URL,"AAF Locator URL: ");
854
855                                                         Future<Configuration> acf = aafcon.client(new SingleEndpointLocator(locator))
856                                                                         .read("/configure/"+fqi+"/aaf", configDF);
857                                                         if(acf.get(TIMEOUT)) {
858                                                                 PrintStream pstemp;
859                                                                 for(Props props : acf.value.getProps()) {
860                                                                         if(Config.CADI_X509_ISSUERS.equals(props.getTag())) {
861                                                                                 pstemp=psCredProps;
862                                                                         } else {
863                                                                                 pstemp = psProps;
864                                                                         }
865                                                                         pstemp.print(props.getTag());
866                                                                         pstemp.print('=');
867                                                                         pstemp.println(props.getValue());                                       
868                                                                 }
869                                                                 ok = true;
870                                                         } else if(acf.code()==401){
871                                                                 trans.error().log("Bad Password sent to AAF");
872                                                         } else {
873                                                                 trans.error().log(errMsg.toMsg(acf));
874                                                         }
875                                                 } else {
876                                                         String cpf = pa.getProperty(Config.CADI_PROP_FILES);
877                                                         if(cpf!=null){
878                                                                 for(String f : Split.split(File.pathSeparatorChar, cpf)) {
879                                                                         System.out.format("Reading %s\n",f);
880                                                                         FileInputStream fis = new FileInputStream(f); 
881                                                                         try {
882                                                                                 Properties props = new Properties();
883                                                                                 props.load(fis);
884                                                                                 PrintStream pstemp;
885                                                                                 String key,value;
886                                                                                 for(Entry<Object, Object> prop : props.entrySet()) {
887                                                                                         key = prop.getKey().toString();
888                                                                                         if(Config.CADI_X509_ISSUERS.equals(key)) {
889                                                                                                 pstemp=psCredProps;
890                                                                                                 value = prop.getValue().toString();
891                                                                                         } else if(key.endsWith("_password")){
892                                                                                                 if(Config.AAF_APPPASS.equals(key) || Config.CADI_TRUSTSTORE_PASSWORD.equals(key)) {
893                                                                                                         continue;
894                                                                                                 }
895                                                                                                 value = "enc:" + filesymm.enpass(prop.getValue().toString());
896                                                                                                 pstemp = psCredProps;
897                                                                                         } else if(Config.CADI_TRUSTSTORE.equals(key)) {
898                                                                                                 continue;
899                                                                                         } else {
900                                                                                                 value = prop.getValue().toString();
901                                                                                                 pstemp = psProps;
902                                                                                         }
903                                                                                         pstemp.print(key);
904                                                                                         pstemp.print('=');
905                                                                                         pstemp.println(value);
906                                                                                 }
907                                                                         } finally {
908                                                                                 fis.close();
909                                                                         }
910                                                                 }
911                                                         }
912                                                         ok = true;
913                                                 }
914                                         } finally {
915                                                 psProps.close();
916                                         }
917                                         if(ok) {
918                                                 File newFile = new File(dir,rootFile+".props");
919                                                 fProps.renameTo(newFile);
920                                                 System.out.println("Created " + newFile.getCanonicalPath());
921                                                 fProps = newFile;
922                                                 
923                                                 fSecureTempProps.renameTo(fSecureProps);
924                                                 System.out.println("Created " + fSecureProps.getCanonicalPath());
925                                                 fProps = newFile;
926                                         } else {
927                                                 fProps.delete();
928                                                 fSecureTempProps.delete();
929                                         }
930                                 } finally {
931                                         psCredProps.close();
932                                 }
933                         } finally {
934                                 psProps.close();
935                         }
936                 } finally {
937                         tt.done();
938                 }
939         }
940         
941         private static void validate(final PropAccess pa) throws LocatorException, CadiException, APIException {
942                 System.out.println("Validating Configuration...");
943                 final AAFCon<?> aafcon = new AAFConHttp(pa,Config.AAF_URL,new SecurityInfoC<HttpURLConnection>(pa));
944                 aafcon.best(new Retryable<Void>() {
945                         @Override
946                         public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
947                                 Future<Perms> fc = client.read("/authz/perms/user/"+aafcon.defID(),permDF);
948                                 if(fc.get(aafcon.timeout)) {
949                                         System.out.print("Success connecting to ");
950                                         System.out.println(client.getURI());
951                                         System.out.print("   Permissions for ");
952                                         System.out.println(aafcon.defID());
953                                         for(Perm p : fc.value.getPerm()) {
954                                                 System.out.print('\t');
955                                                 System.out.print(p.getType());
956                                                 System.out.print('|');
957                                                 System.out.print(p.getInstance());
958                                                 System.out.print('|');
959                                                 System.out.println(p.getAction());
960                                         }
961                                 } else {
962                                         System.err.println("Error: " + fc.code() + ' ' + fc.body());
963                                 }
964                                 return null;
965                         }
966                 });
967         }
968
969         /**
970          * Check returns Error Codes, so that Scripts can know what to do
971          * 
972          *   0 - Check Complete, nothing to do
973          *   1 - General Error
974          *   2 - Error for specific Artifact - read check.msg
975          *   10 - Certificate Updated - check.msg is email content
976          *   
977          * @param trans
978          * @param aafcon
979          * @param cmds
980          * @return
981          * @throws Exception
982          */
983         private static int check(Trans trans, AAFCon<?> aafcon, Deque<String> cmds) throws Exception {
984                 int exitCode=1;
985                 String mechID = fqi(cmds);
986                 String machine = machine(cmds);
987                 
988                 TimeTaken tt = trans.start("Check Certificate", Env.REMOTE);
989                 try {
990                 
991                         Future<Artifacts> acf = aafcon.client(CM_VER)
992                                         .read("/cert/artifacts/"+mechID+'/'+machine, artifactsDF);
993                         if(acf.get(TIMEOUT)) {
994                                 // Have to wait for JDK 1.7 source...
995                                 //switch(artifact.getType()) {
996                                 if(acf.value.getArtifact()==null || acf.value.getArtifact().isEmpty()) {
997                                         AAFSSO.cons.printf("No Artifacts found for %s on %s", mechID, machine);
998                                 } else {
999                                         String id = aafcon.defID();
1000                                         GregorianCalendar now = new GregorianCalendar();
1001                                         for(Artifact a : acf.value.getArtifact()) {
1002                                                 if(id.equals(a.getMechid())) {
1003                                                         File dir = new File(a.getDir());
1004                                                         Properties props = new Properties();
1005                                                         FileInputStream fis = new FileInputStream(new File(dir,a.getNs()+".props"));
1006                                                         try {
1007                                                                 props.load(fis);
1008                                                         } finally {
1009                                                                 fis.close();
1010                                                         }
1011                                                         
1012                                                         String prop;                                            
1013                                                         File f;
1014         
1015                                                         if((prop=props.getProperty(Config.CADI_KEYFILE))==null ||
1016                                                                 !(f=new File(prop)).exists()) {
1017                                                                         trans.error().printf("Keyfile must exist to check Certificates for %s on %s",
1018                                                                                 a.getMechid(), a.getMachine());
1019                                                         } else {
1020                                                                 String ksf = props.getProperty(Config.CADI_KEYSTORE);
1021                                                                 String ksps = props.getProperty(Config.CADI_KEYSTORE_PASSWORD);
1022                                                                 if(ksf==null || ksps == null) {
1023                                                                         trans.error().printf("Properties %s and %s must exist to check Certificates for %s on %s",
1024                                                                                         Config.CADI_KEYSTORE, Config.CADI_KEYSTORE_PASSWORD,a.getMechid(), a.getMachine());
1025                                                                 } else {
1026                                                                         KeyStore ks = KeyStore.getInstance("JKS");
1027                                                                         Symm symm = Symm.obtain(f);
1028                                                                         
1029                                                                         fis = new FileInputStream(ksf);
1030                                                                         try {
1031                                                                                 ks.load(fis,symm.depass(ksps).toCharArray());
1032                                                                         } finally {
1033                                                                                 fis.close();
1034                                                                         }
1035                                                                         X509Certificate cert = (X509Certificate)ks.getCertificate(mechID);
1036                                                                         String msg = null;
1037
1038                                                                         if(cert==null) {
1039                                                                                 msg = String.format("X509Certificate does not exist for %s on %s in %s",
1040                                                                                                 a.getMechid(), a.getMachine(), ksf);
1041                                                                                 trans.error().log(msg);
1042                                                                                 exitCode = 2;
1043                                                                         } else {
1044                                                                                 GregorianCalendar renew = new GregorianCalendar();
1045                                                                                 renew.setTime(cert.getNotAfter());
1046                                                                                 renew.add(GregorianCalendar.DAY_OF_MONTH,-1*a.getRenewDays());
1047                                                                                 if(renew.after(now)) {
1048                                                                                         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", 
1049                                                                                                         a.getMechid(), a.getMachine(),Chrono.dateOnlyStamp(now),cert.getNotAfter(),Chrono.dateOnlyStamp(renew));
1050                                                                                         trans.info().log(msg);
1051                                                                                         exitCode = 0; // OK
1052                                                                                 } else {
1053                                                                                         trans.info().printf("X509Certificate for %s on %s expiration, %s, needs Renewal.\n", 
1054                                                                                                         a.getMechid(), a.getMachine(),cert.getNotAfter());
1055                                                                                         cmds.offerLast(mechID);
1056                                                                                         cmds.offerLast(machine);
1057                                                                                         if(placeCerts(trans,aafcon,cmds)) {
1058                                                                                                 msg = String.format("X509Certificate for %s on %s has been renewed. Ensure services using are refreshed.\n", 
1059                                                                                                                 a.getMechid(), a.getMachine());
1060                                                                                                 exitCode = 10; // Refreshed
1061                                                                                         } else {
1062                                                                                                 msg = String.format("X509Certificate for %s on %s attempted renewal, but failed. Immediate Investigation is required!\n", 
1063                                                                                                                 a.getMechid(), a.getMachine());
1064                                                                                                 exitCode = 1; // Error Renewing
1065                                                                                         }
1066                                                                                 }
1067                                                                         }
1068                                                                         if(msg!=null) {
1069                                                                                 FileOutputStream fos = new FileOutputStream(a.getDir()+'/'+a.getNs()+".msg");
1070                                                                                 try {
1071                                                                                         fos.write(msg.getBytes());
1072                                                                                 } finally {
1073                                                                                         fos.close();
1074                                                                                 }
1075                                                                         }
1076                                                                 }
1077                                                                 
1078                                                         }
1079                                                 }
1080                                         }
1081                                 }
1082                         } else {
1083                                 trans.error().log(errMsg.toMsg(acf));
1084                                 exitCode=1;
1085                         }
1086                 } finally {
1087                         tt.done();
1088                 }
1089                 return exitCode;
1090         }
1091
1092 }
1093                         
1094                 
1095
1096