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