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