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