Collection syntax change because of Sonar
[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                                                 set(si.defSS=x509Alias(alias));
170                                         }
171                                 } else {
172                                         if(mechid!=null && encpass !=null) {
173                                                 set(si.defSS=basicAuth(mechid, encpass));
174                                         } else {
175                                                 set(si.defSS=new SecuritySetter<CLIENT>() {
176                                                         
177                                                         @Override
178                                                         public String getID() {
179                                                                 return "";
180                                                         }
181                         
182                                                         @Override
183                                                         public void setSecurity(CLIENT client) throws CadiException {
184                                                                 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
185                                                         }
186
187                                                         @Override
188                                                         public int setLastResponse(int respCode) {
189                                                                 return 0;
190                                                         }
191                                                 });
192                                         }
193                                 }
194                         }
195                         
196                         timeout = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT, Config.AAF_CALL_TIMEOUT_DEF));
197                         cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
198                         highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
199                         connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
200                         userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
201                         usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
202         
203                         app=FQI.reverseDomain(si.defSS.getID());
204                         //TODO Get Realm from AAF
205                         realm="people.osaaf.org";
206         
207                         env = new RosettaEnv();
208                         permsDF = env.newDataFactory(Perms.class);
209                         usersDF = env.newDataFactory(Users.class);
210                         certsDF = env.newDataFactory(Certs.class);
211                         certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
212                         errDF = env.newDataFactory(Error.class);
213                 } catch (APIException e) {
214                         throw new CadiException("AAFCon cannot be configured",e);
215                 }
216         }
217         
218         public RosettaEnv env() {
219                 return env;
220         }
221         
222         /**
223          * Return the backing AAFCon, if there is a Lur Setup that is AAF.
224          * 
225          * If there is no AAFLur setup, it will return "null"
226          * @param servletRequest
227          * @return
228          */
229         public static final AAFCon<?> obtain(Object servletRequest) {
230                 if(servletRequest instanceof CadiWrap) {
231                         Lur lur = ((CadiWrap)servletRequest).getLur();
232                         if(lur != null) {
233                                 if(lur instanceof EpiLur) {
234                                         AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
235                                         if(aal!=null) {
236                                                 return aal.aaf;
237                                         }
238                                 } else {
239                                         if(lur instanceof AbsAAFLur) {
240                                                 return ((AbsAAFLur<?>)lur).aaf;
241                                         }
242                                 }
243                         }
244                 }
245                 return null;
246         }
247         
248         public abstract AAFCon<CLIENT> clone(String url) throws CadiException, LocatorException;
249         
250         public AAFAuthn<CLIENT> newAuthn() throws APIException {
251                 try {
252                         return new AAFAuthn<CLIENT>(this);
253                 } catch (APIException e) {
254                         throw e;
255                 } catch (Exception e) {
256                         throw new APIException(e);
257                 }
258         }
259
260         public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) {
261                 return new AAFAuthn<CLIENT>(this,c);
262         }
263
264         public AAFLurPerm newLur() throws CadiException {
265                 try {
266                         if(lur==null) {
267                                 return (lur =  new AAFLurPerm(this));
268                         } else {
269                                 return new AAFLurPerm(this,lur);
270                         }
271                 } catch (CadiException e) {
272                         throw e;
273                 } catch (Exception e) {
274                         throw new CadiException(e);
275                 }
276         }
277         
278         public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
279                 try {
280                         return new AAFLurPerm(this,c);
281                 } catch (APIException e) {
282                         throw e;
283                 } catch (Exception e) {
284                         throw new APIException(e);
285                 }
286         }
287
288         protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
289         
290         public abstract Rcli<CLIENT> rclient(Locator<URI> loc, SecuritySetter<CLIENT> ss) throws CadiException;
291
292         public Rcli<CLIENT> client(Locator<URI> locator) throws CadiException {
293                 return rclient(locator,si.defSS);
294         }
295         
296         public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
297
298         public abstract<RET> RET bestForUser(GetSetter get, Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
299
300         public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
301         
302         public abstract SecuritySetter<CLIENT> transferSS(TaggedPrincipal principal) throws CadiException;
303         
304         public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
305         
306         public abstract SecuritySetter<CLIENT> tokenSS(final String client_id, final String accessToken) throws CadiException;
307         
308         public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
309         
310
311         public String getRealm() {
312                 return realm;
313
314         }
315         
316         /**
317          * This interface allows the AAFCon, even though generic, to pass in correctly typed values based on the above SS commands.
318          * @author Jonathan
319          *
320          */
321         public interface GetSetter {
322                 public<CLIENT> SecuritySetter<CLIENT> get(AAFCon<CLIENT> con) throws CadiException;
323         }
324
325         public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
326                 si.set(ss);
327                 for(Rcli<CLIENT> client : clients.values()) {
328                         client.setSecuritySetter(ss);
329                 }
330                 return ss;
331         }
332         
333         public SecurityInfoC<CLIENT> securityInfo() {
334                 return si;
335         }
336
337         public String defID() {
338                 if(si!=null) {
339                         return si.defSS.getID();
340                 }
341                 return "unknown";
342         }
343         
344         public void invalidate() throws CadiException {
345                 for(Rcli<CLIENT> client : clients.values()) {
346                         client.invalidate();
347                 }
348                 clients.clear();
349         }
350
351         public String readableErrMsg(Future<?> f) {
352                 String text = f.body();
353                 if(text==null || text.length()==0) {
354                         text = f.code() + ": **No Message**";
355                 } else if(text.contains("%")) {
356                         try {
357                                 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
358                                 return Vars.convert(err.getText(),err.getVariables());
359                         } catch (APIException e){
360                                 // just return the body below
361                         }
362                 }
363                 return text;
364         }
365         
366         public static AAFCon<?> newInstance(PropAccess pa) throws APIException, CadiException, LocatorException {
367                 // Potentially add plugin for other kinds of Access
368                 return new AAFConHttp(pa);
369         }
370 }