Update project structure for aaf/cadi
[aaf/cadi.git] / core / src / main / java / org / onap / aaf / cadi / config / Config.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.cadi.config;\r
24 \r
25 import java.io.IOException;\r
26 import java.lang.reflect.Constructor;\r
27 import java.lang.reflect.Field;\r
28 import java.lang.reflect.Method;\r
29 import java.net.InetAddress;\r
30 import java.net.URI;\r
31 import java.net.UnknownHostException;\r
32 import java.security.NoSuchAlgorithmException;\r
33 import java.security.cert.CertificateException;\r
34 import java.util.ArrayList;\r
35 import java.util.List;\r
36 import java.util.Map.Entry;\r
37 \r
38 import org.onap.aaf.cadi.AbsUserCache;\r
39 import org.onap.aaf.cadi.Access;\r
40 import org.onap.aaf.cadi.CachingLur;\r
41 import org.onap.aaf.cadi.CadiException;\r
42 import org.onap.aaf.cadi.CredVal;\r
43 import org.onap.aaf.cadi.Locator;\r
44 import org.onap.aaf.cadi.Lur;\r
45 import org.onap.aaf.cadi.PropAccess;\r
46 import org.onap.aaf.cadi.Symm;\r
47 import org.onap.aaf.cadi.TrustChecker;\r
48 import org.onap.aaf.cadi.Access.Level;\r
49 import org.onap.aaf.cadi.lur.EpiLur;\r
50 import org.onap.aaf.cadi.lur.LocalLur;\r
51 import org.onap.aaf.cadi.lur.NullLur;\r
52 import org.onap.aaf.cadi.taf.HttpEpiTaf;\r
53 import org.onap.aaf.cadi.taf.HttpTaf;\r
54 import org.onap.aaf.cadi.taf.basic.BasicHttpTaf;\r
55 import org.onap.aaf.cadi.taf.cert.X509Taf;\r
56 import org.onap.aaf.cadi.taf.dos.DenialOfServiceTaf;\r
57 \r
58 import java.util.Properties;\r
59 import java.util.TimerTask;\r
60 \r
61 /**\r
62  * Create a Consistent Configuration mechanism, even when configuration styles are as vastly different as\r
63  * Properties vs JavaBeans vs FilterConfigs...\r
64  * \r
65  *\r
66  */\r
67 public class Config {\r
68 \r
69         private static final String HIDE_PASS = "***************";\r
70 \r
71         public static final String UTF_8 = "UTF-8";\r
72 \r
73         // Property Names associated with configurations.\r
74         // As of 1.0.2, these have had the dots removed so as to be compatible with JavaBean style\r
75         // configurations as well as property list style.\r
76         public static final String HOSTNAME = "hostname";\r
77         public static final String CADI_PROP_FILES = "cadi_prop_files"; // Additional Properties files (separate with ;)\r
78         public static final String CADI_LOGLEVEL = "cadi_loglevel";\r
79         public static final String CADI_LOGNAME = "cadi_logname";\r
80         public static final String CADI_KEYFILE = "cadi_keyfile";\r
81         public static final String CADI_KEYSTORE = "cadi_keystore";\r
82         public static final String CADI_KEYSTORE_PASSWORD = "cadi_keystore_password";\r
83         public static final String CADI_ALIAS = "cadi_alias";\r
84         public static final String CADI_LOGINPAGE_URL = "cadi_loginpage_url";\r
85 \r
86         public static final String CADI_KEY_PASSWORD = "cadi_key_password";\r
87         public static final String CADI_TRUSTSTORE = "cadi_truststore";\r
88         public static final String CADI_TRUSTSTORE_PASSWORD = "cadi_truststore_password";\r
89         public static final String CADI_X509_ISSUERS = "cadi_x509_issuers";\r
90         public static final String CADI_TRUST_MASKS="cadi_trust_masks";\r
91         public static final String CADI_TRUST_PERM="cadi_trust_perm"; //  IDs with this perm can utilize the "AS " user concept\r
92         public static final String CADI_PROTOCOLS = "cadi_protocols";\r
93         public static final String CADI_NOAUTHN = "cadi_noauthn";\r
94         public static final String CADI_LOC_LIST = "cadi_loc_list";\r
95         \r
96         public static final String CADI_USER_CHAIN_TAG = "cadi_user_chain";\r
97         public static final String CADI_USER_CHAIN = "USER_CHAIN";\r
98 \r
99         \r
100         \r
101         public static final String CSP_DOMAIN = "csp_domain";\r
102         public static final String CSP_HOSTNAME = "csp_hostname";\r
103         public static final String CSP_DEVL_LOCALHOST = "csp_devl_localhost";\r
104         public static final String CSP_USER_HEADER = "CSP_USER";\r
105         public static final String CSP_SYSTEMS_CONF = "CSPSystems.conf";\r
106     public static final String CSP_SYSTEMS_CONF_FILE = "csp_systems_conf_file";\r
107 \r
108 \r
109         public static final String TGUARD_ENV="tguard_env";\r
110         public static final String TGUARD_DOMAIN = "tguard_domain";\r
111         public static final String TGUARD_TIMEOUT = "tguard_timeout";\r
112         public static final String TGUARD_TIMEOUT_DEF = "5000";\r
113         public static final String TGUARD_CERTS = "tguard_certs"; // comma delimited SHA-256 finger prints\r
114 //      public static final String TGUARD_DEVL_LOCALHOST = "tguard_devl_localhost";\r
115 //      public static final String TGUARD_USER_HEADER = "TGUARD_USER";\r
116 \r
117         public static final String LOCALHOST_ALLOW = "localhost_allow";\r
118         public static final String LOCALHOST_DENY = "localhost_deny";\r
119         \r
120         public static final String BASIC_REALM = "basic_realm";  // what is sent to the client \r
121         public static final String BASIC_WARN = "basic_warn";  // Warning of insecure channel \r
122         public static final String USERS = "local_users";\r
123         public static final String GROUPS = "local_groups";\r
124         public static final String WRITE_TO = "local_writeto"; // dump RBAC to local file in Tomcat Style (some apps use)\r
125         \r
126         public static final String AAF_ENV = "aaf_env";\r
127         public static final String AAF_ROOT_NS = "aaf_root_ns";\r
128         public static final String AAF_ROOT_COMPANY = "aaf_root_company";\r
129         public static final String AAF_URL = "aaf_url"; //URL for AAF... Use to trigger AAF configuration\r
130         public static final String AAF_MECHID = "aaf_id";\r
131         public static final String AAF_MECHPASS = "aaf_password";\r
132         public static final String AAF_LUR_CLASS = "aaf_lur_class";\r
133         public static final String AAF_TAF_CLASS = "aaf_taf_class";\r
134         public static final String AAF_CONNECTOR_CLASS = "aaf_connector_class";\r
135         public static final String AAF_LOCATOR_CLASS = "aaf_locator_class";\r
136         public static final String AAF_CONN_TIMEOUT = "aaf_conn_timeout";\r
137         public static final String AAF_CONN_TIMEOUT_DEF = "3000";\r
138         public static final String AAF_READ_TIMEOUT = "aaf_timeout";\r
139         public static final String AAF_READ_TIMEOUT_DEF = "5000";\r
140         public static final String AAF_USER_EXPIRES = "aaf_user_expires";\r
141         public static final String AAF_USER_EXPIRES_DEF = "600000"; // Default is 10 mins\r
142         public static final String AAF_CLEAN_INTERVAL = "aaf_clean_interval";\r
143         public static final String AAF_CLEAN_INTERVAL_DEF = "30000"; // Default is 30 seconds\r
144         public static final String AAF_REFRESH_TRIGGER_COUNT = "aaf_refresh_trigger_count";\r
145         public static final String AAF_REFRESH_TRIGGER_COUNT_DEF = "3"; // Default is 10 mins\r
146         \r
147         public static final String AAF_HIGH_COUNT = "aaf_high_count";\r
148         public static final String AAF_HIGH_COUNT_DEF = "1000"; // Default is 1000 entries\r
149         public static final String AAF_PERM_MAP = "aaf_perm_map";\r
150         public static final String AAF_DEPLOYED_VERSION = "DEPLOYED_VERSION";\r
151         public static final String AAF_CERT_IDS = "aaf_cert_ids";\r
152         public static final String AAF_DEBUG_IDS = "aaf_debug_ids"; // comma delimited\r
153         \r
154         public static final String GW_URL = "gw_url";\r
155         public static final String CM_URL = "cm_url";\r
156         public static final String CM_TRUSTED_CAS = "cm_trusted_cas";\r
157 \r
158         public static final String PATHFILTER_URLPATTERN = "pathfilter_urlpattern";\r
159         public static final String PATHFILTER_STACK = "pathfilter_stack";\r
160         public static final String PATHFILTER_NS = "pathfilter_ns";\r
161         public static final String PATHFILTER_NOT_AUTHORIZED_MSG = "pathfilter_not_authorized_msg";\r
162 \r
163         public static final String AFT_DME2_TRUSTSTORE_PASSWORD = "AFT_DME2_TRUSTSTORE_PASSWORD";\r
164         public static final String AFT_DME2_TRUSTSTORE = "AFT_DME2_TRUSTSTORE";\r
165         public static final String AFT_DME2_KEYSTORE_PASSWORD = "AFT_DME2_KEYSTORE_PASSWORD";\r
166         public static final String AFT_DME2_KEY_PASSWORD = "AFT_DME2_KEY_PASSWORD";\r
167         public static final String AFT_DME2_KEYSTORE = "AFT_DME2_KEYSTORE";\r
168         public static final String AFT_DME2_SSL_TRUST_ALL = "AFT_DME2_SSL_TRUST_ALL";\r
169         public static final String AFT_DME2_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_SSL_INCLUDE_PROTOCOLS";\r
170 \r
171 \r
172         // DME2 Client.  First property must be set to "false", and the others set in order to use SSL Client\r
173         public static final String AFT_DME2_CLIENT_IGNORE_SSL_CONFIG="AFT_DME2_CLIENT_IGNORE_SSL_CONFIG";\r
174         public static final String AFT_DME2_CLIENT_KEYSTORE = "AFT_DME2_CLIENT_KEYSTORE";\r
175         public static final String AFT_DME2_CLIENT_KEYSTORE_PASSWORD = "AFT_DME2_CLIENT_KEYSTORE_PASSWORD";\r
176         public static final String AFT_DME2_CLIENT_TRUSTSTORE = "AFT_DME2_CLIENT_TRUSTSTORE";\r
177         public static final String AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD = "AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD";\r
178         public static final String AFT_DME2_CLIENT_SSL_CERT_ALIAS = "AFT_DME2_CLIENT_SSL_CERT_ALIAS"; \r
179         public static final String AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS = "AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS";\r
180 \r
181         \r
182         // This one should go unpublic\r
183         public static final String AAF_DEFAULT_REALM = "aaf_default_realm";\r
184         private static String defaultRealm="none";\r
185 \r
186         public static final String AAF_DOMAIN_SUPPORT = "aaf_domain_support";\r
187         //public static final String AAF_DOMAIN_SUPPORT_DEF = ".com";\r
188         public static final String AAF_DOMAIN_SUPPORT_DEF = ".org";\r
189 \r
190 \r
191         public static void setDefaultRealm(Access access) throws CadiException {\r
192                 try {\r
193                         boolean hasCSP;\r
194                         try {\r
195                                 Class.forName("com.att.cadi.taf.csp.CSPTaf");\r
196                                 hasCSP=true;\r
197                         } catch(ClassNotFoundException e) {\r
198                                 hasCSP = logProp(access,Config.CSP_DOMAIN, null)!=null;\r
199                         }\r
200                         defaultRealm = logProp(access,Config.AAF_DEFAULT_REALM,\r
201                                         hasCSP?"csp.att.com":\r
202                                         logProp(access,Config.BASIC_REALM,\r
203                                                 logProp(access,HOSTNAME,InetAddress.getLocalHost().getHostName())\r
204                                                 )\r
205                                         );\r
206                 } catch (UnknownHostException e) {\r
207                         //defaultRealm="none";\r
208                 }\r
209         }\r
210         \r
211 \r
212         public static HttpTaf configHttpTaf(Access access, TrustChecker tc, CredVal up, Lur lur, Object ... additionalTafLurs) throws CadiException {\r
213                 /////////////////////////////////////////////////////\r
214                 // Setup AAFCon for any following\r
215                 /////////////////////////////////////////////////////\r
216                 Object aafcon = null;\r
217                 if(lur != null) {\r
218                         Field f = null;\r
219                         try {\r
220                                 f = lur.getClass().getField("aaf");\r
221                                 aafcon = f.get(lur);\r
222                         } catch (Exception nsfe) {\r
223                         }\r
224                 }\r
225                 // IMPORTANT!  Don't attempt to load AAF Connector if there is no AAF URL\r
226                 String aafURL = access.getProperty(AAF_URL,null);\r
227                 if(aafcon==null && aafURL!=null) {\r
228                         aafcon = loadAAFConnector(access, aafURL);      \r
229                 }\r
230                 \r
231                 HttpTaf taf;\r
232                 // Setup Host, in case Network reports an unusable Hostname (i.e. VTiers, VPNs, etc)\r
233                 String hostname = logProp(access, HOSTNAME,null);\r
234                 if(hostname==null) {\r
235                         try {\r
236                                 hostname = InetAddress.getLocalHost().getHostName();\r
237                         } catch (UnknownHostException e1) {\r
238                                 throw new CadiException("Unable to determine Hostname",e1);\r
239                         }\r
240                 }\r
241                 \r
242                 access.log(Level.INIT, "Hostname set to",hostname);\r
243                 // Get appropriate TAFs\r
244                 ArrayList<HttpTaf> htlist = new ArrayList<HttpTaf>();\r
245 \r
246                 /////////////////////////////////////////////////////\r
247                 // Add a Denial of Service TAF\r
248                 // Note: how IPs and IDs are added are up to service type.\r
249                 // They call "DenialOfServiceTaf.denyIP(String) or denyID(String)\r
250                 /////////////////////////////////////////////////////\r
251                 htlist.add(new DenialOfServiceTaf(access));\r
252 \r
253                 /////////////////////////////////////////////////////\r
254                 // Configure LocalHost \r
255                 /////////////////////////////////////////////////////\r
256                 \r
257                 String truststore = logProp(access, CADI_TRUSTSTORE, access.getProperty("AFT_DME2_TRUSTSTORE", null));\r
258                 if(truststore!=null) {\r
259                         String truststore_pwd = access.getProperty(CADI_TRUSTSTORE_PASSWORD, access.getProperty("AFT_DME2_TRUSTSTORE_PASSWORD",null));\r
260                         if(truststore_pwd!=null) {\r
261                                 if(truststore_pwd.startsWith(Symm.ENC)) {\r
262                                         try {\r
263                                                 truststore_pwd = access.decrypt(truststore_pwd,false);\r
264                                         } catch (IOException e) {\r
265                                                 throw new CadiException(CADI_TRUSTSTORE_PASSWORD + " cannot be decrypted",e);\r
266                                         }\r
267                                 }\r
268                                 try {\r
269                                         htlist.add(new X509Taf(access,lur));\r
270                                         access.log(Level.INIT,"Certificate Authorization enabled");\r
271                                 } catch (SecurityException e) {\r
272                                         access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);\r
273                                 } catch (IllegalArgumentException e) {\r
274                                         access.log(Level.INIT,"AAFListedCertIdentity cannot be instantiated. Certificate Authorization is now disabled",e);\r
275                                 } catch (CertificateException e) {\r
276                                         access.log(Level.INIT,"Certificate Authorization failed, it is disabled",e);\r
277                                 } catch (NoSuchAlgorithmException e) {\r
278                                         access.log(Level.INIT,"Certificate Authorization failed, wrong Security Algorithm",e);\r
279                                 }\r
280                         }\r
281                 } else {\r
282                         access.log(Level.INIT,"Certificate Authorization not enabled");\r
283                 }\r
284                 \r
285                 /////////////////////////////////////////////////////\r
286                 // Configure Basic Auth (local content)\r
287                 /////////////////////////////////////////////////////\r
288                 String basic_realm = logProp(access, BASIC_REALM,null);\r
289                 boolean basic_warn = "TRUE".equals(access.getProperty(BASIC_WARN,"FALSE"));\r
290                 if(basic_realm!=null && up!=null) {\r
291                         access.log(Level.INIT,"Basic Authorization is enabled using realm",basic_realm);\r
292                         // Allow warning about insecure channel to be turned off\r
293                         if(!basic_warn)access.log(Level.INIT,"WARNING! The basic_warn property has been set to false.",\r
294                                         " There will be no additional warning if Basic Auth is used on an insecure channel"\r
295                                         );\r
296                         String aafCleanup = logProp(access, AAF_USER_EXPIRES,AAF_USER_EXPIRES_DEF); // Default is 10 mins\r
297                         long userExp = Long.parseLong(aafCleanup);\r
298 \r
299                         htlist.add(new BasicHttpTaf(access, up, basic_realm, userExp, basic_warn));\r
300                 } else {\r
301                         access.log(Level.INIT,"Local Basic Authorization is disabled.  Enable by setting basic_realm=<appropriate realm, i.e. my.att.com>");\r
302                 }\r
303                 \r
304                 /////////////////////////////////////////////////////\r
305                 // Configure AAF Driven Basic Auth\r
306                 /////////////////////////////////////////////////////\r
307                 boolean getRemoteAAF = true;\r
308                 if(additionalTafLurs!=null) {\r
309                         for(Object o : additionalTafLurs) {\r
310                                 if(o.getClass().getSimpleName().equals("DirectAAFLur")) {\r
311                                         getRemoteAAF = false;\r
312                                         break;\r
313                                 }\r
314                         }\r
315                 }\r
316                 HttpTaf aaftaf=null;\r
317                 if(getRemoteAAF) {\r
318                         if(aafcon==null) {\r
319                                 access.log(Level.INIT,"AAF Connection (AAFcon) is null.  Cannot create an AAF TAF");\r
320                         } else if(aafURL==null) {\r
321                                 access.log(Level.INIT,"No AAF URL in properties, Cannot create an AAF TAF");\r
322                         } else {// There's an AAF_URL... try to configure an AAF \r
323                                 String defName = aafURL.contains("version=2.0")?"com.att.cadi.aaf.v2_0.AAFTaf":"";\r
324                                 String aafTafClassName = logProp(access, AAF_TAF_CLASS,defName);\r
325                                 // Only 2.0 available at this time\r
326                                 if("com.att.cadi.aaf.v2_0.AAFTaf".equals(aafTafClassName)) { \r
327                                         try {\r
328                                                 Class<?> aafTafClass = loadClass(access,aafTafClassName);\r
329                                                 Class<?> aafConClass = loadClass(access,"com.att.cadi.aaf.v2_0.AAFCon");\r
330         \r
331                                                 Constructor<?> cstr = aafTafClass.getConstructor(aafConClass,boolean.class,AbsUserCache.class);\r
332                                                 if(cstr!=null) {\r
333                                                         aaftaf = (HttpTaf)cstr.newInstance(aafcon,basic_warn,lur);\r
334                                                         if(aaftaf==null) {\r
335                                                                 access.log(Level.INIT,"ERROR! AAF TAF Failed construction.  NOT Configured");\r
336                                                         } else {\r
337                                                                 access.log(Level.INIT,"AAF TAF Configured to ",aafURL);\r
338                                                                 // Note: will add later, after all others configured\r
339                                                         }\r
340                                                 }\r
341                                         } catch(Exception e) {\r
342                                                 access.log(Level.INIT,"ERROR! AAF TAF Failed construction.  NOT Configured");\r
343                                         }\r
344                                 }\r
345                         }\r
346                 }\r
347                 \r
348                 \r
349                 String alias = logProp(access, CADI_ALIAS,null);\r
350 \r
351                 /////////////////////////////////////////////////////\r
352                 // Configure tGuard... (AT&T Client Repo)\r
353                 /////////////////////////////////////////////////////\r
354                 // TGUARD Environment, translated to any other remote Environment validation mechanism...\r
355                 String tGuard_domain = logProp(access, TGUARD_DOMAIN,null);\r
356                 String tGuard_env = logProp(access, TGUARD_ENV, null);\r
357 \r
358                 if(!("PROD".equals(tGuard_env) || "STAGE".equals(tGuard_env))) {\r
359                         access.log(Level.INIT, "tGuard Authorization is disabled.  Enable by setting", TGUARD_ENV, "to \"PROD\" or \"STAGE\"");\r
360                 } else if(tGuard_domain==null) {\r
361                         access.log(Level.INIT,TGUARD_DOMAIN + " must be set:  tGuard Authorization is disabled.");\r
362                 } else if(alias == null) {\r
363                         access.log(Level.INIT,CADI_ALIAS + " must be set:  tGuard Authorization is disabled.");\r
364                 } else {\r
365                         try {\r
366                                 Class<?> tGuardClass = loadClass(access,"com.att.cadi.tguard.TGuardHttpTaf");\r
367                                 if(aaftaf!=null) {\r
368                                         Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, AbsUserCache.class});\r
369                                         htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {access,aaftaf}));\r
370                                         access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");\r
371                                 } else {\r
372                                         Constructor<?> tGuardCnst = tGuardClass.getConstructor(new Class[]{Access.class, int.class, int.class, int.class});\r
373                                         htlist.add((HttpTaf)tGuardCnst.newInstance(new Object[] {\r
374                                                         access,\r
375                                                         Integer.parseInt(logProp(access, AAF_CLEAN_INTERVAL,AAF_CLEAN_INTERVAL_DEF)),\r
376                                                         Integer.parseInt(logProp(access, AAF_HIGH_COUNT, AAF_HIGH_COUNT_DEF)),\r
377                                                         Integer.parseInt(logProp(access, AAF_REFRESH_TRIGGER_COUNT, AAF_REFRESH_TRIGGER_COUNT_DEF))\r
378                                                         }));\r
379                                         access.log(Level.INIT,"tGuard Authorization is enabled on",tGuard_env,"on the",tGuard_domain," tGuard Domain");\r
380                                 }\r
381                         } catch(Exception e) {\r
382                                 access.log(e, Level.INIT,"tGuard Class cannot be loaded:  tGuard Authorization is disabled.");\r
383                         }\r
384                 }\r
385                 \r
386                 /////////////////////////////////////////////////////\r
387                 // Adding BasicAuth (AAF) last, after other primary Cookie Based\r
388                 // Needs to be before Cert... see below\r
389                 /////////////////////////////////////////////////////\r
390                 if(aaftaf!=null) {\r
391                         htlist.add(aaftaf);\r
392                 }\r
393 \r
394 \r
395                 /////////////////////////////////////////////////////\r
396                 // Any Additional Lurs passed in Constructor\r
397                 /////////////////////////////////////////////////////\r
398                 if(additionalTafLurs!=null) {\r
399                         for(Object additional : additionalTafLurs) {\r
400                                 if(additional instanceof HttpTaf) {\r
401                                         htlist.add((HttpTaf)additional);\r
402                                         access.log(Level.INIT,additional);\r
403                                 }\r
404                         }\r
405                 }\r
406 \r
407                 /////////////////////////////////////////////////////\r
408                 // Create EpiTaf from configured TAFs\r
409                 /////////////////////////////////////////////////////\r
410                 if(htlist.size()==1) {\r
411                         // just return the one\r
412                         taf = htlist.get(0);\r
413                 } else {\r
414                         HttpTaf[] htarray = new HttpTaf[htlist.size()];\r
415                         htlist.toArray(htarray);\r
416                         Locator<URI> locator = loadLocator(access, logProp(access, CADI_LOGINPAGE_URL, null));\r
417                         \r
418                         taf = new HttpEpiTaf(access,locator, tc, htarray); // ok to pass locator == null\r
419                         String level = logProp(access, CADI_LOGLEVEL, null);\r
420                         if(level!=null) {\r
421                                 access.setLogLevel(Level.valueOf(level));\r
422                         }\r
423                 }\r
424                 \r
425                 return taf;\r
426         }\r
427         \r
428         public static String logProp(Access access,String tag, String def) {\r
429                 String rv = access.getProperty(tag, def);\r
430                 if(rv == null) {\r
431                         access.log(Level.INIT,tag,"is not set");\r
432                 } else {\r
433                         access.log(Level.INIT,tag,"is set to",rv);\r
434                 }\r
435                 return rv;\r
436         }\r
437         \r
438         public static Lur configLur(Access access, Object ... additionalTafLurs) throws CadiException {\r
439                 List<Lur> lurs = new ArrayList<Lur>();\r
440                 \r
441                 /////////////////////////////////////////////////////\r
442                 // Configure a Local Property Based RBAC/LUR\r
443                 /////////////////////////////////////////////////////\r
444                 try {\r
445                         String users = access.getProperty(USERS,null);\r
446                         String groups = access.getProperty(GROUPS,null);\r
447 \r
448                         if(groups!=null || users!=null) {\r
449                                 LocalLur ll;\r
450                                 lurs.add(ll = new LocalLur(access, users, groups)); // note b64==null is ok.. just means no encryption.\r
451                                 \r
452                                 String writeto = access.getProperty(WRITE_TO,null);\r
453                                 if(writeto!=null) {\r
454                                         String msg = UsersDump.updateUsers(writeto, ll);\r
455                                         if(msg!=null) access.log(Level.INIT,"ERROR! Error Updating ",writeto,"with roles and users:",msg);\r
456                                 }\r
457                         }\r
458                 } catch (IOException e) {\r
459                         throw new CadiException(e);\r
460                 }\r
461                 \r
462                 /////////////////////////////////////////////////////\r
463                 // Configure the AAF Lur (if any)\r
464                 /////////////////////////////////////////////////////\r
465                 String aafURL = logProp(access,AAF_URL,null); // Trigger Property\r
466                 String aaf_env = access.getProperty(AAF_ENV,null);\r
467                 if(aaf_env == null && aafURL!=null && access instanceof PropAccess) { // set AAF_ENV from AAF_URL\r
468                         int ec = aafURL.indexOf("envContext=");\r
469                         if(ec>0) {\r
470                                 ec += 11; // length of envContext=\r
471                                 int slash = aafURL.indexOf('/', ec);\r
472                                 if(slash>0) {\r
473                                         aaf_env = aafURL.substring(ec, slash);\r
474                                         ((PropAccess)access).setProperty(AAF_ENV, aaf_env);\r
475                                         access.printf(Level.INIT, "Setting aaf_env to %s from aaf_url value",aaf_env);\r
476                                 }\r
477                         }\r
478                 }\r
479                         \r
480                 if(aafURL==null) {\r
481                         access.log(Level.INIT,"No AAF LUR properties, AAF will not be loaded");\r
482                 } else {// There's an AAF_URL... try to configure an AAF\r
483                         String aafLurClassStr = logProp(access,AAF_LUR_CLASS,"com.att.cadi.aaf.v2_0.AAFLurPerm");\r
484                         ////////////AAF Lur 2.0 /////////////\r
485                         if(aafLurClassStr.startsWith("com.att.cadi.aaf.v2_0")) { \r
486                                 try {\r
487                                         Object aafcon = loadAAFConnector(access, aafURL);\r
488                                         if(aafcon==null) {\r
489                                                 access.log(Level.INIT,"AAF LUR class,",aafLurClassStr,"cannot be constructed without valid AAFCon object.");\r
490                                         } else {\r
491                                                 Class<?> aafAbsAAFCon = loadClass(access, "com.att.cadi.aaf.v2_0.AAFCon");\r
492                                                 Method mNewLur = aafAbsAAFCon.getMethod("newLur");\r
493                                                 Object aaflur = mNewLur.invoke(aafcon);\r
494         \r
495                                                 if(aaflur==null) {\r
496                                                         access.log(Level.INIT,"ERROR! AAF LUR Failed construction.  NOT Configured");\r
497                                                 } else {\r
498                                                         access.log(Level.INIT,"AAF LUR Configured to ",aafURL);\r
499                                                         lurs.add((Lur)aaflur);\r
500                                                         String debugIDs = logProp(access,Config.AAF_DEBUG_IDS, null);\r
501                                                         if(debugIDs !=null && aaflur instanceof CachingLur) {\r
502                                                                 ((CachingLur<?>)aaflur).setDebug(debugIDs);\r
503                                                         }\r
504                                                 }\r
505                                         }\r
506                                 } catch (Exception e) {\r
507                                         access.log(e,"AAF LUR class,",aafLurClassStr,"could not be constructed with given Constructors.");\r
508                                 }\r
509                         } \r
510                 } \r
511 \r
512                 /////////////////////////////////////////////////////\r
513                 // Any Additional passed in Constructor\r
514                 /////////////////////////////////////////////////////\r
515                 if(additionalTafLurs!=null) {\r
516                         for(Object additional : additionalTafLurs) {\r
517                                 if(additional instanceof Lur) {\r
518                                         lurs.add((Lur)additional);\r
519                                         access.log(Level.INIT, additional);\r
520                                 }\r
521                         }\r
522                 }\r
523 \r
524                 /////////////////////////////////////////////////////\r
525                 // Return a Lur based on how many there are... \r
526                 /////////////////////////////////////////////////////\r
527                 switch(lurs.size()) {\r
528                         case 0: \r
529                                 access.log(Level.INIT,"WARNING! No CADI LURs configured");\r
530                                 // Return a NULL Lur that does nothing.\r
531                                 return new NullLur();\r
532                         case 1:\r
533                                 return lurs.get(0); // Only one, just return it, save processing\r
534                         default:\r
535                                 // Multiple Lurs, use EpiLUR to handle\r
536                                 Lur[] la = new Lur[lurs.size()];\r
537                                 lurs.toArray(la);\r
538                                 return new EpiLur(la);\r
539                 }\r
540         }\r
541         \r
542         private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2 = "com.att.cadi.aaf.v2_0.AAFConDME2";\r
543         private static final String COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP = "com.att.cadi.aaf.v2_0.AAFConHttp";\r
544         public static Object loadAAFConnector(Access access, String aafURL) {\r
545                 Object aafcon = null;\r
546                 Class<?> aafConClass = null;\r
547 \r
548                 try {\r
549                         if(aafURL!=null) {\r
550                                 String aafConnector = access.getProperty(AAF_CONNECTOR_CLASS, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);\r
551                                 if(COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2.equals(aafConnector) || aafURL.contains("/service=")) {\r
552                                         aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_DME2);\r
553                                         if(aafConClass!=null) {\r
554                                                 Constructor<?> cons = aafConClass.getConstructor(PropAccess.class);\r
555                                                 aafcon = cons.newInstance(access);\r
556                                         } else {\r
557                                                 access.log(Level.ERROR, "URL contains '/service=', which requires DME2");\r
558                                         }\r
559                                 } else if(COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP.equals(aafConnector)) {\r
560                                         aafConClass = loadClass(access, COM_ATT_CADI_AAF_V2_0_AAF_CON_HTTP);\r
561                                         for(Constructor<?> c : aafConClass.getConstructors()) {\r
562                                                 List<Object> lo = new ArrayList<Object>();\r
563                                                 for(Class<?> pc : c.getParameterTypes()) {\r
564                                                         if(pc.equals(PropAccess.class)) {\r
565                                                                 lo.add(access);\r
566                                                         } else if(pc.equals(Locator.class)) {\r
567                                                                 lo.add(loadLocator(access, aafURL));\r
568                                                         } else {\r
569                                                                 continue;\r
570                                                         }\r
571                                                 }\r
572                                                 if(c.getParameterTypes().length!=lo.size()) {\r
573                                                         continue; // back to another Constructor\r
574                                                 } else {\r
575                                                         aafcon = c.newInstance(lo.toArray());\r
576                                                 }\r
577                                                 break;\r
578                                         }\r
579                                 }\r
580                                 if(aafcon!=null) {\r
581                                         String mechid = logProp(access,Config.AAF_MECHID, null);\r
582                                         String pass = access.getProperty(Config.AAF_MECHPASS, null);\r
583                                         if(mechid!=null && pass!=null) {\r
584                                                 try {\r
585                                                         Method basicAuth = aafConClass.getMethod("basicAuth", String.class, String.class);\r
586                                                         basicAuth.invoke(aafcon, mechid,pass);\r
587                                                 } catch (NoSuchMethodException nsme) {\r
588                                                         // it's ok, don't use\r
589                                                 }\r
590                                         }\r
591                                 }\r
592                         }\r
593                 } catch (Exception e) {\r
594                         access.log(e,"AAF Connector could not be constructed with given Constructors.");\r
595                 }\r
596                 \r
597                 return aafcon;\r
598         }\r
599 \r
600         public static Class<?> loadClass(Access access, String className) {\r
601                 Class<?> cls=null;\r
602                 try {\r
603                         cls = access.classLoader().loadClass(className);\r
604                 } catch (ClassNotFoundException cnfe) {\r
605                         try {\r
606                                 cls = access.getClass().getClassLoader().loadClass(className);\r
607                         } catch (ClassNotFoundException cnfe2) {\r
608                                 // just return null\r
609                         }\r
610                 }\r
611                 return cls;\r
612         }\r
613 \r
614         @SuppressWarnings("unchecked")\r
615         public static Locator<URI> loadLocator(Access access, String url) {\r
616                 Locator<URI> locator = null;\r
617                 if(url==null) {\r
618                         access.log(Level.INIT,"No URL for AAF Login Page. Disabled");\r
619                 } else {\r
620                         if(url.contains("DME2RESOLVE")) {\r
621                                 try {\r
622                                         Class<?> lcls = loadClass(access,"com.att.cadi.locator.DME2Locator");\r
623                                         Class<?> dmcls = loadClass(access,"com.att.aft.dme2.api.DME2Manager");\r
624                                         Constructor<?> cnst = lcls.getConstructor(new Class[] {Access.class,dmcls,String.class});\r
625                                         locator = (Locator<URI>)cnst.newInstance(new Object[] {access,null,url});\r
626                                         access.log(Level.INFO, "DME2Locator enabled with " + url);\r
627                                 } catch (Exception e) {\r
628                                         access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires DME2. It is now disabled",e);\r
629                                 }\r
630                         } else {\r
631                                 try {\r
632                                         Class<?> cls = loadClass(access,"com.att.cadi.locator.PropertyLocator");\r
633                                         Constructor<?> cnst = cls.getConstructor(new Class[] {String.class});\r
634                                         locator = (Locator<URI>)cnst.newInstance(new Object[] {url});\r
635                                         access.log(Level.INFO, "PropertyLocator enabled with " + url);\r
636                                 } catch (Exception e) {\r
637                                         access.log(Level.INIT,"AAF Login Page accessed by " + url + " requires PropertyLocator. It is now disabled",e);\r
638                                 }\r
639                         }\r
640                 }\r
641                 return locator;\r
642         }\r
643 \r
644         /*\r
645          * DME2 can only read Passwords as clear text properties.  Leaving in "System Properties" un-encrypted exposes these passwords\r
646          */\r
647         public static class PasswordRemoval extends TimerTask {\r
648                 private Access access;\r
649                 \r
650                 private final List<String> pws;\r
651 \r
652                 public PasswordRemoval(Access access) {\r
653                         this.access = access;\r
654                         pws = new ArrayList<String>();\r
655                 }\r
656                 \r
657                 @Override\r
658                 public void run() {\r
659                         for(String key:pws) {\r
660                                 access.log(Level.INIT, "Scrubbing " + key);\r
661                                 System.clearProperty(key);\r
662                         }\r
663                 }               \r
664                 public void add(String key) {\r
665                         pws.add(key);\r
666                 }\r
667         }\r
668 \r
669         private static final String Y = "Y";\r
670 \r
671         private static String[][] CONVERTER_STRINGS=new String[][] {\r
672                         {AFT_DME2_KEYSTORE,CADI_KEYSTORE,null},\r
673                         {AFT_DME2_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},\r
674                         {AFT_DME2_KEY_PASSWORD,CADI_KEY_PASSWORD,null},\r
675                         {AFT_DME2_TRUSTSTORE,CADI_TRUSTSTORE,null},\r
676                         {AFT_DME2_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},\r
677                         {AFT_DME2_CLIENT_KEYSTORE,CADI_KEYSTORE,null},\r
678                         {AFT_DME2_CLIENT_KEYSTORE_PASSWORD,CADI_KEYSTORE_PASSWORD,null},\r
679                         {AFT_DME2_CLIENT_TRUSTSTORE,CADI_TRUSTSTORE,null},\r
680                         {AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD,CADI_TRUSTSTORE_PASSWORD,null},\r
681                         {AFT_DME2_CLIENT_SSL_CERT_ALIAS,CADI_ALIAS,null},\r
682                         {AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},\r
683                         {"AFT_DME2_HOSTNAME",HOSTNAME,null},\r
684                         {"AFT_LATITUDE",null,Y},\r
685                         {"AFT_LONGITUDE",null,Y},\r
686                         {"AFT_ENVIRONMENT",null,Y},\r
687                         {"SCLD_PLATFORM",null,Y},\r
688                         {"DME2_EP_REGISTRY_CLASS",null,Y},// for Developer local access\r
689                         {"AFT_DME2_EP_REGISTRY_FS_DIR",null,Y},\r
690                         {"DME2.DEBUG",null,null},\r
691                         {"AFT_DME2_HTTP_EXCHANGE_TRACE_ON",null,null},\r
692                         {"AFT_DME2_SSL_ENABLE",null,null},\r
693                         {"AFT_DME2_SSL_WANT_CLIENT_AUTH",null,null},\r
694                         {AFT_DME2_SSL_INCLUDE_PROTOCOLS,CADI_PROTOCOLS,null},\r
695                         {"AFT_DME2_SSL_VALIDATE_CERTS",null,null},\r
696                         {AFT_DME2_CLIENT_IGNORE_SSL_CONFIG,null,null},\r
697                         {"https.protocols",CADI_PROTOCOLS,Y},\r
698                         };\r
699 \r
700 \r
701 \r
702         public static Properties getDME2Props(PropAccess access) {\r
703                 Properties dprops = new Properties();\r
704                 String value = null;\r
705                 boolean reqClientConfig = false;\r
706                 for(String[] row : CONVERTER_STRINGS) {\r
707                         value = access.getProperty(row[0],null);\r
708                         if(value==null) {\r
709                                 value = System.getProperty(row[0]);\r
710                                 if(value==null && row[1]!=null) {\r
711                                         value = access.getProperty(row[1],null);\r
712                                         if(value == null) {\r
713                                                 value = System.getProperty(row[1]);\r
714                                         }\r
715                                 }\r
716                         }\r
717                         if(value!=null) {\r
718                                 if(row[0].contains("_SSL_")) {\r
719                                         reqClientConfig = true;\r
720                                 }\r
721                                 if(row[0].startsWith("AFT") || row[0].startsWith("SCLD") || row[0].contains("DME2")) {\r
722                                         if(value.startsWith("enc:")) {\r
723                                                 try {\r
724                                                         value = access.decrypt(value, true);\r
725                                                 } catch (IOException e) {\r
726                                                         access.log(Level.ERROR, e);\r
727                                                 }\r
728                                                 System.setProperty(row[0], value);\r
729                                         } else if(Y.equals(row[2])) {\r
730                                                 System.setProperty(row[0], value);\r
731                                                 dprops.setProperty(row[0], value);\r
732                                         } else if(row[0].contains("PASSWORD") || row[0].contains("STORE")) {\r
733                                                 System.setProperty(row[0], value);\r
734                                         } else {\r
735                                                 dprops.setProperty(row[0], value);\r
736                                         }\r
737                                 }\r
738                                 \r
739                         }\r
740                         \r
741                 }\r
742                 \r
743                 Properties sprops = System.getProperties();\r
744                 if(reqClientConfig && sprops.getProperty(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG)==null) {\r
745                         sprops.put(AFT_DME2_CLIENT_IGNORE_SSL_CONFIG, "false");\r
746                         replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE,AFT_DME2_TRUSTSTORE);\r
747                         replaceKeyWithTrust(sprops,AFT_DME2_KEYSTORE_PASSWORD,AFT_DME2_TRUSTSTORE_PASSWORD);\r
748                         replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE,AFT_DME2_CLIENT_TRUSTSTORE);\r
749                         replaceKeyWithTrust(sprops,AFT_DME2_CLIENT_KEYSTORE_PASSWORD,AFT_DME2_CLIENT_TRUSTSTORE_PASSWORD);\r
750                 }\r
751                 \r
752                 if(sprops.getProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS)==null) {\r
753                         sprops.setProperty(AFT_DME2_CLIENT_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));\r
754                 }\r
755 \r
756                 if(sprops.getProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS)==null) {\r
757                         sprops.setProperty(AFT_DME2_SSL_INCLUDE_PROTOCOLS, access.getProperty(CADI_PROTOCOLS,SecurityInfo.HTTPS_PROTOCOLS_DEFAULT));\r
758                 }\r
759                 \r
760                 if(access.willLog(Level.DEBUG)) {\r
761                         if(access instanceof PropAccess) {\r
762                                 access.log(Level.DEBUG,"Access Properties");\r
763                                 for(Entry<Object, Object> es : ((PropAccess)access).getProperties().entrySet()) {\r
764                                         access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),es.getValue().toString());\r
765                                 }\r
766                         }\r
767                         access.log(Level.DEBUG,"DME2 Properties()");\r
768                         for(Entry<Object, Object> es : dprops.entrySet()) {\r
769                                 value = es.getValue().toString();\r
770                                 if(es.getKey().toString().contains("PASS")) {\r
771                                         if(value==null || !value.contains("enc:")) {\r
772                                                 value = HIDE_PASS;\r
773                                         }\r
774                                 }\r
775                                 access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),value);\r
776                         }\r
777                         \r
778                         access.log(Level.DEBUG,"System (AFT) Properties");\r
779                         for(Entry<Object, Object> es : System.getProperties().entrySet()) {\r
780                                 if(es.getKey().toString().startsWith("AFT")) {\r
781                                         value = es.getValue().toString();\r
782                                         if(es.getKey().toString().contains("PASS")) {\r
783                                                 if(value==null || !value.contains("enc:")) {\r
784                                                         value = HIDE_PASS;\r
785                                                 }\r
786                                         }\r
787                                         access.printf(Level.DEBUG,"    %s=%s",es.getKey().toString(),value);\r
788                                 }\r
789                         }\r
790                 }\r
791                 // Cover any not specific AFT props\r
792                 String key;\r
793                 for(Entry<Object, Object> es : access.getProperties().entrySet()) {\r
794                         if((key=es.getKey().toString()).startsWith("AFT_") && \r
795                                         !key.contains("PASSWORD") &&\r
796                                         dprops.get(key)==null) {\r
797                                 dprops.put(key, es.getValue());\r
798                         }\r
799                 }\r
800                 return dprops;\r
801         }\r
802         \r
803         private static void replaceKeyWithTrust(Properties props, String ks, String ts) {\r
804                 String value;\r
805                 if(props.get(ks)==null && (value=props.getProperty(ts))!=null) {\r
806                         props.put(ks,value);\r
807                         props.remove(ts);\r
808                 }\r
809         }\r
810         // Set by CSP, or is hostname.\r
811         public static String getDefaultRealm() {\r
812                 return defaultRealm;\r
813         }\r
814 \r
815 }\r