3210713115f71ed2c5d0de87dde5a20c8944b77e
[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         /*
80         protected abstract SecuritySetter<CLIENT>  bestSS(SecurityInfoC<CLIENT> si) throws CadiException;
81         */
82         
83         /**
84          * Use this call to get the appropriate client based on configuration (HTTP, future)
85          * 
86          * @param apiVersion
87          * @return
88          * @throws CadiException
89          */
90         public Rcli<CLIENT> client(String apiVersion) throws CadiException {
91                 Rcli<CLIENT> client = clients.get(apiVersion);
92                 if(client==null) {
93                         client = rclient(initURI(),si.defSS);
94                         client.apiVersion(apiVersion)
95                                   .readTimeout(connTimeout);
96                         clients.put(apiVersion, client);
97                 } 
98                 return client;
99         }
100
101         public Rcli<CLIENT> client(URI uri) throws CadiException {
102                 return rclient(uri,si.defSS).readTimeout(connTimeout);
103         }
104         
105         /**
106          * Use this API when you have permission to have your call act as the end client's ID.
107          * 
108          *  Your calls will get 403 errors if you do not have this permission.  it is a special setup, rarely given.
109          * 
110          * @param apiVersion
111          * @param req
112          * @return
113          * @throws CadiException
114          */
115         public Rcli<CLIENT> clientAs(String apiVersion, TaggedPrincipal p) throws CadiException {
116                 Rcli<CLIENT> cl = client(apiVersion);
117                 return cl.forUser(transferSS(p));
118         }
119         
120         protected AAFCon(AAFCon<CLIENT> copy) {
121                 access = copy.access;
122                 timeout = copy.timeout;
123                 cleanInterval = copy.cleanInterval;
124                 connTimeout = copy.connTimeout;
125                 highCount = copy.highCount;
126                 userExpires = copy.userExpires;
127                 usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
128                 permsDF = copy.permsDF;
129                 certsDF = copy.certsDF;
130                 usersDF = copy.usersDF;
131                 errDF = copy.errDF;
132                 app = copy.app;
133                 si = copy.si;
134                 env = copy.env;
135                 realm = copy.realm;
136         }
137         
138         protected AAFCon(Access access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
139                 if(tag==null) {
140                         throw new CadiException("AAFCon cannot be constructed without a property tag or URL");
141                 } else {
142                         String str = access.getProperty(tag,null);
143                         if(str==null) {
144                                 if(tag.contains("://")) { // assume a URL
145                                         str = tag;
146                                 } else {
147                                         throw new CadiException("A URL or " + tag + " property is required.");
148                                 }
149                         }
150                         setInitURI(str);
151                 }
152                 try {
153                         this.access = access;
154                         this.si = si;
155                         if(si.defSS.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                                                 si.defSS=x509Alias(alias);
171                                                 set(si.defSS);
172                                         }
173                                 } else {
174                                         if(mechid!=null) {
175                                                 si.defSS=basicAuth(mechid, encpass);
176                                                 set(si.defSS);
177                                         } else {
178                                                 si.defSS=new SecuritySetter<CLIENT>() {
179
180                                                         @Override
181                                                         public String getID() {
182                                                                 return "";
183                                                         }
184
185                                                         @Override
186                                                         public void setSecurity(CLIENT client) throws CadiException {
187                                                                 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
188                                                         }
189
190                                                         @Override
191                                                         public int setLastResponse(int respCode) {
192                                                                 return 0;
193                                                         }
194                                                 };
195                                                 set(si.defSS);
196                                         }
197                                 }
198                         }
199                         
200                         timeout = Integer.parseInt(access.getProperty(Config.AAF_CALL_TIMEOUT, Config.AAF_CALL_TIMEOUT_DEF));
201                         cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
202                         highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
203                         connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
204                         userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
205                         usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
206         
207                         app=FQI.reverseDomain(si.defSS.getID());
208                         //TODO Get Realm from AAF
209                         realm="people.osaaf.org";
210         
211                         env = new RosettaEnv();
212                         permsDF = env.newDataFactory(Perms.class);
213                         usersDF = env.newDataFactory(Users.class);
214                         certsDF = env.newDataFactory(Certs.class);
215                         certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
216                         errDF = env.newDataFactory(Error.class);
217                 } catch (APIException e) {
218                         throw new CadiException("AAFCon cannot be configured",e);
219                 }
220         }
221         
222         public RosettaEnv env() {
223                 return env;
224         }
225         
226         /**
227          * Return the backing AAFCon, if there is a Lur Setup that is AAF.
228          * 
229          * If there is no AAFLur setup, it will return "null"
230          * @param servletRequest
231          * @return
232          */
233         public static final AAFCon<?> obtain(Object servletRequest) {
234                 if(servletRequest instanceof CadiWrap) {
235                         Lur lur = ((CadiWrap)servletRequest).getLur();
236                         if(lur != null) {
237                                 if(lur instanceof EpiLur) {
238                                         AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
239                                         if(aal!=null) {
240                                                 return aal.aaf;
241                                         }
242                                 } else {
243                                         if(lur instanceof AbsAAFLur) {
244                                                 return ((AbsAAFLur<?>)lur).aaf;
245                                         }
246                                 }
247                         }
248                 }
249                 return null;
250         }
251         
252         public abstract AAFCon<CLIENT> clone(String url) throws CadiException, LocatorException;
253         
254         public AAFAuthn<CLIENT> newAuthn() throws APIException {
255                 try {
256                         return new AAFAuthn<>(this);
257                 } catch (Exception e) {
258                         throw new APIException(e);
259                 }
260         }
261
262         public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) {
263                 return new AAFAuthn<>(this, c);
264         }
265
266         public AAFLurPerm newLur() throws CadiException {
267                 try {
268                         if(lur==null) {
269                                 lur = new AAFLurPerm(this);
270                                 return lur;
271                         } else {
272                                 return new AAFLurPerm(this,lur);
273                         }
274                 } catch (CadiException e) {
275                         throw e;
276                 } catch (Exception e) {
277                         throw new CadiException(e);
278                 }
279         }
280         
281         public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
282                 try {
283                         return new AAFLurPerm(this,c);
284                 } catch (APIException e) {
285                         throw e;
286                 } catch (Exception e) {
287                         throw new APIException(e);
288                 }
289         }
290
291         protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
292         
293         public abstract Rcli<CLIENT> rclient(Locator<URI> loc, SecuritySetter<CLIENT> ss) throws CadiException;
294
295         public Rcli<CLIENT> client(Locator<URI> locator) throws CadiException {
296                 return rclient(locator,si.defSS);
297         }
298         
299         public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
300
301         public abstract<RET> RET bestForUser(GetSetter get, Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
302
303         public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
304         
305         public abstract SecuritySetter<CLIENT> transferSS(TaggedPrincipal principal) throws CadiException;
306         
307         public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
308         
309         public abstract SecuritySetter<CLIENT> tokenSS(final String client_id, final String accessToken) throws CadiException;
310         
311         public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
312         
313
314         public String getRealm() {
315                 return realm;
316
317         }
318         
319         /**
320          * This interface allows the AAFCon, even though generic, to pass in correctly typed values based on the above SS commands.
321          * @author Jonathan
322          *
323          */
324         public interface GetSetter {
325                 public<CLIENT> SecuritySetter<CLIENT> get(AAFCon<CLIENT> con) throws CadiException;
326         }
327
328         public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
329                 si.set(ss);
330                 for(Rcli<CLIENT> client : clients.values()) {
331                         client.setSecuritySetter(ss);
332                 }
333                 return ss;
334         }
335         
336         public SecurityInfoC<CLIENT> securityInfo() {
337                 return si;
338         }
339
340         public String defID() {
341                 if(si!=null) {
342                         return si.defSS.getID();
343                 }
344                 return "unknown";
345         }
346         
347         public void invalidate() throws CadiException {
348                 for(Rcli<CLIENT> client : clients.values()) {
349                         client.invalidate();
350                 }
351                 clients.clear();
352         }
353
354         public String readableErrMsg(Future<?> f) {
355                 String text = f.body();
356                 if(text==null || text.length()==0) {
357                         text = f.code() + ": **No Message**";
358                 } else if(text.contains("%")) {
359                         try {
360                                 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
361                                 return Vars.convert(err.getText(),err.getVariables());
362                         } catch (APIException e){
363                                 access.log(e);
364                         }
365                 }
366                 return text;
367         }
368         
369         public static AAFCon<?> newInstance(PropAccess pa) throws CadiException, LocatorException {
370                 // Potentially add plugin for other kinds of Access
371                 return new AAFConHttp(pa);
372         }
373 }