AT&T 2.0.19 Code drop, stage 4
[aaf/authz.git] / authz-gw / src / main / java / org / onap / aaf / 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 org.onap.aaf.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 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
43 \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
58 \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
64         \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
70         \r
71 //      private static String service, version, envContext; \r
72         private static String routeOffer;\r
73 \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
78         \r
79         /**\r
80          * Normal Init level APIs\r
81          * \r
82          * @param gwAPI\r
83          * @param facade\r
84          * @throws Exception\r
85          */\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
89                 \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
94                         switch(count) {\r
95                                 case 2:\r
96 //                                      service = gwAPI.aafurl.substring(equals, slash);\r
97                                         break;\r
98                                 case 3:\r
99 //                                      version = gwAPI.aafurl.substring(equals, slash);\r
100                                         break;\r
101                                 case 4:\r
102 //                                      envContext = gwAPI.aafurl.substring(equals, slash);\r
103                                         break;\r
104                                 case 5:\r
105                                         routeOffer = gwAPI.aafurl.substring(equals);\r
106                                         break;\r
107                         }\r
108                 }\r
109                 if(count<6) throw new MalformedURLException(gwAPI.aafurl);\r
110                 \r
111                 gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new GwCode(facade,GET_PERMS_BY_USER, true) {\r
112                         @Override\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
115                                 try {\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
120                                                 return;\r
121                                         }\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
124                                         Dated d;\r
125                                         try {\r
126                                                 d = gwAPI.cacheUser.get(key);\r
127                                         } finally {\r
128                                                 tt2.done();\r
129                                         }\r
130                                         \r
131                                         if(d==null || d.data.isEmpty()) {\r
132                                                 tt2 = trans.start("AAF Service Call",Env.REMOTE);\r
133                                                 try {\r
134                                                         gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {\r
135                                                                 @Override\r
136                                                                 public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {\r
137                                                                         Future<String> fp = client.read("/authz/perms/user/"+user,accept);\r
138                                                                         if(fp.get(5000)) {\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
142                                                                                 try {\r
143                                                                                         sos = resp.getOutputStream();\r
144                                                                                         sos.print(fp.value);\r
145                                                                                 } catch (IOException e) {\r
146                                                                                         throw new CadiException(e);\r
147                                                                                 }\r
148                                                                         } else {\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
151                                                                         }\r
152                                                                         return null;\r
153                                                                 }\r
154                                                         });\r
155                                                 } finally {\r
156                                                         tt2.done();\r
157                                                 }\r
158                                         } else {\r
159                                                 User u = (User)d.data.get(0);\r
160                                                 resp.setStatus(u.code);\r
161                                                 ServletOutputStream sos = resp.getOutputStream();\r
162                                                 sos.print(u.resp);\r
163                                         }\r
164                                 } finally {\r
165                                         tt.done();\r
166                                 }\r
167                         }\r
168                 });\r
169 \r
170                 gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new GwCode(facade,BASIC_AUTH, true) {\r
171                         @Override\r
172                         public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
173                                 Principal p = trans.getUserPrincipal();\r
174                                 if(p == null) {\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
181                                 } else {\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
185                                 }\r
186                         }\r
187                 },"text/plain","*/*","*");\r
188 \r
189                 /**\r
190                  * Query User Has Perm\r
191                  */\r
192                 gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new GwCode(facade,USER_HAS_PERM, true) {\r
193                         @Override\r
194                         public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
195                                 try {\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
204                                 }\r
205                         }\r
206                 });\r
207 \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
210                                 @Override\r
211                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
212                                         try{\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
220                                         }\r
221                                 }\r
222                         });\r
223 \r
224                         gwAPI.route(HttpMethods.GET,"/test/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access TEST GUI for AAF", true) {\r
225                                 @Override\r
226                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
227                                         try{\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
235                                         }\r
236                                 }\r
237                         });\r
238 \r
239                         gwAPI.route(HttpMethods.GET,"/perf/aaf/:version/:path*",API.VOID ,new GwCode(facade,"Access PERF GUI for AAF", true) {\r
240                                 @Override\r
241                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
242                                         try{\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
250                                         }\r
251                                 }\r
252                         });\r
253 \r
254                         gwAPI.route(HttpMethods.GET,"/dev/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access DEV GUI for AAF", true) {\r
255                                 @Override\r
256                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
257                                         try {\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
265                                         }\r
266                                 }\r
267                         });\r
268                 } else {\r
269                         gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new GwCode(facade,"Access PROD GUI for AAF", true) {\r
270                                 @Override\r
271                                 public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
272                                         try {\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
280                                         }\r
281                                 }\r
282                         });\r
283                 }\r
284                 \r
285         }\r
286         \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
290         \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
293 \r
294                 /**\r
295                  * "login" url\r
296                  */\r
297                 gwAPI.route(HttpMethods.GET,"/login",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {\r
298                         @Override\r
299                         public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
300                                 try {\r
301                                         redirect(trans, req, resp, context, \r
302                                                         new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer), \r
303                                                         "login");\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
308                                 }\r
309                         }\r
310                 });\r
311 \r
312                 /**\r
313                  * Default URL\r
314                  */\r
315                 gwAPI.route(HttpMethods.GET,"/",API.VOID,new GwCode(facade,"Access " + aftctx + " GUI for AAF", true) {\r
316                         @Override\r
317                         public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {\r
318                                 try {\r
319                                         redirect(trans, req, resp, context, \r
320                                                         new DME2Locator(gwAPI.env, gwAPI.dme2Man, AUTHZ_DME2_GUI, "2.0", aftctx, routeOffer), \r
321                                                         "gui/home");\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
326                                 }\r
327                         }\r
328                 });\r
329         }\r
330 \r
331         private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, GwFacade context, Locator loc, String path) throws IOException {\r
332                 try {\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
340                                 if(str!=null) {\r
341                                         redirectURL.append('?');\r
342                                         redirectURL.append(str);\r
343                                 }\r
344                                 trans.info().log("Redirect to",redirectURL);\r
345                                 resp.sendRedirect(redirectURL.toString());\r
346                         } else {\r
347                                 context.error(trans, resp, Result.err(Result.ERR_NotFound,"%s is not valid",req.getPathInfo()));\r
348                         }\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
351                 }\r
352         }\r
353 \r
354         private static class User {\r
355                 public final int code;\r
356                 public final String resp;\r
357                 \r
358                 public User(int code, String resp) {\r
359                         this.code = code;\r
360                         this.resp = resp;\r
361                 }\r
362         }\r
363 }\r