1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.cadi.aaf.v2_0;
\r
25 import java.net.URI;
\r
26 import java.security.Principal;
\r
27 import java.util.Map;
\r
28 import java.util.concurrent.ConcurrentHashMap;
\r
30 import javax.servlet.ServletRequest;
\r
31 import javax.servlet.http.HttpServletRequest;
\r
33 import org.onap.aaf.cadi.AbsUserCache;
\r
34 import org.onap.aaf.cadi.CadiException;
\r
35 import org.onap.aaf.cadi.CadiWrap;
\r
36 import org.onap.aaf.cadi.Connector;
\r
37 import org.onap.aaf.cadi.LocatorException;
\r
38 import org.onap.aaf.cadi.Lur;
\r
39 import org.onap.aaf.cadi.PropAccess;
\r
40 import org.onap.aaf.cadi.SecuritySetter;
\r
41 import org.onap.aaf.cadi.aaf.AAFPermission;
\r
42 import org.onap.aaf.cadi.aaf.marshal.CertsMarshal;
\r
43 import org.onap.aaf.cadi.client.AbsBasicAuth;
\r
44 import org.onap.aaf.cadi.client.Future;
\r
45 import org.onap.aaf.cadi.client.Rcli;
\r
46 import org.onap.aaf.cadi.client.Retryable;
\r
47 import org.onap.aaf.cadi.config.Config;
\r
48 import org.onap.aaf.cadi.config.SecurityInfoC;
\r
49 import org.onap.aaf.cadi.lur.EpiLur;
\r
50 import org.onap.aaf.cadi.principal.BasicPrincipal;
\r
51 import org.onap.aaf.cadi.util.Vars;
\r
53 import org.onap.aaf.inno.env.APIException;
\r
54 import org.onap.aaf.inno.env.Data.TYPE;
\r
55 import org.onap.aaf.inno.env.util.Split;
\r
56 import org.onap.aaf.rosetta.env.RosettaDF;
\r
57 import org.onap.aaf.rosetta.env.RosettaEnv;
\r
59 import aaf.v2_0.Certs;
\r
60 import aaf.v2_0.Error;
\r
61 import aaf.v2_0.Perms;
\r
62 import aaf.v2_0.Users;
\r
64 public abstract class AAFCon<CLIENT> implements Connector {
\r
65 public static final String AAF_LATEST_VERSION = "2.0";
\r
67 final public PropAccess access;
\r
69 final public int timeout, cleanInterval, connTimeout;
\r
70 final public int highCount, userExpires, usageRefreshTriggerCount;
\r
71 private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();
\r
72 final public RosettaDF<Perms> permsDF;
\r
73 final public RosettaDF<Certs> certsDF;
\r
74 final public RosettaDF<Users> usersDF;
\r
75 final public RosettaDF<Error> errDF;
\r
76 private String realm;
\r
77 public final String app;
\r
78 protected SecuritySetter<CLIENT> ss;
\r
79 protected SecurityInfoC<CLIENT> si;
\r
81 private DisableCheck disableCheck;
\r
83 private AAFLurPerm lur;
\r
85 private RosettaEnv env;
\r
86 protected abstract URI initURI();
\r
87 protected abstract void setInitURI(String uriString) throws CadiException;
\r
90 * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)
\r
94 * @throws CadiException
\r
96 public Rcli<CLIENT> client(String apiVersion) throws CadiException {
\r
97 Rcli<CLIENT> client = clients.get(apiVersion);
\r
99 client = rclient(initURI(),ss);
\r
100 client.apiVersion(apiVersion)
\r
101 .readTimeout(connTimeout);
\r
102 clients.put(apiVersion, client);
\r
108 * Use this API when you have permission to have your call act as the end client's ID.
\r
110 * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
\r
112 * @param apiVersion
\r
115 * @throws CadiException
\r
117 public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {
\r
118 Rcli<CLIENT> cl = client(apiVersion);
\r
119 return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));
\r
122 protected AAFCon(AAFCon<CLIENT> copy) {
\r
123 access = copy.access;
\r
124 timeout = copy.timeout;
\r
125 cleanInterval = copy.cleanInterval;
\r
126 connTimeout = copy.connTimeout;
\r
127 highCount = copy.highCount;
\r
128 userExpires = copy.userExpires;
\r
129 usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
\r
130 permsDF = copy.permsDF;
\r
131 certsDF = copy.certsDF;
\r
132 usersDF = copy.usersDF;
\r
133 errDF = copy.errDF;
\r
138 disableCheck = copy.disableCheck;
\r
139 realm = copy.realm;
\r
142 protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
\r
144 throw new CadiException("AAFCon cannot be constructed with a tag=null");
\r
147 this.access = access;
\r
149 this.ss = si.defSS;
\r
151 String mechid = access.getProperty(Config.AAF_MECHID, null);
\r
152 String encpass = access.getProperty(Config.AAF_MECHPASS, null);
\r
153 if(encpass==null) {
\r
154 String alias = access.getProperty(Config.CADI_ALIAS, mechid);
\r
156 throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");
\r
158 set(si.defSS=x509Alias(alias));
\r
160 if(mechid!=null && encpass !=null) {
\r
161 set(si.defSS=basicAuth(mechid, encpass));
\r
163 set(si.defSS=new SecuritySetter<CLIENT>() {
\r
166 public String getID() {
\r
171 public void setSecurity(CLIENT client) throws CadiException {
\r
172 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
\r
176 public int setLastResponse(int respCode) {
\r
184 timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));
\r
185 cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
\r
186 highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
\r
187 connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
\r
188 userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
\r
189 usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
\r
191 String str = access.getProperty(tag,null);
\r
193 throw new CadiException(tag + " property is required.");
\r
197 app=reverseDomain(ss.getID());
\r
198 realm="openecomp.org";
\r
200 env = new RosettaEnv();
\r
201 permsDF = env.newDataFactory(Perms.class);
\r
202 usersDF = env.newDataFactory(Users.class);
\r
203 certsDF = env.newDataFactory(Certs.class);
\r
204 certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
\r
205 errDF = env.newDataFactory(Error.class);
\r
206 } catch (APIException e) {
\r
207 throw new CadiException("AAFCon cannot be configured",e);
\r
211 public RosettaEnv env() {
\r
216 * Return the backing AAFCon, if there is a Lur Setup that is AAF.
\r
218 * If there is no AAFLur setup, it will return "null"
\r
219 * @param servletRequest
\r
222 public static final AAFCon<?> obtain(Object servletRequest) {
\r
223 if(servletRequest instanceof CadiWrap) {
\r
224 Lur lur = ((CadiWrap)servletRequest).getLur();
\r
226 if(lur instanceof EpiLur) {
\r
227 AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
\r
232 if(lur instanceof AbsAAFLur) {
\r
233 return ((AbsAAFLur<?>)lur).aaf;
\r
241 public abstract AAFCon<CLIENT> clone(String url) throws CadiException;
\r
243 public AAFAuthn<CLIENT> newAuthn() throws APIException {
\r
245 return new AAFAuthn<CLIENT>(this);
\r
246 } catch (APIException e) {
\r
248 } catch (Exception e) {
\r
249 throw new APIException(e);
\r
253 public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {
\r
255 return new AAFAuthn<CLIENT>(this,c);
\r
256 } catch (APIException e) {
\r
258 } catch (Exception e) {
\r
259 throw new APIException(e);
\r
263 public AAFLurPerm newLur() throws CadiException {
\r
266 return new AAFLurPerm(this);
\r
268 return new AAFLurPerm(this,lur);
\r
270 } catch (CadiException e) {
\r
272 } catch (Exception e) {
\r
273 throw new CadiException(e);
\r
277 public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
\r
279 return new AAFLurPerm(this,c);
\r
280 } catch (APIException e) {
\r
282 } catch (Exception e) {
\r
283 throw new APIException(e);
\r
288 * Take a Fully Qualified User, and get a Namespace from it.
\r
292 public static String reverseDomain(String user) {
\r
293 StringBuilder sb = null;
\r
294 String[] split = Split.split('.',user);
\r
296 for(int i=split.length-1;i>=0;--i) {
\r
298 sb = new StringBuilder();
\r
303 if((at = split[i].indexOf('@'))>0) {
\r
304 sb.append(split[i].subSequence(at+1, split[i].length()));
\r
306 sb.append(split[i]);
\r
310 return sb==null?"":sb.toString();
\r
313 protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
\r
315 public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
\r
318 public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
\r
320 public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;
\r
322 public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
\r
324 public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
\r
327 public String getRealm() {
\r
332 public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
\r
334 if(ss instanceof AbsBasicAuth) {
\r
335 disableCheck = (ss instanceof AbsBasicAuth)?
\r
336 new DisableCheck() {
\r
337 AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;
\r
339 public boolean isDisabled() {
\r
340 return aba.isDenied();
\r
343 new DisableCheck() {
\r
345 public boolean isDisabled() {
\r
346 return this.isDisabled();
\r
350 for(Rcli<CLIENT> client : clients.values()) {
\r
351 client.setSecuritySetter(ss);
\r
356 public SecurityInfoC<CLIENT> securityInfo() {
\r
360 public String defID() {
\r
367 public void invalidate() throws CadiException {
\r
368 for(Rcli<CLIENT> client : clients.values()) {
\r
369 client.invalidate();
\r
370 clients.remove(client);
\r
374 public String readableErrMsg(Future<?> f) {
\r
375 String text = f.body();
\r
376 if(text==null || text.length()==0) {
\r
377 text = f.code() + ": **No Message**";
\r
378 } else if(text.contains("%")) {
\r
380 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
\r
381 return Vars.convert(err.getText(),err.getVariables());
\r
382 } catch (APIException e){
\r
383 // just return the body below
\r
389 private interface DisableCheck {
\r
390 public boolean isDisabled();
\r
393 public boolean isDisabled() {
\r
394 return disableCheck.isDisabled();
\r