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