Sonar fixes related to exceptions
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / aaf / v2_0 / AAFCon.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.aaf.v2_0;
23
24 import java.net.URI;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.onap.aaf.cadi.AbsUserCache;
29 import org.onap.aaf.cadi.Access;
30 import org.onap.aaf.cadi.CadiException;
31 import org.onap.aaf.cadi.CadiWrap;
32 import org.onap.aaf.cadi.Connector;
33 import org.onap.aaf.cadi.Locator;
34 import org.onap.aaf.cadi.LocatorException;
35 import org.onap.aaf.cadi.Lur;
36 import org.onap.aaf.cadi.PropAccess;
37 import org.onap.aaf.cadi.SecuritySetter;
38 import org.onap.aaf.cadi.aaf.AAFPermission;
39 import org.onap.aaf.cadi.aaf.marshal.CertsMarshal;
40 import org.onap.aaf.cadi.client.Future;
41 import org.onap.aaf.cadi.client.Rcli;
42 import org.onap.aaf.cadi.client.Retryable;
43 import org.onap.aaf.cadi.config.Config;
44 import org.onap.aaf.cadi.config.SecurityInfoC;
45 import org.onap.aaf.cadi.lur.EpiLur;
46 import org.onap.aaf.cadi.principal.BasicPrincipal;
47 import org.onap.aaf.cadi.principal.TaggedPrincipal;
48 import org.onap.aaf.cadi.util.FQI;
49 import org.onap.aaf.cadi.util.Vars;
50 import org.onap.aaf.misc.env.APIException;
51 import org.onap.aaf.misc.env.Data.TYPE;
52 import org.onap.aaf.misc.rosetta.env.RosettaDF;
53 import org.onap.aaf.misc.rosetta.env.RosettaEnv;
54
55 import aaf.v2_0.Certs;
56 import aaf.v2_0.Error;
57 import aaf.v2_0.Perms;
58 import aaf.v2_0.Users;
59
60 public abstract class AAFCon<CLIENT> implements Connector {
61         final public Access access;
62         // Package access
63         final public int timeout, cleanInterval, connTimeout;
64         final public int highCount, userExpires, usageRefreshTriggerCount;
65         private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<>();
66         final public RosettaDF<Perms> permsDF;
67         final public RosettaDF<Certs> certsDF;
68         final public RosettaDF<Users> usersDF;
69         final public RosettaDF<Error> errDF;
70         private String realm;
71         public final String app;
72         protected SecurityInfoC<CLIENT> si;
73
74         private AAFLurPerm lur;
75
76         final public RosettaEnv env;
77         protected abstract URI initURI();
78         protected abstract void setInitURI(String uriString) throws CadiException;
79         protected abstract SecuritySetter<CLIENT>  bestSS(SecurityInfoC<CLIENT> si) throws CadiException;
80         
81         /**
82          * Use this call to get the appropriate client based on configuration (HTTP, future)
83          * 
84          * @param apiVersion
85          * @return
86          * @throws CadiException
87          */
88         public Rcli<CLIENT> client(String apiVersion) throws CadiException {
89                 Rcli<CLIENT> client = clients.get(apiVersion);
90                 if(client==null) {
91                         client = rclient(initURI(),si.defSS);
92                         client.apiVersion(apiVersion)
93                                   .readTimeout(connTimeout);
94                         clients.put(apiVersion, client);
95                 } 
96                 return client;
97         }
98
99         public Rcli<CLIENT> client(URI uri) throws CadiException {
100                 return rclient(uri,si.defSS).readTimeout(connTimeout);
101         }
102         
103         /**
104          * Use this API when you have permission to have your call act as the end client's ID.
105          * 
106          *  Your calls will get 403 errors if you do not have this permission.  it is a special setup, rarely given.
107          * 
108          * @param apiVersion
109          * @param req
110          * @return
111          * @throws CadiException
112          */
113         public Rcli<CLIENT> clientAs(String apiVersion, TaggedPrincipal p) throws CadiException {
114                 Rcli<CLIENT> cl = client(apiVersion);
115                 return cl.forUser(transferSS(p));
116         }
117         
118         protected AAFCon(AAFCon<CLIENT> copy) {
119                 access = copy.access;
120                 timeout = copy.timeout;
121                 cleanInterval = copy.cleanInterval;
122                 connTimeout = copy.connTimeout;
123                 highCount = copy.highCount;
124                 userExpires = copy.userExpires;
125                 usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
126                 permsDF = copy.permsDF;
127                 certsDF = copy.certsDF;
128                 usersDF = copy.usersDF;
129                 errDF = copy.errDF;
130                 app = copy.app;
131                 si = copy.si;
132                 env = copy.env;
133                 realm = copy.realm;
134         }
135         
136         protected AAFCon(Access access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
137                 if(tag==null) {
138                         throw new CadiException("AAFCon cannot be constructed without a property tag or URL");
139                 } else {
140                         si.defSS = bestSS(si);
141                         String str = access.getProperty(tag,null);
142                         if(str==null) {
143                                 if(tag.contains("://")) { // assume a URL
144                                         str = tag;
145                                 } else {
146                                         throw new CadiException("A URL or " + tag + " property is required.");
147                                 }
148                         }
149                         setInitURI(str);
150                 }
151                 try {
152                         this.access = access;
153                         this.si = si;
154                         if(si.defSS.getID().equals(SecurityInfoC.DEF_ID)) { // it's the Preliminary SS, try to get a better one
155                                 String mechid = access.getProperty(Config.AAF_APPID, null);
156                                 if(mechid==null) {
157                                         mechid=access.getProperty(Config.OAUTH_CLIENT_ID,null);
158                                 }
159                                 String encpass = access.getProperty(Config.AAF_APPPASS, null);
160                                 if(encpass==null) {
161                                         encpass = access.getProperty(Config.OAUTH_CLIENT_SECRET,null);
162                                 }
163                                 if(encpass==null) {
164                                         String alias = access.getProperty(Config.CADI_ALIAS, mechid);
165                                         if(alias==null) {
166                                                 access.printf(Access.Level.WARN,"%s, %s or %s required before use.", Config.CADI_ALIAS, Config.AAF_APPID, Config.OAUTH_CLIENT_ID);
167                                                 set(si.defSS);
168                                         } else {
169                                                 si.defSS=x509Alias(alias);
170                                                 set(si.defSS);
171                                         }
172                                 } else {
173                                         if(mechid!=null) {
174                                                 si.defSS=basicAuth(mechid, encpass);
175                                                 set(si.defSS);
176                                         } else {
177                                                 si.defSS=new SecuritySetter<CLIENT>() {
178
179                                                         @Override
180                                                         public String getID() {
181                                                                 return "";
182                                                         }
183
184                                                         @Override
185                                                         public void setSecurity(CLIENT client) throws CadiException {
186                                                                 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
187                                                         }
188
189                                                         @Override
190                                                         public int setLastResponse(int respCode) {
191                                                                 return 0;
192                                                         }
193                                                 };
194                                                 set(si.defSS);
195                                         }
196                                 }
197                         }
198                         
199                         timeout = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT, Config.AAF_CALL_TIMEOUT_DEF));
200                         cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
201                         highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
202                         connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
203                         userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
204                         usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
205         
206                         app=FQI.reverseDomain(si.defSS.getID());
207                         //TODO Get Realm from AAF
208                         realm="people.osaaf.org";
209         
210                         env = new RosettaEnv();
211                         permsDF = env.newDataFactory(Perms.class);
212                         usersDF = env.newDataFactory(Users.class);
213                         certsDF = env.newDataFactory(Certs.class);
214                         certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
215                         errDF = env.newDataFactory(Error.class);
216                 } catch (APIException e) {
217                         throw new CadiException("AAFCon cannot be configured",e);
218                 }
219         }
220         
221         public RosettaEnv env() {
222                 return env;
223         }
224         
225         /**
226          * Return the backing AAFCon, if there is a Lur Setup that is AAF.
227          * 
228          * If there is no AAFLur setup, it will return "null"
229          * @param servletRequest
230          * @return
231          */
232         public static final AAFCon<?> obtain(Object servletRequest) {
233                 if(servletRequest instanceof CadiWrap) {
234                         Lur lur = ((CadiWrap)servletRequest).getLur();
235                         if(lur != null) {
236                                 if(lur instanceof EpiLur) {
237                                         AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
238                                         if(aal!=null) {
239                                                 return aal.aaf;
240                                         }
241                                 } else {
242                                         if(lur instanceof AbsAAFLur) {
243                                                 return ((AbsAAFLur<?>)lur).aaf;
244                                         }
245                                 }
246                         }
247                 }
248                 return null;
249         }
250         
251         public abstract AAFCon<CLIENT> clone(String url) throws CadiException, LocatorException;
252         
253         public AAFAuthn<CLIENT> newAuthn() throws APIException {
254                 try {
255                         return new AAFAuthn<>(this);
256                 } catch (Exception e) {
257                         throw new APIException(e);
258                 }
259         }
260
261         public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) {
262                 return new AAFAuthn<>(this, c);
263         }
264
265         public AAFLurPerm newLur() throws CadiException {
266                 try {
267                         if(lur==null) {
268                                 lur = new AAFLurPerm(this);
269                                 return lur;
270                         } else {
271                                 return new AAFLurPerm(this,lur);
272                         }
273                 } catch (CadiException e) {
274                         throw e;
275                 } catch (Exception e) {
276                         throw new CadiException(e);
277                 }
278         }
279         
280         public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
281                 try {
282                         return new AAFLurPerm(this,c);
283                 } catch (APIException e) {
284                         throw e;
285                 } catch (Exception e) {
286                         throw new APIException(e);
287                 }
288         }
289
290         protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
291         
292         public abstract Rcli<CLIENT> rclient(Locator<URI> loc, SecuritySetter<CLIENT> ss) throws CadiException;
293
294         public Rcli<CLIENT> client(Locator<URI> locator) throws CadiException {
295                 return rclient(locator,si.defSS);
296         }
297         
298         public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
299
300         public abstract<RET> RET bestForUser(GetSetter get, Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
301
302         public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
303         
304         public abstract SecuritySetter<CLIENT> transferSS(TaggedPrincipal principal) throws CadiException;
305         
306         public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
307         
308         public abstract SecuritySetter<CLIENT> tokenSS(final String client_id, final String accessToken) throws CadiException;
309         
310         public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
311         
312
313         public String getRealm() {
314                 return realm;
315
316         }
317         
318         /**
319          * This interface allows the AAFCon, even though generic, to pass in correctly typed values based on the above SS commands.
320          * @author Jonathan
321          *
322          */
323         public interface GetSetter {
324                 public<CLIENT> SecuritySetter<CLIENT> get(AAFCon<CLIENT> con) throws CadiException;
325         }
326
327         public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
328                 si.set(ss);
329                 for(Rcli<CLIENT> client : clients.values()) {
330                         client.setSecuritySetter(ss);
331                 }
332                 return ss;
333         }
334         
335         public SecurityInfoC<CLIENT> securityInfo() {
336                 return si;
337         }
338
339         public String defID() {
340                 if(si!=null) {
341                         return si.defSS.getID();
342                 }
343                 return "unknown";
344         }
345         
346         public void invalidate() throws CadiException {
347                 for(Rcli<CLIENT> client : clients.values()) {
348                         client.invalidate();
349                 }
350                 clients.clear();
351         }
352
353         public String readableErrMsg(Future<?> f) {
354                 String text = f.body();
355                 if(text==null || text.length()==0) {
356                         text = f.code() + ": **No Message**";
357                 } else if(text.contains("%")) {
358                         try {
359                                 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
360                                 return Vars.convert(err.getText(),err.getVariables());
361                         } catch (APIException e){
362                                 access.log(e);
363                         }
364                 }
365                 return text;
366         }
367         
368         public static AAFCon<?> newInstance(PropAccess pa) throws CadiException, LocatorException {
369                 // Potentially add plugin for other kinds of Access
370                 return new AAFConHttp(pa);
371         }
372 }