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.authz.gw.api;
\r
25 import java.io.IOException;
\r
26 import java.net.ConnectException;
\r
27 import java.net.MalformedURLException;
\r
28 import java.net.URI;
\r
29 import java.security.Principal;
\r
31 import javax.servlet.ServletOutputStream;
\r
32 import javax.servlet.http.HttpServletRequest;
\r
33 import javax.servlet.http.HttpServletResponse;
\r
35 import org.onap.aaf.authz.env.AuthzTrans;
\r
36 import org.onap.aaf.authz.gw.GwAPI;
\r
37 import org.onap.aaf.authz.gw.GwCode;
\r
38 import org.onap.aaf.authz.gw.facade.GwFacade;
\r
39 import org.onap.aaf.authz.gw.mapper.Mapper.API;
\r
40 import org.onap.aaf.authz.layer.Result;
\r
41 import org.onap.aaf.cache.Cache.Dated;
\r
42 import org.onap.aaf.cssa.rserv.HttpMethods;
\r
44 import com.att.aft.dme2.internal.jetty.http.HttpStatus;
\r
45 import org.onap.aaf.cadi.CadiException;
\r
46 import org.onap.aaf.cadi.Locator;
\r
47 import org.onap.aaf.cadi.Locator.Item;
\r
48 import org.onap.aaf.cadi.LocatorException;
\r
49 import org.onap.aaf.cadi.aaf.AAFPermission;
\r
50 import org.onap.aaf.cadi.client.Future;
\r
51 import org.onap.aaf.cadi.client.Rcli;
\r
52 import org.onap.aaf.cadi.client.Retryable;
\r
53 import org.onap.aaf.cadi.dme2.DME2Locator;
\r
54 import org.onap.aaf.cadi.principal.BasicPrincipal;
\r
55 import org.onap.aaf.inno.env.APIException;
\r
56 import org.onap.aaf.inno.env.Env;
\r
57 import org.onap.aaf.inno.env.TimeTaken;
\r
59 public class API_AAFAccess {
\r
60 private static final String AUTHZ_DME2_GUI = "com.att.authz.authz-gui";
\r
61 static final String AFT_ENVIRONMENT="AFT_ENVIRONMENT";
\r
62 static final String AFT_ENV_CONTEXT="AFT_ENV_CONTEXT";
\r
63 static final String AFTUAT="AFTUAT";
\r
65 private static final String PROD = "PROD";
\r
66 private static final String IST = "IST"; // main NONPROD system
\r
67 private static final String PERF = "PERF";
\r
68 private static final String TEST = "TEST";
\r
69 private static final String DEV = "DEV";
\r
71 // private static String service, version, envContext;
\r
72 private static String routeOffer;
\r
74 private static final String GET_PERMS_BY_USER = "Get Perms by User";
\r
75 private static final String USER_HAS_PERM ="User Has Perm";
\r
76 // private static final String USER_IN_ROLE ="User Has Role";
\r
77 private static final String BASIC_AUTH ="AAF Basic Auth";
\r
80 * Normal Init level APIs
\r
86 public static void init(final GwAPI gwAPI, GwFacade facade) throws Exception {
\r
87 String aftenv = gwAPI.env.getProperty(AFT_ENVIRONMENT);
\r
88 if(aftenv==null) throw new Exception(AFT_ENVIRONMENT + " must be set");
\r
90 int equals, count=0;
\r
91 for(int slash = gwAPI.aafurl.indexOf('/');slash>0;++count) {
\r
92 equals = gwAPI.aafurl.indexOf('=',slash)+1;
\r
93 slash = gwAPI.aafurl.indexOf('/',slash+1);
\r
96 // service = gwAPI.aafurl.substring(equals, slash);
\r
99 // version = gwAPI.aafurl.substring(equals, slash);
\r
102 // envContext = gwAPI.aafurl.substring(equals, slash);
\r
105 routeOffer = gwAPI.aafurl.substring(equals);
\r
109 if(count<6) throw new MalformedURLException(gwAPI.aafurl);
\r
111 gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new GwCode(facade,GET_PERMS_BY_USER, true) {
\r
113 public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
\r
114 TimeTaken tt = trans.start(GET_PERMS_BY_USER, Env.SUB);
\r
116 final String accept = req.getHeader("ACCEPT");
\r
117 final String user = pathParam(req,":user");
\r
118 if(!user.contains("@")) {
\r
119 context.error(trans,resp,Result.ERR_BadData,"User [%s] must be fully qualified with domain",user);
\r
122 String key = trans.user() + user + (accept!=null&&accept.contains("xml")?"-xml":"-json");
\r
123 TimeTaken tt2 = trans.start("Cache Lookup",Env.SUB);
\r
126 d = gwAPI.cacheUser.get(key);
\r
131 if(d==null || d.data.isEmpty()) {
\r
132 tt2 = trans.start("AAF Service Call",Env.REMOTE);
\r
134 gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
\r
136 public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
\r
137 Future<String> fp = client.read("/authz/perms/user/"+user,accept);
\r
139 gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body())));
\r
140 resp.setStatus(HttpStatus.OK_200);
\r
141 ServletOutputStream sos;
\r
143 sos = resp.getOutputStream();
\r
144 sos.print(fp.value);
\r
145 } catch (IOException e) {
\r
146 throw new CadiException(e);
\r
149 gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body())));
\r
150 context.error(trans,resp,fp.code(),fp.body());
\r
159 User u = (User)d.data.get(0);
\r
160 resp.setStatus(u.code);
\r
161 ServletOutputStream sos = resp.getOutputStream();
\r
170 gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new GwCode(facade,BASIC_AUTH, true) {
\r
172 public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
173 Principal p = trans.getUserPrincipal();
\r
175 trans.error().log("Transaction not Authenticated... no Principal");
\r
176 resp.setStatus(HttpStatus.FORBIDDEN_403);
\r
177 } else if (p instanceof BasicPrincipal) {
\r
178 // the idea is that if call is made with this credential, and it's a BasicPrincipal, it's ok
\r
179 // otherwise, it wouldn't have gotten here.
\r
180 resp.setStatus(HttpStatus.OK_200);
\r
182 trans.checkpoint("Basic Auth Check Failed: This wasn't a Basic Auth Trans");
\r
183 // For Auth Security questions, we don't give any info to client on why failed
\r
184 resp.setStatus(HttpStatus.FORBIDDEN_403);
\r
187 },"text/plain","*/*","*");
\r
190 * Query User Has Perm
\r
192 gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new GwCode(facade,USER_HAS_PERM, true) {
\r
194 public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
196 resp.getOutputStream().print(
\r
197 gwAPI.aafLurPerm.fish(pathParam(req,":user"), new AAFPermission(
\r
198 pathParam(req,":type"),
\r
199 pathParam(req,":instance"),
\r
200 pathParam(req,":action"))));
\r
201 resp.setStatus(HttpStatus.OK_200);
\r
202 } catch(Exception e) {
\r
203 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
208 if(AFTUAT.equals(aftenv)) {
\r
209 gwAPI.route(HttpMethods.GET,"/ist/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access UAT GUI for AAF", true) {
\r
211 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
213 redirect(trans, req, resp, context,
\r
214 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), IST, routeOffer),
\r
215 pathParam(req,":path"));
\r
216 } catch (LocatorException e) {
\r
217 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
218 } catch (Exception e) {
\r
219 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
224 gwAPI.route(HttpMethods.GET,"/test/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access TEST GUI for AAF", true) {
\r
226 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
228 redirect(trans, req, resp, context,
\r
229 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), TEST, routeOffer),
\r
230 pathParam(req,":path"));
\r
231 } catch (LocatorException e) {
\r
232 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
233 } catch (Exception e) {
\r
234 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
239 gwAPI.route(HttpMethods.GET,"/perf/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access PERF GUI for AAF", true) {
\r
241 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
243 redirect(trans, req, resp, context,
\r
244 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), PERF, routeOffer),
\r
245 pathParam(req,":path"));
\r
246 } catch (LocatorException e) {
\r
247 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
248 } catch (Exception e) {
\r
249 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
254 gwAPI.route(HttpMethods.GET,"/dev/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access DEV GUI for AAF", true) {
\r
256 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
258 redirect(trans, req, resp, context,
\r
259 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), DEV, routeOffer),
\r
260 pathParam(req,":path"));
\r
261 } catch (LocatorException e) {
\r
262 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
263 } catch (Exception e) {
\r
264 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
269 gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access PROD GUI for AAF", true) {
\r
271 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
273 redirect(trans, req, resp, context,
\r
274 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), PROD, routeOffer),
\r
275 pathParam(req,":path"));
\r
276 } catch (LocatorException e) {
\r
277 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
278 } catch (Exception e) {
\r
279 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
287 public static void initDefault(final GwAPI gwAPI, GwFacade facade) throws Exception {
\r
288 String aftenv = gwAPI.env.getProperty(AFT_ENVIRONMENT);
\r
289 if(aftenv==null) throw new Exception(AFT_ENVIRONMENT + " must be set");
\r
291 String aftctx = gwAPI.env.getProperty(AFT_ENV_CONTEXT);
\r
292 if(aftctx==null) throw new Exception(AFT_ENV_CONTEXT + " must be set");
\r
297 gwAPI.route(HttpMethods.GET,"/login",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {
\r
299 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
301 redirect(trans, req, resp, context,
\r
302 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer),
\r
304 } catch (LocatorException e) {
\r
305 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
306 } catch (Exception e) {
\r
307 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
315 gwAPI.route(HttpMethods.GET,"/",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {
\r
317 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
319 redirect(trans, req, resp, context,
\r
320 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer),
\r
322 } catch (LocatorException e) {
\r
323 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
324 } catch (Exception e) {
\r
325 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
331 private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, GwFacade context, Locator loc, String path) throws IOException {
\r
333 if(loc.hasItems()) {
\r
334 Item item = loc.best();
\r
335 URI uri = (URI) loc.get(item);
\r
336 StringBuilder redirectURL = new StringBuilder(uri.toString());
\r
337 redirectURL.append('/');
\r
338 redirectURL.append(path);
\r
339 String str = req.getQueryString();
\r
341 redirectURL.append('?');
\r
342 redirectURL.append(str);
\r
344 trans.info().log("Redirect to",redirectURL);
\r
345 resp.sendRedirect(redirectURL.toString());
\r
347 context.error(trans, resp, Result.err(Result.ERR_NotFound,"%s is not valid",req.getPathInfo()));
\r
349 } catch (LocatorException e) {
\r
350 context.error(trans, resp, Result.err(Result.ERR_NotFound,"No DME2 Endpoints found for %s",req.getPathInfo()));
\r
354 private static class User {
\r
355 public final int code;
\r
356 public final String resp;
\r
358 public User(int code, String resp) {
\r