Update AAF Version 1.0.0
[aaf/cadi.git] / aaf / src / main / java / com / att / cadi / aaf / v2_0 / AAFCon.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.aaf.v2_0;\r
24 \r
25 import java.net.URI;\r
26 import java.security.Principal;\r
27 import java.util.Map;\r
28 import java.util.concurrent.ConcurrentHashMap;\r
29 \r
30 import javax.servlet.ServletRequest;\r
31 import javax.servlet.http.HttpServletRequest;\r
32 \r
33 import com.att.cadi.AbsUserCache;\r
34 import com.att.cadi.CadiException;\r
35 import com.att.cadi.CadiWrap;\r
36 import com.att.cadi.Connector;\r
37 import com.att.cadi.LocatorException;\r
38 import com.att.cadi.Lur;\r
39 import com.att.cadi.PropAccess;\r
40 import com.att.cadi.SecuritySetter;\r
41 import com.att.cadi.aaf.AAFPermission;\r
42 import com.att.cadi.aaf.marshal.CertsMarshal;\r
43 import com.att.cadi.client.AbsBasicAuth;\r
44 import com.att.cadi.client.Future;\r
45 import com.att.cadi.client.Rcli;\r
46 import com.att.cadi.client.Retryable;\r
47 import com.att.cadi.config.Config;\r
48 import com.att.cadi.config.SecurityInfoC;\r
49 import com.att.cadi.lur.EpiLur;\r
50 import com.att.cadi.principal.BasicPrincipal;\r
51 import com.att.cadi.util.Vars;\r
52 import com.att.inno.env.APIException;\r
53 import com.att.inno.env.Data.TYPE;\r
54 import com.att.inno.env.util.Split;\r
55 import com.att.rosetta.env.RosettaDF;\r
56 import com.att.rosetta.env.RosettaEnv;\r
57 \r
58 import aaf.v2_0.Certs;\r
59 import aaf.v2_0.Error;\r
60 import aaf.v2_0.Perms;\r
61 import aaf.v2_0.Users;\r
62 \r
63 public abstract class AAFCon<CLIENT> implements Connector {\r
64         public static final String AAF_LATEST_VERSION = "2.0";\r
65 \r
66         final public PropAccess access;\r
67         // Package access\r
68         final public int timeout, cleanInterval, connTimeout;\r
69         final public int highCount, userExpires, usageRefreshTriggerCount;\r
70         private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();\r
71         final public RosettaDF<Perms> permsDF;\r
72         final public RosettaDF<Certs> certsDF;\r
73         final public RosettaDF<Users> usersDF;\r
74         final public RosettaDF<Error> errDF;\r
75         private String realm;\r
76         public final String app;\r
77         protected SecuritySetter<CLIENT> ss;\r
78         protected SecurityInfoC<CLIENT> si;\r
79 \r
80         private DisableCheck disableCheck;\r
81 \r
82         private AAFLurPerm lur;\r
83 \r
84         private RosettaEnv env;\r
85         protected abstract URI initURI();\r
86         protected abstract void setInitURI(String uriString) throws CadiException;\r
87 \r
88         /**\r
89          * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)\r
90          * \r
91          * @param apiVersion\r
92          * @return\r
93          * @throws CadiException\r
94          */\r
95         public Rcli<CLIENT> client(String apiVersion) throws CadiException {\r
96                 Rcli<CLIENT> client = clients.get(apiVersion);\r
97                 if(client==null) {\r
98                         client = rclient(initURI(),ss);\r
99                         client.apiVersion(apiVersion)\r
100                                   .readTimeout(connTimeout);\r
101                         clients.put(apiVersion, client);\r
102                 } \r
103                 return client;\r
104         }\r
105         \r
106         /**\r
107          * Use this API when you have permission to have your call act as the end client's ID.\r
108          * \r
109          *  Your calls will get 403 errors if you do not have this permission.  it is a special setup, rarely given.\r
110          * \r
111          * @param apiVersion\r
112          * @param req\r
113          * @return\r
114          * @throws CadiException\r
115          */\r
116         public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {\r
117                 Rcli<CLIENT> cl = client(apiVersion);\r
118                 return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));\r
119         }\r
120         \r
121         protected AAFCon(AAFCon<CLIENT> copy) {\r
122                 access = copy.access;\r
123                 timeout = copy.timeout;\r
124                 cleanInterval = copy.cleanInterval;\r
125                 connTimeout = copy.connTimeout;\r
126                 highCount = copy.highCount;\r
127                 userExpires = copy.userExpires;\r
128                 usageRefreshTriggerCount = copy.usageRefreshTriggerCount;\r
129                 permsDF = copy.permsDF;\r
130                 certsDF = copy.certsDF;\r
131                 usersDF = copy.usersDF;\r
132                 errDF = copy.errDF;\r
133                 app = copy.app;\r
134                 ss = copy.ss;\r
135                 si = copy.si;\r
136                 env = copy.env;\r
137                 disableCheck = copy.disableCheck;\r
138                 realm = copy.realm;\r
139         }\r
140         \r
141         protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{\r
142                 if(tag==null) {\r
143                         throw new CadiException("AAFCon cannot be constructed with a tag=null");\r
144                 }\r
145                 try {\r
146                         this.access = access;\r
147                         this.si = si;\r
148                         this.ss = si.defSS;\r
149                         if(ss==null) {\r
150                                 String mechid = access.getProperty(Config.AAF_MECHID, null);\r
151                                 String encpass = access.getProperty(Config.AAF_MECHPASS, null);\r
152                                 if(encpass==null) {\r
153                                         String alias = access.getProperty(Config.CADI_ALIAS, mechid);\r
154                                         if(alias==null) {\r
155                                                 throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");\r
156                                         }\r
157                                         set(si.defSS=x509Alias(alias));\r
158                                 } else {\r
159                                         if(mechid!=null && encpass !=null) {\r
160                                                 set(si.defSS=basicAuth(mechid, encpass));\r
161                                         } else {\r
162                                                 set(si.defSS=new SecuritySetter<CLIENT>() {\r
163                                                         \r
164                                                         @Override\r
165                                                         public String getID() {\r
166                                                                 return "";\r
167                                                         }\r
168                         \r
169                                                         @Override\r
170                                                         public void setSecurity(CLIENT client) throws CadiException {\r
171                                                                 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");\r
172                                                         }\r
173 \r
174                                                         @Override\r
175                                                         public int setLastResponse(int respCode) {\r
176                                                                 return 0;\r
177                                                         }\r
178                                                 });\r
179                                         }\r
180                                 }\r
181                         }\r
182                         \r
183                         timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));\r
184                         cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));\r
185                         highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());\r
186                         connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());\r
187                         userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());\r
188                         usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based\r
189         \r
190                         String str = access.getProperty(tag,null);\r
191                         if(str==null) {\r
192                                 throw new CadiException(tag + " property is required.");\r
193                         }\r
194                         setInitURI(str);\r
195         \r
196                         app=reverseDomain(ss.getID());\r
197                         realm="openecomp.org";\r
198         \r
199                         env = new RosettaEnv();\r
200                         permsDF = env.newDataFactory(Perms.class);\r
201                         usersDF = env.newDataFactory(Users.class);\r
202                         certsDF = env.newDataFactory(Certs.class);\r
203                         certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling\r
204                         errDF = env.newDataFactory(Error.class);\r
205                 } catch (APIException e) {\r
206                         throw new CadiException("AAFCon cannot be configured",e);\r
207                 }\r
208         }\r
209         \r
210         public RosettaEnv env() {\r
211                 return env;\r
212         }\r
213         \r
214         /**\r
215          * Return the backing AAFCon, if there is a Lur Setup that is AAF.\r
216          * \r
217          * If there is no AAFLur setup, it will return "null"\r
218          * @param servletRequest\r
219          * @return\r
220          */\r
221         public static final AAFCon<?> obtain(Object servletRequest) {\r
222                 if(servletRequest instanceof CadiWrap) {\r
223                         Lur lur = ((CadiWrap)servletRequest).getLur();\r
224                         if(lur != null) {\r
225                                 if(lur instanceof EpiLur) {\r
226                                         AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);\r
227                                         if(aal!=null) {\r
228                                                 return aal.aaf;\r
229                                         }\r
230                                 } else {\r
231                                         if(lur instanceof AbsAAFLur) {\r
232                                                 return ((AbsAAFLur<?>)lur).aaf;\r
233                                         }\r
234                                 }\r
235                         }\r
236                 }\r
237                 return null;\r
238         }\r
239         \r
240         public abstract AAFCon<CLIENT> clone(String url) throws CadiException;\r
241         \r
242         public AAFAuthn<CLIENT> newAuthn() throws APIException {\r
243                 try {\r
244                         return new AAFAuthn<CLIENT>(this);\r
245                 } catch (APIException e) {\r
246                         throw e;\r
247                 } catch (Exception e) {\r
248                         throw new APIException(e);\r
249                 }\r
250         }\r
251 \r
252         public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {\r
253                 try {\r
254                         return new AAFAuthn<CLIENT>(this,c);\r
255                 } catch (APIException e) {\r
256                         throw e;\r
257                 } catch (Exception e) {\r
258                         throw new APIException(e);\r
259                 }\r
260         }\r
261 \r
262         public AAFLurPerm newLur() throws CadiException {\r
263                 try {\r
264                         if(lur==null) {\r
265                                 return new AAFLurPerm(this);\r
266                         } else {\r
267                                 return new AAFLurPerm(this,lur);\r
268                         }\r
269                 } catch (CadiException e) {\r
270                         throw e;\r
271                 } catch (Exception e) {\r
272                         throw new CadiException(e);\r
273                 }\r
274         }\r
275         \r
276         public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {\r
277                 try {\r
278                         return new AAFLurPerm(this,c);\r
279                 } catch (APIException e) {\r
280                         throw e;\r
281                 } catch (Exception e) {\r
282                         throw new APIException(e);\r
283                 }\r
284         }\r
285 \r
286         /**\r
287          * Take a Fully Qualified User, and get a Namespace from it.\r
288          * @param user\r
289          * @return\r
290          */\r
291         public static String reverseDomain(String user) {\r
292                 StringBuilder sb = null;\r
293                 String[] split = Split.split('.',user);\r
294                 int at;\r
295                 for(int i=split.length-1;i>=0;--i) {\r
296                         if(sb == null) {\r
297                                 sb = new StringBuilder();\r
298                         } else {\r
299                                 sb.append('.');\r
300                         }\r
301 \r
302                         if((at = split[i].indexOf('@'))>0) {\r
303                                 sb.append(split[i].subSequence(at+1, split[i].length()));\r
304                         } else {\r
305                                 sb.append(split[i]);\r
306                         }\r
307                 }\r
308                 \r
309                 return sb==null?"":sb.toString();\r
310         }\r
311 \r
312         protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;\r
313         \r
314         public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;\r
315 \r
316 \r
317         public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;\r
318         \r
319         public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;\r
320         \r
321         public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;\r
322         \r
323         public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;\r
324 \r
325 \r
326         public String getRealm() {\r
327                 return realm;\r
328 \r
329         }\r
330 \r
331         public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {\r
332                 this.ss = ss;\r
333                 if(ss instanceof AbsBasicAuth) {\r
334                         disableCheck = (ss instanceof AbsBasicAuth)?\r
335                         new DisableCheck() {\r
336                                 AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;\r
337                                 @Override\r
338                                 public boolean isDisabled() {\r
339                                         return aba.isDenied();\r
340                                 }\r
341                         }:\r
342                         new DisableCheck() {\r
343                                 @Override\r
344                                 public boolean isDisabled() {\r
345                                         return this.isDisabled();\r
346                                 }\r
347                         };\r
348                 }\r
349                 for(Rcli<CLIENT> client : clients.values()) {\r
350                         client.setSecuritySetter(ss);\r
351                 }\r
352                 return ss;\r
353         }\r
354         \r
355         public SecurityInfoC<CLIENT> securityInfo() {\r
356                 return si;\r
357         }\r
358 \r
359         public String defID() {\r
360                 if(ss!=null) {\r
361                         return ss.getID();\r
362                 }\r
363                 return "unknown";\r
364         }\r
365         \r
366         public void invalidate() throws CadiException {\r
367                 for(Rcli<CLIENT> client : clients.values()) {\r
368                         client.invalidate();\r
369                         clients.remove(client);\r
370                 }\r
371         }\r
372 \r
373         public String readableErrMsg(Future<?> f) {\r
374                 String text = f.body();\r
375                 if(text==null || text.length()==0) {\r
376                         text = f.code() + ": **No Message**";\r
377                 } else if(text.contains("%")) {\r
378                         try {\r
379                                 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();\r
380                                 return Vars.convert(err.getText(),err.getVariables());\r
381                         } catch (APIException e){\r
382                                 // just return the body below\r
383                         }\r
384                 }\r
385                 return text;\r
386         }\r
387         \r
388         private interface DisableCheck {\r
389                 public boolean isDisabled();\r
390         };\r
391         \r
392         public boolean isDisabled() {\r
393                 return disableCheck.isDisabled();\r
394         }\r
395 }\r