Add Cert Cred for aafcli
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / sso / AAFSSO.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.sso;
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.InputStream;
29 import java.io.PrintStream;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Map.Entry;
35 import java.util.Properties;
36
37 import org.onap.aaf.cadi.Access.Level;
38 import org.onap.aaf.cadi.CadiException;
39 import org.onap.aaf.cadi.PropAccess;
40 import org.onap.aaf.cadi.Symm;
41 import org.onap.aaf.cadi.config.Config;
42 import org.onap.aaf.cadi.util.MyConsole;
43 import org.onap.aaf.cadi.util.SubStandardConsole;
44 import org.onap.aaf.cadi.util.TheConsole;
45
46 public class AAFSSO {
47         public static final MyConsole  cons = TheConsole.implemented() ? new TheConsole() : new SubStandardConsole();
48 //      private static final int EIGHT_HOURS = 8 * 60 * 60 * 1000;
49
50         private Properties diskprops;
51         private boolean touchDiskprops;
52         private File dot_aaf = null;
53         private File sso = null; // instantiated, if ever, with diskprops
54
55         boolean removeSSO = false;
56         boolean loginOnly = false;
57         boolean doExit = true;
58         private PropAccess access;
59         private StringBuilder err;
60         private String user;
61         private String encrypted_pass;
62         private boolean use_X509;
63
64         private PrintStream os;
65
66         private Method close;
67         private final PrintStream stdOutOrig;
68         private final PrintStream stdErrOrig;
69         private boolean ok;
70
71         public AAFSSO(String[] args) throws IOException, CadiException {
72                 ok = true;
73                 List<String> nargs = parseArgs(args);
74                 diskprops = new Properties();
75                 touchDiskprops = false;
76
77                 dot_aaf = new File(System.getProperty("user.home") + "/.aaf");
78                 if (!dot_aaf.exists()) {
79                         dot_aaf.mkdirs();
80                 }
81                 stdOutOrig = System.out;
82                 stdErrOrig = System.err;
83                 File f = new File(dot_aaf, "sso.out");
84                 os = new PrintStream(new FileOutputStream(f, true));
85                 System.setOut(os);
86                 System.setErr(os);
87
88                 sso = new File(dot_aaf, "sso.props");
89                 if(sso.exists()) {
90                         InputStream propStream = new FileInputStream(sso);
91                         try {
92                                 diskprops.load(propStream);
93                         } finally {
94                                 propStream.close();
95                         }
96                 }
97                 
98 //              String keyfile = diskprops.getProperty(Config.CADI_KEYFILE);
99 //              if(keyfile==null) {
100 //                      keyfile = dot_aaf.getCanonicalPath()+".keyfile";
101 //                      touchDiskprops=true;
102 //              }
103                 File dot_aaf_kf = new File(dot_aaf, "keyfile");
104
105                 if (removeSSO) {
106                         if (dot_aaf_kf.exists()) {
107                                 dot_aaf_kf.setWritable(true, true);
108                                 dot_aaf_kf.delete();
109                         }
110                         if (sso.exists()) {
111                                 Properties temp = new Properties();
112                                 // Keep only these
113                                 for(Entry<Object, Object> es : diskprops.entrySet()) {
114                                         if(Config.CADI_LATITUDE.equals(es.getKey()) ||
115                                            Config.CADI_LONGITUDE.equals(es.getKey()) ||
116                                            Config.AAF_DEFAULT_REALM.equals(es.getKey())) {
117                                                  temp.setProperty(es.getKey().toString(), es.getValue().toString());
118                                         }
119                                 }
120                                 diskprops = temp;
121                                 touchDiskprops = true;
122                         }
123                         String[] naargs = new String[nargs.size()];
124                         nargs.toArray(naargs);
125                         access = new PropAccess(os, naargs);
126                         ok = false;
127                         setLogDefault();
128                         System.out.println("AAF SSO information removed");
129                 } else {
130                         //      Config.setDefaultRealm(access);
131         
132                         if (!dot_aaf_kf.exists()) {
133                                 FileOutputStream fos = new FileOutputStream(dot_aaf_kf);
134                                 try {
135                                         fos.write(Symm.keygen());
136                                         setReadonly(dot_aaf_kf);
137                                 } finally {
138                                         fos.close();
139                                 }
140                         }
141
142                         for(Entry<Object, Object> es : diskprops.entrySet()) {
143                                 nargs.add(es.getKey().toString() + '=' + es.getValue().toString());
144                         }
145                         String[] naargs = new String[nargs.size()];
146                         nargs.toArray(naargs);
147                         access = new PropAccess(os, naargs);
148                         
149                         if(loginOnly) {
150                                 for(String tag : new String[] {Config.AAF_APPID, Config.AAF_APPPASS, 
151                                                 Config.CADI_ALIAS, Config.CADI_KEYSTORE,Config.CADI_KEYSTORE_PASSWORD,Config.CADI_KEY_PASSWORD}) {
152                                         access.getProperties().remove(tag);
153                                         diskprops.remove(tag);
154                                 }
155                                 touchDiskprops=true;
156 // TODO Do we want to require reset of Passwords at least every Eight Hours.
157 //                      } else if (sso.lastModified() > (System.currentTimeMillis() - EIGHT_HOURS)) {
158 //                              for(String tag : new String[] {Config.AAF_APPPASS,Config.CADI_KEYSTORE_PASSWORD,Config.CADI_KEY_PASSWORD}) {
159 //                                      access.getProperties().remove(tag);
160 //                                      diskprops.remove(tag);
161 //                              }
162 //                              touchDiskprops=true;
163                         }
164         
165                         String keyfile = access.getProperty(Config.CADI_KEYFILE); // in case its CertificateMan props
166                         if (keyfile == null) {
167                                 access.setProperty(Config.CADI_KEYFILE, dot_aaf_kf.getAbsolutePath());
168                                 addProp(Config.CADI_KEYFILE,dot_aaf_kf.getAbsolutePath());
169                         }
170         
171         
172                         String alias, appID;
173                         alias = access.getProperty(Config.CADI_ALIAS);
174                         if(alias==null) {
175                                 appID = access.getProperty(Config.AAF_APPID);
176                                 user=appID;
177                         } else {
178                                 user=alias;
179                                 appID=null;
180                         }
181                         
182                         String keystore=access.getProperty(Config.CADI_KEYSTORE);
183                         String keystore_pass=access.getProperty(Config.CADI_KEYSTORE_PASSWORD);
184                         
185                         if(user==null || (alias!=null && (keystore==null || keystore_pass==null))) {
186                                 String select = null;
187                                 String name;
188                                 for (File tsf : dot_aaf.listFiles()) {
189                                         name = tsf.getName();
190                                         if (!name.contains("trust") && (name.endsWith(".jks") || name.endsWith(".p12"))) {
191                                                 select = cons.readLine("Use %s for Identity? (y/n): ",tsf.getName());
192                                                 if("y".equalsIgnoreCase(select)) {
193                                                         keystore = tsf.getCanonicalPath();
194                                                         access.setProperty(Config.CADI_KEYSTORE, keystore);
195                                                         addProp(Config.CADI_KEYSTORE, keystore);
196                                                         char[] password = cons.readPassword("Keystore Password: ");
197                                                         encrypted_pass= access.encrypt(new String(password));
198                                                         access.setProperty(Config.CADI_KEYSTORE_PASSWORD, encrypted_pass);
199                                                         addProp(Config.CADI_KEYSTORE_PASSWORD, encrypted_pass);
200                                                         
201                                                         // TODO READ Aliases out of Keystore?
202                                                         user = alias = cons.readLine("Keystore alias: ");
203                                                         access.setProperty(Config.CADI_ALIAS, user);
204                                                         addProp(Config.CADI_ALIAS, user);
205                                                         break;
206                                                 }
207                                         }
208                                 }
209                                 if(alias==null) {
210                                         user = appID = cons.readLine(Config.AAF_APPID + ": ");
211                                         access.setProperty(Config.AAF_APPID, appID);
212                                         addProp(Config.AAF_APPID, appID);
213                                         char[] password = cons.readPassword(Config.AAF_APPPASS + ": ");
214                                         encrypted_pass= access.encrypt(new String(password));
215                                         access.setProperty(Config.AAF_APPPASS, encrypted_pass);
216                                         addProp(Config.AAF_APPPASS, encrypted_pass);
217                                 }
218                         } else {
219                                 encrypted_pass = access.getProperty(Config.CADI_KEYSTORE_PASSWORD);
220                                 if(encrypted_pass == null) {
221                                         keystore_pass = null;
222                                         encrypted_pass = access.getProperty(Config.AAF_APPPASS);
223                                 } else {
224                                         keystore_pass = encrypted_pass;
225                                 }
226                         }
227                         
228         
229                         if (alias!=null) {
230                                 use_X509 = true;
231                         } else {
232                                 use_X509 = false;
233                                 Symm decryptor = Symm.obtain(dot_aaf_kf);
234                                 if (user == null) {
235                                         if (sso.exists()) {
236                                                 String cm_url = access.getProperty(Config.CM_URL); // SSO might overwrite...
237                                                 FileInputStream fos = new FileInputStream(sso);
238                                                 try {
239                                                         access.load(fos);
240                                                         user = access.getProperty(Config.AAF_APPID);
241                                                         encrypted_pass = access.getProperty(Config.AAF_APPPASS);
242                                                         // decrypt with .aaf, and re-encrypt with regular Keyfile
243                                                         access.setProperty(Config.AAF_APPPASS,
244                                                                         access.encrypt(decryptor.depass(encrypted_pass)));
245                                                         if (cm_url != null) { //Command line CM_URL Overwrites ssofile.
246                                                                 access.setProperty(Config.CM_URL, cm_url);
247                                                         }
248                                                 } finally {
249                                                         fos.close();
250                                                 }
251                                         } else {
252                                                 diskprops = new Properties();
253                                                 String realm = Config.getDefaultRealm();
254                                                 // Turn on Console Sysout
255                                                 System.setOut(System.out);
256                                                 user = cons.readLine("aaf_id(%s@%s): ", System.getProperty("user.name"), realm);
257                                                 if (user == null) {
258                                                         user = System.getProperty("user.name") + '@' + realm;
259                                                 } else if (user.length() == 0) { //
260                                                         user = System.getProperty("user.name") + '@' + realm;
261                                                 } else if ((user.indexOf('@') < 0) && (realm != null)) {
262                                                         user = user + '@' + realm;
263                                                 }
264                                                 access.setProperty(Config.AAF_APPID, user);
265                                                 diskprops.setProperty(Config.AAF_APPID, user);
266                                                 encrypted_pass = new String(cons.readPassword("aaf_password: "));
267                                                 System.setOut(os);
268                                                 encrypted_pass = Symm.ENC + decryptor.enpass(encrypted_pass);
269                                                 access.setProperty(Config.AAF_APPPASS, encrypted_pass);
270                                                 diskprops.setProperty(Config.AAF_APPPASS, encrypted_pass);
271                                                 diskprops.setProperty(Config.CADI_KEYFILE, access.getProperty(Config.CADI_KEYFILE));
272                                         }
273                                 }
274                         }
275                         if (user == null) {
276                                 err = new StringBuilder("Add -D" + Config.AAF_APPID + "=<id> ");
277                         }
278         
279                         if (encrypted_pass == null && alias == null) {
280                                 if (err == null) {
281                                         err = new StringBuilder();
282                                 } else {
283                                         err.append("and ");
284                                 }
285                                 err.append("-D" + Config.AAF_APPPASS + "=<passwd> ");
286                         }
287                         
288                         String locateUrl = access.getProperty(Config.AAF_LOCATE_URL);
289                         if(locateUrl==null) {
290                                 locateUrl=AAFSSO.cons.readLine("AAF Locator FQDN/machine[:port]=https://");
291                                 if(locateUrl==null || locateUrl.length()==0) {
292                                         err = new StringBuilder(Config.AAF_LOCATE_URL);
293                                         err.append(" is required.");
294                                         ok = false;
295                                         return;
296                                 } else {
297                                         locateUrl="https://"+locateUrl+"/locate";
298                                 }
299                                 access.setProperty(Config.AAF_LOCATE_URL, locateUrl);
300                                 addProp(Config.AAF_LOCATE_URL, locateUrl);
301                         }
302                         
303                         String aafUrl = "https://AAF_LOCATE_URL/AAF_NS.service/2.0";
304                         access.setProperty(Config.AAF_URL, aafUrl);
305                         access.setProperty(Config.CM_URL, "https://AAF_LOCATE_URL/AAF_NS.cm/2.0");
306                         String cadiLatitude = access.getProperty(Config.CADI_LATITUDE);
307                         if(cadiLatitude==null) {
308                                 System.out.println("# If you do not know your Global Coordinates, we suggest bing.com/maps");
309                                 cadiLatitude=AAFSSO.cons.readLine("cadi_latitude[0.000]=");
310                                 if(cadiLatitude==null || cadiLatitude.isEmpty()) {
311                                         cadiLatitude="0.000";
312                                 }
313                                 access.setProperty(Config.CADI_LATITUDE, cadiLatitude);
314                                 addProp(Config.CADI_LATITUDE, cadiLatitude);
315                                 
316                         }
317                         String cadiLongitude = access.getProperty(Config.CADI_LONGITUDE);
318                         if(cadiLongitude==null) {
319                                 cadiLongitude=AAFSSO.cons.readLine("cadi_longitude[0.000]=");
320                                 if(cadiLongitude==null || cadiLongitude.isEmpty()) {
321                                         cadiLongitude="0.000";
322                                 }
323                                 access.setProperty(Config.CADI_LONGITUDE, cadiLongitude);
324                                 addProp(Config.CADI_LONGITUDE, cadiLongitude);
325                         }
326         
327                         String cadi_truststore = access.getProperty(Config.CADI_TRUSTSTORE);
328                         if(cadi_truststore==null) {
329                                 String name; 
330                                 String select;
331                                 for (File tsf : dot_aaf.listFiles()) {
332                                         name = tsf.getName();
333                                         if (name.contains("trust") && 
334                                                         (name.endsWith(".jks") || name.endsWith(".p12"))) {
335                                                 select = cons.readLine("Use %s for TrustStore? (y/n):",tsf.getName());
336                                                 if("y".equalsIgnoreCase(select)) {
337                                                         cadi_truststore=tsf.getCanonicalPath();
338                                                         access.setProperty(Config.CADI_TRUSTSTORE, cadi_truststore);
339                                                         addProp(Config.CADI_TRUSTSTORE, cadi_truststore);
340                                                         break;
341                                                 }
342                                         }
343                                 }
344                         }
345                         if(cadi_truststore!=null) {
346                                 if(cadi_truststore.indexOf(File.separatorChar)<0) {
347                                         cadi_truststore=dot_aaf.getPath()+File.separator+cadi_truststore;
348                                 }
349                                 String cadi_truststore_password = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD);
350                                 if(cadi_truststore_password==null) {
351                                         cadi_truststore_password=AAFSSO.cons.readLine("cadi_truststore_password[%s]=","changeit");
352                                         cadi_truststore_password = access.encrypt(cadi_truststore_password);
353                                         access.setProperty(Config.CADI_TRUSTSTORE_PASSWORD, cadi_truststore_password);
354                                         addProp(Config.CADI_TRUSTSTORE_PASSWORD, cadi_truststore_password);
355                                 }
356                         }
357                         ok = err==null;
358                 }
359                 writeFiles();
360         }
361
362         public void setLogDefault() {
363                 this.setLogDefault(PropAccess.DEFAULT);
364                 System.setOut(stdOutOrig);
365         }
366
367         public void setStdErrDefault() {
368                 access.setLogLevel(PropAccess.DEFAULT);
369                 System.setOut(stdErrOrig);
370         }
371
372         public void setLogDefault(Level level) {
373                 if(access!=null) {
374                         access.setLogLevel(level);
375                 }
376                 System.setOut(stdOutOrig);
377         }
378
379         public boolean loginOnly() {
380                 return loginOnly;
381         }
382
383         public void addProp(String key, String value) {
384                 if(key==null || value==null) {
385                         return;
386                 }
387                 touchDiskprops=true;
388                 diskprops.setProperty(key, value);
389         }
390
391         public void writeFiles() throws IOException {
392                 if(touchDiskprops) {
393                         // Store Creds, if they work
394                         if (diskprops != null) {
395                                 if (!dot_aaf.exists()) {
396                                         dot_aaf.mkdirs();
397                                 }
398                                 FileOutputStream fos = new FileOutputStream(sso);
399                                 try {
400                                         diskprops.store(fos, "AAF Single Signon");
401                                 } finally {
402                                         fos.close();
403                                         setReadonly(sso);
404                                 }
405                         }
406                         if (sso != null) {
407                                 setReadonly(sso);
408                                 sso.setWritable(true, true);
409                         }
410                 }
411         }
412
413         public PropAccess access() {
414                 return access;
415         }
416
417         public StringBuilder err() {
418                 return err;
419         }
420
421         public String user() {
422                 return user;
423         }
424
425         public String enc_pass() {
426                 return encrypted_pass;
427         }
428
429         public boolean useX509() {
430                 return use_X509;
431         }
432
433         public void close() {
434                 if (close != null) {
435                         try {
436                                 close.invoke(null);
437                         } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
438                                 // nothing to do here.
439                         }
440                         close = null;
441                 }
442         }
443
444         private List<String> parseArgs(String[] args)
445         {
446                 List<String> larg = new ArrayList<String>(args.length);
447
448                 // Cover for bash's need to escape *.. (\\*)
449                 // also, remove SSO if required
450                 for (int i = 0; i < args.length; ++i) {
451                         if ("\\*".equals(args[i])) {
452                                 args[i] = "*";
453                         }
454
455                         if ("-logout".equalsIgnoreCase(args[i])) {
456                                 removeSSO = true;
457                         } else if ("-login".equalsIgnoreCase(args[i])) {
458                                 loginOnly = true;
459                         } else if ("-noexit".equalsIgnoreCase(args[i])) {
460                                 doExit = false;
461                         } else {
462                                 larg.add(args[i]);
463                         }
464                 }
465                 return larg;
466         }
467         
468         private void setReadonly(File file) {
469                 file.setExecutable(false, false);
470                 file.setWritable(false, false);
471                 file.setReadable(false, false);
472                 file.setReadable(true, true);
473         }
474
475         public boolean ok() {
476                 return ok;
477         }
478 }