2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.cadi.aaf.v2_0;
25 import java.net.UnknownHostException;
26 import java.util.List;
28 import java.util.concurrent.ConcurrentHashMap;
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;
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;
65 public abstract class AAFCon<CLIENT> implements Connector {
66 final public Access 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;
77 public final String app;
78 protected final String apiVersion;
79 protected SecurityInfoC<CLIENT> si;
81 private AAFLurPerm lur;
83 final public RosettaEnv env;
84 protected AAFCon(AAFCon<CLIENT> copy) {
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;
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);
106 throw new CadiException("AAFCon cannot be constructed without a property tag or URL");
108 String str = access.getProperty(tag,null);
110 if (tag.contains("://")) { // assume a URL
113 throw new CadiException("A URL or " + tag + " property is required.");
117 RegistrationPropHolder rph = new RegistrationPropHolder(access, 0);
118 str = rph.replacements("AAFCon",str, null,null);
119 } catch (UnknownHostException e) {
120 throw new CadiException(e);
122 access.printf(Level.INFO, "AAFCon has URL of %s",str);
126 this.access = access;
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);
131 mechid=access.getProperty(Config.OAUTH_CLIENT_ID,null);
133 String alias = access.getProperty(Config.CADI_ALIAS, null);
135 si.defSS=x509Alias(alias);
139 String encpass = access.getProperty(Config.AAF_APPPASS, null);
141 encpass = access.getProperty(Config.OAUTH_CLIENT_SECRET,null);
146 access.printf(Access.Level.WARN,"%s, %s or %s required before use.", Config.CADI_ALIAS, Config.AAF_APPID, Config.OAUTH_CLIENT_ID);
151 si.defSS=basicAuth(mechid, encpass);
154 si.defSS=new SecuritySetter<CLIENT>() {
157 public String getID() {
162 public void setSecurity(CLIENT client) throws CadiException {
163 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
167 public int setLastResponse(int respCode) {
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
184 app=FQI.reverseDomain(si.defSS.getID());
185 realm = access.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm());
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);
198 protected abstract URI initURI();
199 protected abstract void setInitURI(String uriString) throws CadiException;
201 public final String aafVersion() {
206 * Use this call to get the appropriate client based on configuration (HTTP, future)
207 * using default AAF API Version
211 * @throws CadiException
213 public Rcli<CLIENT> client() throws CadiException {
214 return client(apiVersion);
218 * Use this call to get the appropriate client based on configuration (HTTP, future)
222 * @throws CadiException
224 public Rcli<CLIENT> client(final String apiVersion) throws CadiException {
225 Rcli<CLIENT> client = clients.get(apiVersion);
227 client = rclient(initURI(),si.defSS);
228 client.apiVersion(apiVersion)
229 .readTimeout(connTimeout);
230 clients.put(apiVersion, client);
235 public Rcli<CLIENT> client(URI uri) throws CadiException {
236 return rclient(uri,si.defSS).readTimeout(connTimeout);
240 * Use this API when you have permission to have your call act as the end client's ID.
242 * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
247 * @throws CadiException
249 public Rcli<CLIENT> clientAs(TaggedPrincipal p) throws CadiException {
250 return clientAs(apiVersion,p);
254 * Use this API when you have permission to have your call act as the end client's ID.
256 * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
261 * @throws CadiException
263 public Rcli<CLIENT> clientAs(String apiVersion, TaggedPrincipal p) throws CadiException {
264 Rcli<CLIENT> cl = client(apiVersion);
265 return cl.forUser(transferSS(p));
270 * Use this call to get the appropriate client based on configuration (HTTP, future),
271 * ignoring those already attempted, using the default api version
273 * @param attemptedClients
275 * @throws CadiException
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);
287 public RosettaEnv env() {
292 * Return the backing AAFCon, if there is a Lur Setup that is AAF.
294 * If there is no AAFLur setup, it will return "null"
295 * @param servletRequest
298 public static final AAFCon<?> obtain(Object servletRequest) {
299 if (servletRequest instanceof CadiWrap) {
300 Lur lur = ((CadiWrap)servletRequest).getLur();
302 if (lur instanceof EpiLur) {
303 AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
308 if (lur instanceof AbsAAFLur) {
309 return ((AbsAAFLur<?>)lur).aaf;
317 public abstract AAFCon<CLIENT> clone(String url) throws CadiException, LocatorException;
319 public AAFAuthn<CLIENT> newAuthn() throws APIException {
321 return new AAFAuthn<>(this);
322 } catch (Exception e) {
323 throw new APIException(e);
327 public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) {
328 return new AAFAuthn<>(this, c);
331 public AAFLurPerm newLur() throws CadiException {
334 lur = new AAFLurPerm(this);
337 return new AAFLurPerm(this,lur);
339 } catch (CadiException e) {
341 } catch (Exception e) {
342 throw new CadiException(e);
346 public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
348 return new AAFLurPerm(this,c);
349 } catch (APIException e) {
351 } catch (Exception e) {
352 throw new APIException(e);
356 protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
358 protected abstract Rcli<CLIENT> rclient(List<URI> uris, SecuritySetter<CLIENT> ss) throws CadiException;
360 public abstract Rcli<CLIENT> rclient(Locator<URI> loc, SecuritySetter<CLIENT> ss) throws CadiException;
362 public Rcli<CLIENT> client(Locator<URI> locator) throws CadiException {
363 return rclient(locator,si.defSS);
366 public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
368 public abstract<RET> RET bestForUser(GetSetter get, Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
370 public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
372 public abstract SecuritySetter<CLIENT> transferSS(TaggedPrincipal principal) throws CadiException;
374 public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
376 public abstract SecuritySetter<CLIENT> tokenSS(final String client_id, final String accessToken) throws CadiException;
378 public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
381 public String getRealm() {
387 * This interface allows the AAFCon, even though generic, to pass in correctly typed values based on the above SS commands.
391 public interface GetSetter {
392 public<CLIENT> SecuritySetter<CLIENT> get(AAFCon<CLIENT> con) throws CadiException;
395 public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
397 for (Rcli<CLIENT> client : clients.values()) {
398 client.setSecuritySetter(ss);
403 public SecurityInfoC<CLIENT> securityInfo() {
407 public String defID() {
409 return si.defSS.getID();
414 public void invalidate() throws CadiException {
415 for (Rcli<CLIENT> client : clients.values()) {
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("%")) {
427 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
428 return Vars.convert(err.getText(),err.getVariables());
429 } catch (APIException e){
436 public static AAFCon<?> newInstance(PropAccess pa) throws CadiException, LocatorException {
437 // Potentially add plugin for other kinds of Access
438 return new AAFConHttp(pa);