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