2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.cadi.sso;
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;
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;
47 public static final MyConsole cons = TheConsole.implemented() ? new TheConsole() : new SubStandardConsole();
48 // private static final int EIGHT_HOURS = 8 * 60 * 60 * 1000;
50 private Properties diskprops;
51 private boolean touchDiskprops;
52 private File dot_aaf = null;
53 private File sso = null; // instantiated, if ever, with diskprops
55 boolean removeSSO = false;
56 boolean loginOnly = false;
57 boolean doExit = true;
58 private PropAccess access;
59 private StringBuilder err;
61 private String encrypted_pass;
62 private boolean use_X509;
64 private PrintStream os;
67 private final PrintStream stdOutOrig;
68 private final PrintStream stdErrOrig;
71 public AAFSSO(String[] args) throws IOException, CadiException {
73 List<String> nargs = parseArgs(args);
74 diskprops = new Properties();
75 touchDiskprops = false;
77 dot_aaf = new File(System.getProperty("user.home") + "/.aaf");
78 if (!dot_aaf.exists()) {
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));
88 sso = new File(dot_aaf, "sso.props");
90 InputStream propStream = new FileInputStream(sso);
92 diskprops.load(propStream);
98 File dot_aaf_kf = new File(dot_aaf, "keyfile");
101 if (dot_aaf_kf.exists()) {
102 dot_aaf_kf.setWritable(true, true);
106 Properties temp = new Properties();
108 for(Entry<Object, Object> es : diskprops.entrySet()) {
109 if(Config.CADI_LATITUDE.equals(es.getKey()) ||
110 Config.CADI_LONGITUDE.equals(es.getKey()) ||
111 Config.AAF_DEFAULT_REALM.equals(es.getKey())) {
112 temp.setProperty(es.getKey().toString(), es.getValue().toString());
116 touchDiskprops = true;
118 String[] naargs = new String[nargs.size()];
119 nargs.toArray(naargs);
120 access = new PropAccess(os, naargs);
123 System.out.println("AAF SSO information removed");
125 // Config.setDefaultRealm(access);
127 if (!dot_aaf_kf.exists()) {
128 FileOutputStream fos = new FileOutputStream(dot_aaf_kf);
130 fos.write(Symm.keygen());
131 setReadonly(dot_aaf_kf);
137 for(Entry<Object, Object> es : diskprops.entrySet()) {
138 nargs.add(es.getKey().toString() + '=' + es.getValue().toString());
140 String[] naargs = new String[nargs.size()];
141 nargs.toArray(naargs);
142 access = new PropAccess(os, naargs);
145 for(String tag : new String[] {Config.AAF_APPID, Config.AAF_APPPASS,
146 Config.CADI_ALIAS, Config.CADI_KEYSTORE,Config.CADI_KEYSTORE_PASSWORD,Config.CADI_KEY_PASSWORD}) {
147 access.getProperties().remove(tag);
148 diskprops.remove(tag);
151 // TODO Do we want to require reset of Passwords at least every Eight Hours.
152 // } else if (sso.lastModified() > (System.currentTimeMillis() - EIGHT_HOURS)) {
153 // for(String tag : new String[] {Config.AAF_APPPASS,Config.CADI_KEYSTORE_PASSWORD,Config.CADI_KEY_PASSWORD}) {
154 // access.getProperties().remove(tag);
155 // diskprops.remove(tag);
157 // touchDiskprops=true;
160 String keyfile = access.getProperty(Config.CADI_KEYFILE); // in case its CertificateMan props
161 if (keyfile == null) {
162 access.setProperty(Config.CADI_KEYFILE, dot_aaf_kf.getAbsolutePath());
163 addProp(Config.CADI_KEYFILE,dot_aaf_kf.getAbsolutePath());
168 alias = access.getProperty(Config.CADI_ALIAS);
170 appID = access.getProperty(Config.AAF_APPID);
177 String keystore=access.getProperty(Config.CADI_KEYSTORE);
178 String keystore_pass=access.getProperty(Config.CADI_KEYSTORE_PASSWORD);
180 if(user==null || (alias!=null && (keystore==null || keystore_pass==null))) {
181 String select = null;
183 for (File tsf : dot_aaf.listFiles()) {
184 name = tsf.getName();
185 if (!name.contains("trust") && (name.endsWith(".jks") || name.endsWith(".p12"))) {
186 select = cons.readLine("Use %s for Identity? (y/n): ",tsf.getName());
187 if("y".equalsIgnoreCase(select)) {
188 keystore = tsf.getCanonicalPath();
189 access.setProperty(Config.CADI_KEYSTORE, keystore);
190 addProp(Config.CADI_KEYSTORE, keystore);
191 char[] password = cons.readPassword("Keystore Password: ");
192 encrypted_pass= access.encrypt(new String(password));
193 access.setProperty(Config.CADI_KEYSTORE_PASSWORD, encrypted_pass);
194 addProp(Config.CADI_KEYSTORE_PASSWORD, encrypted_pass);
196 // TODO READ Aliases out of Keystore?
197 user = alias = cons.readLine("Keystore alias: ");
198 access.setProperty(Config.CADI_ALIAS, user);
199 addProp(Config.CADI_ALIAS, user);
205 user = appID = cons.readLine(Config.AAF_APPID + ": ");
206 access.setProperty(Config.AAF_APPID, appID);
207 addProp(Config.AAF_APPID, appID);
208 char[] password = cons.readPassword(Config.AAF_APPPASS + ": ");
209 encrypted_pass= access.encrypt(new String(password));
210 access.setProperty(Config.AAF_APPPASS, encrypted_pass);
211 addProp(Config.AAF_APPPASS, encrypted_pass);
214 encrypted_pass = access.getProperty(Config.CADI_KEYSTORE_PASSWORD);
215 if(encrypted_pass == null) {
216 keystore_pass = null;
217 encrypted_pass = access.getProperty(Config.AAF_APPPASS);
219 keystore_pass = encrypted_pass;
228 Symm decryptor = Symm.obtain(dot_aaf_kf);
231 String cm_url = access.getProperty(Config.CM_URL); // SSO might overwrite...
232 FileInputStream fos = new FileInputStream(sso);
235 user = access.getProperty(Config.AAF_APPID);
236 encrypted_pass = access.getProperty(Config.AAF_APPPASS);
237 // decrypt with .aaf, and re-encrypt with regular Keyfile
238 access.setProperty(Config.AAF_APPPASS,
239 access.encrypt(decryptor.depass(encrypted_pass)));
240 if (cm_url != null) { //Command line CM_URL Overwrites ssofile.
241 access.setProperty(Config.CM_URL, cm_url);
247 diskprops = new Properties();
248 String realm = Config.getDefaultRealm();
249 // Turn on Console Sysout
250 System.setOut(System.out);
251 user = cons.readLine("aaf_id(%s@%s): ", System.getProperty("user.name"), realm);
253 user = System.getProperty("user.name") + '@' + realm;
254 } else if (user.length() == 0) { //
255 user = System.getProperty("user.name") + '@' + realm;
256 } else if ((user.indexOf('@') < 0) && (realm != null)) {
257 user = user + '@' + realm;
259 access.setProperty(Config.AAF_APPID, user);
260 diskprops.setProperty(Config.AAF_APPID, user);
261 encrypted_pass = new String(cons.readPassword("aaf_password: "));
263 encrypted_pass = Symm.ENC + decryptor.enpass(encrypted_pass);
264 access.setProperty(Config.AAF_APPPASS, encrypted_pass);
265 diskprops.setProperty(Config.AAF_APPPASS, encrypted_pass);
266 diskprops.setProperty(Config.CADI_KEYFILE, access.getProperty(Config.CADI_KEYFILE));
271 err = new StringBuilder("Add -D" + Config.AAF_APPID + "=<id> ");
274 if (encrypted_pass == null && alias == null) {
276 err = new StringBuilder();
280 err.append("-D" + Config.AAF_APPPASS + "=<passwd> ");
283 String locateUrl = access.getProperty(Config.AAF_LOCATE_URL);
284 if(locateUrl==null) {
285 locateUrl=AAFSSO.cons.readLine("AAF Locator FQDN/machine[:port]=https://");
286 if(locateUrl==null || locateUrl.length()==0) {
287 err = new StringBuilder(Config.AAF_LOCATE_URL);
288 err.append(" is required.");
292 locateUrl="https://"+locateUrl+"/locate";
294 access.setProperty(Config.AAF_LOCATE_URL, locateUrl);
295 addProp(Config.AAF_LOCATE_URL, locateUrl);
298 String aafUrl = "https://AAF_LOCATE_URL/AAF_NS.service:2.0";
299 access.setProperty(Config.AAF_URL, aafUrl);
300 access.setProperty(Config.CM_URL, "https://AAF_LOCATE_URL/AAF_NS.cm:2.0");
301 String cadiLatitude = access.getProperty(Config.CADI_LATITUDE);
302 if(cadiLatitude==null) {
303 System.out.println("# If you do not know your Global Coordinates, we suggest bing.com/maps");
304 cadiLatitude=AAFSSO.cons.readLine("cadi_latitude[0.000]=");
305 if(cadiLatitude==null || cadiLatitude.isEmpty()) {
306 cadiLatitude="0.000";
308 access.setProperty(Config.CADI_LATITUDE, cadiLatitude);
309 addProp(Config.CADI_LATITUDE, cadiLatitude);
312 String cadiLongitude = access.getProperty(Config.CADI_LONGITUDE);
313 if(cadiLongitude==null) {
314 cadiLongitude=AAFSSO.cons.readLine("cadi_longitude[0.000]=");
315 if(cadiLongitude==null || cadiLongitude.isEmpty()) {
316 cadiLongitude="0.000";
318 access.setProperty(Config.CADI_LONGITUDE, cadiLongitude);
319 addProp(Config.CADI_LONGITUDE, cadiLongitude);
322 String cadi_truststore = access.getProperty(Config.CADI_TRUSTSTORE);
323 if(cadi_truststore==null) {
326 for (File tsf : dot_aaf.listFiles()) {
327 name = tsf.getName();
328 if (name.contains("trust") &&
329 (name.endsWith(".jks") || name.endsWith(".p12"))) {
330 select = cons.readLine("Use %s for TrustStore? (y/n):",tsf.getName());
331 if("y".equalsIgnoreCase(select)) {
332 cadi_truststore=tsf.getCanonicalPath();
333 access.setProperty(Config.CADI_TRUSTSTORE, cadi_truststore);
334 addProp(Config.CADI_TRUSTSTORE, cadi_truststore);
340 if(cadi_truststore!=null) {
341 if(cadi_truststore.indexOf(File.separatorChar)<0) {
342 cadi_truststore=dot_aaf.getPath()+File.separator+cadi_truststore;
344 String cadi_truststore_password = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD);
345 if(cadi_truststore_password==null) {
346 cadi_truststore_password=AAFSSO.cons.readLine("cadi_truststore_password[%s]=","changeit");
347 cadi_truststore_password = access.encrypt(cadi_truststore_password);
348 access.setProperty(Config.CADI_TRUSTSTORE_PASSWORD, cadi_truststore_password);
349 addProp(Config.CADI_TRUSTSTORE_PASSWORD, cadi_truststore_password);
357 public void setLogDefault() {
358 this.setLogDefault(PropAccess.DEFAULT);
359 System.setOut(stdOutOrig);
362 public void setStdErrDefault() {
363 access.setLogLevel(PropAccess.DEFAULT);
364 System.setErr(stdErrOrig);
367 public void setLogDefault(Level level) {
369 access.setLogLevel(level);
371 System.setOut(stdOutOrig);
374 public boolean loginOnly() {
378 public void addProp(String key, String value) {
379 if(key==null || value==null) {
383 diskprops.setProperty(key, value);
386 public void writeFiles() throws IOException {
388 // Store Creds, if they work
389 if (diskprops != null) {
390 if (!dot_aaf.exists()) {
393 FileOutputStream fos = new FileOutputStream(sso);
395 diskprops.store(fos, "AAF Single Signon");
403 sso.setWritable(true, true);
408 public PropAccess access() {
412 public StringBuilder err() {
416 public String user() {
420 public String enc_pass() {
421 return encrypted_pass;
424 public boolean useX509() {
428 public void close() {
432 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
433 // nothing to do here.
439 private List<String> parseArgs(String[] args)
441 List<String> larg = new ArrayList<String>(args.length);
443 // Cover for bash's need to escape *.. (\\*)
444 // also, remove SSO if required
445 for (int i = 0; i < args.length; ++i) {
446 if ("\\*".equals(args[i])) {
450 if ("-logout".equalsIgnoreCase(args[i])) {
452 } else if ("-login".equalsIgnoreCase(args[i])) {
454 } else if ("-noexit".equalsIgnoreCase(args[i])) {
463 private void setReadonly(File file) {
464 file.setExecutable(false, false);
465 file.setWritable(false, false);
466 file.setReadable(false, false);
467 file.setReadable(true, true);
470 public boolean ok() {