[AAF-21] Updated Copyright Headers for AAF
[aaf/authz.git] / authz-gw / src / main / java / com / att / authz / gw / api / API_AAFAccess.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\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
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \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
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package com.att.authz.gw.api;\r
24 \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
30 \r
31 import javax.servlet.ServletOutputStream;\r
32 import javax.servlet.http.HttpServletRequest;\r
33 import javax.servlet.http.HttpServletResponse;\r
34 \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
57 \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
63         \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
69         \r
70 //      private static String service, version, envContext; \r
71         private static String routeOffer;\r
72 \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
77         \r
78         /**\r
79          * Normal Init level APIs\r
80          * \r
81          * @param gwAPI\r
82          * @param facade\r
83          * @throws Exception\r
84          */\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
88                 \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
93                         switch(count) {\r
94                                 case 2:\r
95 //                                      service = gwAPI.aafurl.substring(equals, slash);\r
96                                         break;\r
97                                 case 3:\r
98 //                                      version = gwAPI.aafurl.substring(equals, slash);\r
99                                         break;\r
100                                 case 4:\r
101 //                                      envContext = gwAPI.aafurl.substring(equals, slash);\r
102                                         break;\r
103                                 case 5:\r
104                                         routeOffer = gwAPI.aafurl.substring(equals);\r
105                                         break;\r
106                         }\r
107                 }\r
108                 if(count<6) throw new MalformedURLException(gwAPI.aafurl);\r
109                 \r
110                 gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new GwCode(facade,GET_PERMS_BY_USER, true) {\r
111                         @Override\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
114                                 try {\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
119                                                 return;\r
120                                         }\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
123                                         Dated d;\r
124                                         try {\r
125                                                 d = gwAPI.cacheUser.get(key);\r
126                                         } finally {\r
127                                                 tt2.done();\r
128                                         }\r
129                                         \r
130                                         if(d==null || d.data.isEmpty()) {\r
131                                                 tt2 = trans.start("AAF Service Call",Env.REMOTE);\r
132                                                 try {\r
133                                                         gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {\r
134                                                                 @Override\r
135                                                                 public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {\r
136                                                                         Future<String> fp = client.read("/authz/perms/user/"+user,accept);\r
137                                                                         if(fp.get(5000)) {\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
141                                                                                 try {\r
142                                                                                         sos = resp.getOutputStream();\r
143                                                                                         sos.print(fp.value);\r
144                                                                                 } catch (IOException e) {\r
145                                                                                         throw new CadiException(e);\r
146                                                                                 }\r
147                                                                         } else {\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
150                                                                         }\r
151                                                                         return null;\r
152                                                                 }\r
153                                                         });\r
154                                                 } finally {\r
155                                                         tt2.done();\r
156                                                 }\r
157                                         } else {\r
158                                                 User u = (User)d.data.get(0);\r
159                                                 resp.setStatus(u.code);\r
160                                                 ServletOutputStream sos = resp.getOutputStream();\r
161                                                 sos.print(u.resp);\r
162                                         }\r
163                                 } finally {\r
164                                         tt.done();\r
165                                 }\r
166                         }\r
167                 });\r
168 \r
169                 gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new GwCode(facade,BASIC_AUTH, true) {\r
170                         @Override\r
171                         public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
172                                 Principal p = trans.getUserPrincipal();\r
173                                 if(p == null) {\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
180                                 } else {\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
184                                 }\r
185                         }\r
186                 },"text/plain","*/*","*");\r
187 \r
188                 /**\r
189                  * Query User Has Perm\r
190                  */\r
191                 gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new GwCode(facade,USER_HAS_PERM, true) {\r
192                         @Override\r
193                         public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
194                                 try {\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
203                                 }\r
204                         }\r
205                 });\r
206 \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
209                                 @Override\r
210                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
211                                         try{\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
219                                         }\r
220                                 }\r
221                         });\r
222 \r
223                         gwAPI.route(HttpMethods.GET,"/test/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access TEST GUI for AAF", true) {\r
224                                 @Override\r
225                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
226                                         try{\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
234                                         }\r
235                                 }\r
236                         });\r
237 \r
238                         gwAPI.route(HttpMethods.GET,"/perf/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access PERF GUI for AAF", true) {\r
239                                 @Override\r
240                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
241                                         try{\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
249                                         }\r
250                                 }\r
251                         });\r
252 \r
253                         gwAPI.route(HttpMethods.GET,"/dev/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access DEV GUI for AAF", true) {\r
254                                 @Override\r
255                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
256                                         try {\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
264                                         }\r
265                                 }\r
266                         });\r
267                 } else {\r
268                         gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access PROD GUI for AAF", true) {\r
269                                 @Override\r
270                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
271                                         try {\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
279                                         }\r
280                                 }\r
281                         });\r
282                 }\r
283                 \r
284         }\r
285         \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
289         \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
292 \r
293                 /**\r
294                  * "login" url\r
295                  */\r
296                 gwAPI.route(HttpMethods.GET,"/login",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {\r
297                         @Override\r
298                         public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
299                                 try {\r
300                                         redirect(trans, req, resp, context, \r
301                                                         new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer), \r
302                                                         "login");\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
307                                 }\r
308                         }\r
309                 });\r
310 \r
311                 /**\r
312                  * Default URL\r
313                  */\r
314                 gwAPI.route(HttpMethods.GET,"/",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {\r
315                         @Override\r
316                         public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
317                                 try {\r
318                                         redirect(trans, req, resp, context, \r
319                                                         new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer), \r
320                                                         "gui/home");\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
325                                 }\r
326                         }\r
327                 });\r
328         }\r
329 \r
330         private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, GwFacade context, Locator loc, String path) throws IOException {\r
331                 try {\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
339                                 if(str!=null) {\r
340                                         redirectURL.append('?');\r
341                                         redirectURL.append(str);\r
342                                 }\r
343                                 trans.info().log("Redirect to",redirectURL);\r
344                                 resp.sendRedirect(redirectURL.toString());\r
345                         } else {\r
346                                 context.error(trans, resp, Result.err(Result.ERR_NotFound,"%s is not valid",req.getPathInfo()));\r
347                         }\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
350                 }\r
351         }\r
352 \r
353         private static class User {\r
354                 public final int code;\r
355                 public final String resp;\r
356                 \r
357                 public User(int code, String resp) {\r
358                         this.code = code;\r
359                         this.resp = resp;\r
360                 }\r
361         }\r
362 }\r