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