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 com.att.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 com.att.cadi.AbsUserCache;
\r
34 import com.att.cadi.CadiException;
\r
35 import com.att.cadi.CadiWrap;
\r
36 import com.att.cadi.Connector;
\r
37 import com.att.cadi.LocatorException;
\r
38 import com.att.cadi.Lur;
\r
39 import com.att.cadi.PropAccess;
\r
40 import com.att.cadi.SecuritySetter;
\r
41 import com.att.cadi.aaf.AAFPermission;
\r
42 import com.att.cadi.aaf.marshal.CertsMarshal;
\r
43 import com.att.cadi.client.AbsBasicAuth;
\r
44 import com.att.cadi.client.Future;
\r
45 import com.att.cadi.client.Rcli;
\r
46 import com.att.cadi.client.Retryable;
\r
47 import com.att.cadi.config.Config;
\r
48 import com.att.cadi.config.SecurityInfoC;
\r
49 import com.att.cadi.lur.EpiLur;
\r
50 import com.att.cadi.principal.BasicPrincipal;
\r
51 import com.att.cadi.util.Vars;
\r
52 import com.att.inno.env.APIException;
\r
53 import com.att.inno.env.Data.TYPE;
\r
54 import com.att.inno.env.util.Split;
\r
55 import com.att.rosetta.env.RosettaDF;
\r
56 import com.att.rosetta.env.RosettaEnv;
\r
58 import aaf.v2_0.Certs;
\r
59 import aaf.v2_0.Error;
\r
60 import aaf.v2_0.Perms;
\r
61 import aaf.v2_0.Users;
\r
63 public abstract class AAFCon<CLIENT> implements Connector {
\r
64 public static final String AAF_LATEST_VERSION = "2.0";
\r
66 final public PropAccess access;
\r
68 final public int timeout, cleanInterval, connTimeout;
\r
69 final public int highCount, userExpires, usageRefreshTriggerCount;
\r
70 private Map<String,Rcli<CLIENT>> clients = new ConcurrentHashMap<String,Rcli<CLIENT>>();
\r
71 final public RosettaDF<Perms> permsDF;
\r
72 final public RosettaDF<Certs> certsDF;
\r
73 final public RosettaDF<Users> usersDF;
\r
74 final public RosettaDF<Error> errDF;
\r
75 private String realm;
\r
76 public final String app;
\r
77 protected SecuritySetter<CLIENT> ss;
\r
78 protected SecurityInfoC<CLIENT> si;
\r
80 private DisableCheck disableCheck;
\r
82 private AAFLurPerm lur;
\r
84 private RosettaEnv env;
\r
85 protected abstract URI initURI();
\r
86 protected abstract void setInitURI(String uriString) throws CadiException;
\r
89 * Use this call to get the appropriate client based on configuration (DME2, HTTP, future)
\r
93 * @throws CadiException
\r
95 public Rcli<CLIENT> client(String apiVersion) throws CadiException {
\r
96 Rcli<CLIENT> client = clients.get(apiVersion);
\r
98 client = rclient(initURI(),ss);
\r
99 client.apiVersion(apiVersion)
\r
100 .readTimeout(connTimeout);
\r
101 clients.put(apiVersion, client);
\r
107 * Use this API when you have permission to have your call act as the end client's ID.
\r
109 * Your calls will get 403 errors if you do not have this permission. it is a special setup, rarely given.
\r
111 * @param apiVersion
\r
114 * @throws CadiException
\r
116 public Rcli<CLIENT> clientAs(String apiVersion, ServletRequest req) throws CadiException {
\r
117 Rcli<CLIENT> cl = client(apiVersion);
\r
118 return cl.forUser(transferSS(((HttpServletRequest)req).getUserPrincipal()));
\r
121 protected AAFCon(AAFCon<CLIENT> copy) {
\r
122 access = copy.access;
\r
123 timeout = copy.timeout;
\r
124 cleanInterval = copy.cleanInterval;
\r
125 connTimeout = copy.connTimeout;
\r
126 highCount = copy.highCount;
\r
127 userExpires = copy.userExpires;
\r
128 usageRefreshTriggerCount = copy.usageRefreshTriggerCount;
\r
129 permsDF = copy.permsDF;
\r
130 certsDF = copy.certsDF;
\r
131 usersDF = copy.usersDF;
\r
132 errDF = copy.errDF;
\r
137 disableCheck = copy.disableCheck;
\r
138 realm = copy.realm;
\r
141 protected AAFCon(PropAccess access, String tag, SecurityInfoC<CLIENT> si) throws CadiException{
\r
143 throw new CadiException("AAFCon cannot be constructed with a tag=null");
\r
146 this.access = access;
\r
148 this.ss = si.defSS;
\r
150 String mechid = access.getProperty(Config.AAF_MECHID, null);
\r
151 String encpass = access.getProperty(Config.AAF_MECHPASS, null);
\r
152 if(encpass==null) {
\r
153 String alias = access.getProperty(Config.CADI_ALIAS, mechid);
\r
155 throw new CadiException(Config.CADI_ALIAS + " or " + Config.AAF_MECHID + " required.");
\r
157 set(si.defSS=x509Alias(alias));
\r
159 if(mechid!=null && encpass !=null) {
\r
160 set(si.defSS=basicAuth(mechid, encpass));
\r
162 set(si.defSS=new SecuritySetter<CLIENT>() {
\r
165 public String getID() {
\r
170 public void setSecurity(CLIENT client) throws CadiException {
\r
171 throw new CadiException("AAFCon has not been initialized with Credentials (SecuritySetter)");
\r
175 public int setLastResponse(int respCode) {
\r
183 timeout = Integer.parseInt(access.getProperty(Config.AAF_READ_TIMEOUT, Config.AAF_READ_TIMEOUT_DEF));
\r
184 cleanInterval = Integer.parseInt(access.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF));
\r
185 highCount = Integer.parseInt(access.getProperty(Config.AAF_HIGH_COUNT, Config.AAF_HIGH_COUNT_DEF).trim());
\r
186 connTimeout = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF).trim());
\r
187 userExpires = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim());
\r
188 usageRefreshTriggerCount = Integer.parseInt(access.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF).trim())-1; // zero based
\r
190 String str = access.getProperty(tag,null);
\r
192 throw new CadiException(tag + " property is required.");
\r
196 app=reverseDomain(ss.getID());
\r
197 realm="openecomp.org";
\r
199 env = new RosettaEnv();
\r
200 permsDF = env.newDataFactory(Perms.class);
\r
201 usersDF = env.newDataFactory(Users.class);
\r
202 certsDF = env.newDataFactory(Certs.class);
\r
203 certsDF.rootMarshal(new CertsMarshal()); // Speedier Marshaling
\r
204 errDF = env.newDataFactory(Error.class);
\r
205 } catch (APIException e) {
\r
206 throw new CadiException("AAFCon cannot be configured",e);
\r
210 public RosettaEnv env() {
\r
215 * Return the backing AAFCon, if there is a Lur Setup that is AAF.
\r
217 * If there is no AAFLur setup, it will return "null"
\r
218 * @param servletRequest
\r
221 public static final AAFCon<?> obtain(Object servletRequest) {
\r
222 if(servletRequest instanceof CadiWrap) {
\r
223 Lur lur = ((CadiWrap)servletRequest).getLur();
\r
225 if(lur instanceof EpiLur) {
\r
226 AbsAAFLur<?> aal = (AbsAAFLur<?>) ((EpiLur)lur).subLur(AbsAAFLur.class);
\r
231 if(lur instanceof AbsAAFLur) {
\r
232 return ((AbsAAFLur<?>)lur).aaf;
\r
240 public abstract AAFCon<CLIENT> clone(String url) throws CadiException;
\r
242 public AAFAuthn<CLIENT> newAuthn() throws APIException {
\r
244 return new AAFAuthn<CLIENT>(this);
\r
245 } catch (APIException e) {
\r
247 } catch (Exception e) {
\r
248 throw new APIException(e);
\r
252 public AAFAuthn<CLIENT> newAuthn(AbsUserCache<AAFPermission> c) throws APIException {
\r
254 return new AAFAuthn<CLIENT>(this,c);
\r
255 } catch (APIException e) {
\r
257 } catch (Exception e) {
\r
258 throw new APIException(e);
\r
262 public AAFLurPerm newLur() throws CadiException {
\r
265 return new AAFLurPerm(this);
\r
267 return new AAFLurPerm(this,lur);
\r
269 } catch (CadiException e) {
\r
271 } catch (Exception e) {
\r
272 throw new CadiException(e);
\r
276 public AAFLurPerm newLur(AbsUserCache<AAFPermission> c) throws APIException {
\r
278 return new AAFLurPerm(this,c);
\r
279 } catch (APIException e) {
\r
281 } catch (Exception e) {
\r
282 throw new APIException(e);
\r
287 * Take a Fully Qualified User, and get a Namespace from it.
\r
291 public static String reverseDomain(String user) {
\r
292 StringBuilder sb = null;
\r
293 String[] split = Split.split('.',user);
\r
295 for(int i=split.length-1;i>=0;--i) {
\r
297 sb = new StringBuilder();
\r
302 if((at = split[i].indexOf('@'))>0) {
\r
303 sb.append(split[i].subSequence(at+1, split[i].length()));
\r
305 sb.append(split[i]);
\r
309 return sb==null?"":sb.toString();
\r
312 protected abstract Rcli<CLIENT> rclient(URI uri, SecuritySetter<CLIENT> ss) throws CadiException;
\r
314 public abstract<RET> RET best(Retryable<RET> retryable) throws LocatorException, CadiException, APIException;
\r
317 public abstract SecuritySetter<CLIENT> basicAuth(String user, String password) throws CadiException;
\r
319 public abstract SecuritySetter<CLIENT> transferSS(Principal principal) throws CadiException;
\r
321 public abstract SecuritySetter<CLIENT> basicAuthSS(BasicPrincipal principal) throws CadiException;
\r
323 public abstract SecuritySetter<CLIENT> x509Alias(String alias) throws APIException, CadiException;
\r
326 public String getRealm() {
\r
331 public SecuritySetter<CLIENT> set(final SecuritySetter<CLIENT> ss) {
\r
333 if(ss instanceof AbsBasicAuth) {
\r
334 disableCheck = (ss instanceof AbsBasicAuth)?
\r
335 new DisableCheck() {
\r
336 AbsBasicAuth<?> aba = (AbsBasicAuth<?>)ss;
\r
338 public boolean isDisabled() {
\r
339 return aba.isDenied();
\r
342 new DisableCheck() {
\r
344 public boolean isDisabled() {
\r
345 return this.isDisabled();
\r
349 for(Rcli<CLIENT> client : clients.values()) {
\r
350 client.setSecuritySetter(ss);
\r
355 public SecurityInfoC<CLIENT> securityInfo() {
\r
359 public String defID() {
\r
366 public void invalidate() throws CadiException {
\r
367 for(Rcli<CLIENT> client : clients.values()) {
\r
368 client.invalidate();
\r
369 clients.remove(client);
\r
373 public String readableErrMsg(Future<?> f) {
\r
374 String text = f.body();
\r
375 if(text==null || text.length()==0) {
\r
376 text = f.code() + ": **No Message**";
\r
377 } else if(text.contains("%")) {
\r
379 Error err = errDF.newData().in(TYPE.JSON).load(f.body()).asObject();
\r
380 return Vars.convert(err.getText(),err.getVariables());
\r
381 } catch (APIException e){
\r
382 // just return the body below
\r
388 private interface DisableCheck {
\r
389 public boolean isDisabled();
\r
392 public boolean isDisabled() {
\r
393 return disableCheck.isDisabled();
\r