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.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 com.att.aft.dme2.internal.jetty.http.HttpStatus;
\r
36 import com.att.authz.env.AuthzTrans;
\r
37 import com.att.authz.gw.GwAPI;
\r
38 import com.att.authz.gw.GwCode;
\r
39 import com.att.authz.gw.facade.GwFacade;
\r
40 import com.att.authz.gw.mapper.Mapper.API;
\r
41 import com.att.authz.layer.Result;
\r
42 import com.att.cache.Cache.Dated;
\r
43 import com.att.cadi.CadiException;
\r
44 import com.att.cadi.Locator;
\r
45 import com.att.cadi.Locator.Item;
\r
46 import com.att.cadi.LocatorException;
\r
47 import com.att.cadi.aaf.AAFPermission;
\r
48 import com.att.cadi.client.Future;
\r
49 import com.att.cadi.client.Rcli;
\r
50 import com.att.cadi.client.Retryable;
\r
51 import com.att.cadi.dme2.DME2Locator;
\r
52 import com.att.cadi.principal.BasicPrincipal;
\r
53 import com.att.cssa.rserv.HttpMethods;
\r
54 import com.att.inno.env.APIException;
\r
55 import com.att.inno.env.Env;
\r
56 import com.att.inno.env.TimeTaken;
\r
58 public class API_AAFAccess {
\r
59 private static final String AUTHZ_DME2_GUI = "com.att.authz.authz-gui";
\r
60 static final String AFT_ENVIRONMENT="AFT_ENVIRONMENT";
\r
61 static final String AFT_ENV_CONTEXT="AFT_ENV_CONTEXT";
\r
62 static final String AFTUAT="AFTUAT";
\r
64 private static final String PROD = "PROD";
\r
65 private static final String IST = "IST"; // main NONPROD system
\r
66 private static final String PERF = "PERF";
\r
67 private static final String TEST = "TEST";
\r
68 private static final String DEV = "DEV";
\r
70 // private static String service, version, envContext;
\r
71 private static String routeOffer;
\r
73 private static final String GET_PERMS_BY_USER = "Get Perms by User";
\r
74 private static final String USER_HAS_PERM ="User Has Perm";
\r
75 // private static final String USER_IN_ROLE ="User Has Role";
\r
76 private static final String BASIC_AUTH ="AAF Basic Auth";
\r
79 * Normal Init level APIs
\r
85 public static void init(final GwAPI gwAPI, GwFacade facade) throws Exception {
\r
86 String aftenv = gwAPI.env.getProperty(AFT_ENVIRONMENT);
\r
87 if(aftenv==null) throw new Exception(AFT_ENVIRONMENT + " must be set");
\r
89 int equals, count=0;
\r
90 for(int slash = gwAPI.aafurl.indexOf('/');slash>0;++count) {
\r
91 equals = gwAPI.aafurl.indexOf('=',slash)+1;
\r
92 slash = gwAPI.aafurl.indexOf('/',slash+1);
\r
95 // service = gwAPI.aafurl.substring(equals, slash);
\r
98 // version = gwAPI.aafurl.substring(equals, slash);
\r
101 // envContext = gwAPI.aafurl.substring(equals, slash);
\r
104 routeOffer = gwAPI.aafurl.substring(equals);
\r
108 if(count<6) throw new MalformedURLException(gwAPI.aafurl);
\r
110 gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new GwCode(facade,GET_PERMS_BY_USER, true) {
\r
112 public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
\r
113 TimeTaken tt = trans.start(GET_PERMS_BY_USER, Env.SUB);
\r
115 final String accept = req.getHeader("ACCEPT");
\r
116 final String user = pathParam(req,":user");
\r
117 if(!user.contains("@")) {
\r
118 context.error(trans,resp,Result.ERR_BadData,"User [%s] must be fully qualified with domain",user);
\r
121 String key = trans.user() + user + (accept!=null&&accept.contains("xml")?"-xml":"-json");
\r
122 TimeTaken tt2 = trans.start("Cache Lookup",Env.SUB);
\r
125 d = gwAPI.cacheUser.get(key);
\r
130 if(d==null || d.data.isEmpty()) {
\r
131 tt2 = trans.start("AAF Service Call",Env.REMOTE);
\r
133 gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
\r
135 public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
\r
136 Future<String> fp = client.read("/authz/perms/user/"+user,accept);
\r
138 gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body())));
\r
139 resp.setStatus(HttpStatus.OK_200);
\r
140 ServletOutputStream sos;
\r
142 sos = resp.getOutputStream();
\r
143 sos.print(fp.value);
\r
144 } catch (IOException e) {
\r
145 throw new CadiException(e);
\r
148 gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body())));
\r
149 context.error(trans,resp,fp.code(),fp.body());
\r
158 User u = (User)d.data.get(0);
\r
159 resp.setStatus(u.code);
\r
160 ServletOutputStream sos = resp.getOutputStream();
\r
169 gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new GwCode(facade,BASIC_AUTH, true) {
\r
171 public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
172 Principal p = trans.getUserPrincipal();
\r
174 trans.error().log("Transaction not Authenticated... no Principal");
\r
175 resp.setStatus(HttpStatus.FORBIDDEN_403);
\r
176 } else if (p instanceof BasicPrincipal) {
\r
177 // the idea is that if call is made with this credential, and it's a BasicPrincipal, it's ok
\r
178 // otherwise, it wouldn't have gotten here.
\r
179 resp.setStatus(HttpStatus.OK_200);
\r
181 trans.checkpoint("Basic Auth Check Failed: This wasn't a Basic Auth Trans");
\r
182 // For Auth Security questions, we don't give any info to client on why failed
\r
183 resp.setStatus(HttpStatus.FORBIDDEN_403);
\r
186 },"text/plain","*/*","*");
\r
189 * Query User Has Perm
\r
191 gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new GwCode(facade,USER_HAS_PERM, true) {
\r
193 public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
195 resp.getOutputStream().print(
\r
196 gwAPI.aafLurPerm.fish(pathParam(req,":user"), new AAFPermission(
\r
197 pathParam(req,":type"),
\r
198 pathParam(req,":instance"),
\r
199 pathParam(req,":action"))));
\r
200 resp.setStatus(HttpStatus.OK_200);
\r
201 } catch(Exception e) {
\r
202 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
207 if(AFTUAT.equals(aftenv)) {
\r
208 gwAPI.route(HttpMethods.GET,"/ist/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access UAT GUI for AAF", true) {
\r
210 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
212 redirect(trans, req, resp, context,
\r
213 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), IST, routeOffer),
\r
214 pathParam(req,":path"));
\r
215 } catch (LocatorException e) {
\r
216 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
217 } catch (Exception e) {
\r
218 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
223 gwAPI.route(HttpMethods.GET,"/test/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access TEST GUI for AAF", true) {
\r
225 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
227 redirect(trans, req, resp, context,
\r
228 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), TEST, routeOffer),
\r
229 pathParam(req,":path"));
\r
230 } catch (LocatorException e) {
\r
231 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
232 } catch (Exception e) {
\r
233 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
238 gwAPI.route(HttpMethods.GET,"/perf/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access PERF GUI for AAF", true) {
\r
240 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
242 redirect(trans, req, resp, context,
\r
243 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), PERF, routeOffer),
\r
244 pathParam(req,":path"));
\r
245 } catch (LocatorException e) {
\r
246 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
247 } catch (Exception e) {
\r
248 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
253 gwAPI.route(HttpMethods.GET,"/dev/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access DEV GUI for AAF", true) {
\r
255 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
257 redirect(trans, req, resp, context,
\r
258 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), DEV, routeOffer),
\r
259 pathParam(req,":path"));
\r
260 } catch (LocatorException e) {
\r
261 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
262 } catch (Exception e) {
\r
263 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
268 gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access PROD GUI for AAF", true) {
\r
270 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
272 redirect(trans, req, resp, context,
\r
273 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, pathParam(req,":version"), PROD, routeOffer),
\r
274 pathParam(req,":path"));
\r
275 } catch (LocatorException e) {
\r
276 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
277 } catch (Exception e) {
\r
278 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
286 public static void initDefault(final GwAPI gwAPI, GwFacade facade) throws Exception {
\r
287 String aftenv = gwAPI.env.getProperty(AFT_ENVIRONMENT);
\r
288 if(aftenv==null) throw new Exception(AFT_ENVIRONMENT + " must be set");
\r
290 String aftctx = gwAPI.env.getProperty(AFT_ENV_CONTEXT);
\r
291 if(aftctx==null) throw new Exception(AFT_ENV_CONTEXT + " must be set");
\r
296 gwAPI.route(HttpMethods.GET,"/login",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {
\r
298 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
300 redirect(trans, req, resp, context,
\r
301 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer),
\r
303 } catch (LocatorException e) {
\r
304 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
305 } catch (Exception e) {
\r
306 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
314 gwAPI.route(HttpMethods.GET,"/",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {
\r
316 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
\r
318 redirect(trans, req, resp, context,
\r
319 new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer),
\r
321 } catch (LocatorException e) {
\r
322 context.error(trans, resp, Result.ERR_BadData, e.getMessage());
\r
323 } catch (Exception e) {
\r
324 context.error(trans, resp, Result.ERR_General, e.getMessage());
\r
330 private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, GwFacade context, Locator loc, String path) throws IOException {
\r
332 if(loc.hasItems()) {
\r
333 Item item = loc.best();
\r
334 URI uri = (URI) loc.get(item);
\r
335 StringBuilder redirectURL = new StringBuilder(uri.toString());
\r
336 redirectURL.append('/');
\r
337 redirectURL.append(path);
\r
338 String str = req.getQueryString();
\r
340 redirectURL.append('?');
\r
341 redirectURL.append(str);
\r
343 trans.info().log("Redirect to",redirectURL);
\r
344 resp.sendRedirect(redirectURL.toString());
\r
346 context.error(trans, resp, Result.err(Result.ERR_NotFound,"%s is not valid",req.getPathInfo()));
\r
348 } catch (LocatorException e) {
\r
349 context.error(trans, resp, Result.err(Result.ERR_NotFound,"No DME2 Endpoints found for %s",req.getPathInfo()));
\r
353 private static class User {
\r
354 public final int code;
\r
355 public final String resp;
\r
357 public User(int code, String resp) {
\r