[AAF-21] Updated Copyright Headers for AAF
[aaf/authz.git] / authz-certman / src / main / java / com / att / authz / cm / facade / FacadeImpl.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.cm.facade;\r
24 \r
25 import static com.att.authz.layer.Result.ERR_ActionNotCompleted;\r
26 import static com.att.authz.layer.Result.ERR_BadData;\r
27 import static com.att.authz.layer.Result.ERR_ConflictAlreadyExists;\r
28 import static com.att.authz.layer.Result.ERR_Denied;\r
29 import static com.att.authz.layer.Result.ERR_NotFound;\r
30 import static com.att.authz.layer.Result.ERR_NotImplemented;\r
31 import static com.att.authz.layer.Result.ERR_Policy;\r
32 import static com.att.authz.layer.Result.ERR_Security;\r
33 import static com.att.authz.layer.Result.OK;\r
34 \r
35 import java.io.IOException;\r
36 \r
37 import javax.servlet.http.HttpServletRequest;\r
38 import javax.servlet.http.HttpServletResponse;\r
39 \r
40 import com.att.authz.cm.api.API_Cert;\r
41 import com.att.authz.cm.ca.CA;\r
42 import com.att.authz.cm.data.CertResp;\r
43 import com.att.authz.cm.mapper.Mapper;\r
44 import com.att.authz.cm.mapper.Mapper.API;\r
45 import com.att.authz.cm.service.CMService;\r
46 import com.att.authz.cm.service.CertManAPI;\r
47 import com.att.authz.env.AuthzEnv;\r
48 import com.att.authz.env.AuthzTrans;\r
49 import com.att.authz.layer.Result;\r
50 import com.att.cadi.aaf.AAFPermission;\r
51 import com.att.dao.aaf.cass.ArtiDAO;\r
52 import com.att.dao.aaf.cass.Status;\r
53 import com.att.inno.env.APIException;\r
54 import com.att.inno.env.Data;\r
55 import com.att.inno.env.Env;\r
56 import com.att.inno.env.Slot;\r
57 import com.att.inno.env.TimeTaken;\r
58 import com.att.inno.env.util.Split;\r
59 import com.att.rosetta.env.RosettaDF;\r
60 import com.att.rosetta.env.RosettaData;\r
61 \r
62 /**\r
63  * AuthzFacade\r
64  * \r
65  * This Service Facade encapsulates the essence of the API Service can do, and provides\r
66  * a single created object for elements such as RosettaDF.\r
67  *\r
68  * The Responsibilities of this class are to:\r
69  * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)\r
70  * 2) Validate incoming data (if applicable)\r
71  * 3) Convert the Service response into the right Format, and mark the Content Type\r
72  *              a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.\r
73  * 4) Log Service info, warnings and exceptions as necessary\r
74  * 5) When asked by the API layer, this will create and write Error content to the OutputStream\r
75  * \r
76  * Note: This Class does NOT set the HTTP Status Code.  That is up to the API layer, so that it can be \r
77  * clearly coordinated with the API Documentation\r
78  * \r
79  *\r
80  */\r
81 public abstract class FacadeImpl<REQ,CERT,ARTIFACTS,ERROR> extends com.att.authz.layer.FacadeImpl implements Facade<REQ,CERT,ARTIFACTS,ERROR> \r
82         {\r
83         private static final String REQUEST_CERT = "Request New Certificate";\r
84         private static final String RENEW_CERT = "Renew Certificate";\r
85         private static final String DROP_CERT = "Drop Certificate";\r
86         private static final String CREATE_ARTIFACTS = "Create Deployment Artifact";\r
87         private static final String READ_ARTIFACTS = "Read Deployment Artifact";\r
88         private static final String UPDATE_ARTIFACTS = "Update Deployment Artifact";\r
89         private static final String DELETE_ARTIFACTS = "Delete Deployment Artifact";\r
90 \r
91         private CMService service;\r
92 \r
93         private final RosettaDF<ERROR>          errDF;\r
94         private final RosettaDF<REQ>            certRequestDF, certRenewDF, certDropDF;\r
95         private final RosettaDF<CERT>           certDF;\r
96         private final RosettaDF<ARTIFACTS>      artiDF;\r
97         private Mapper<REQ, CERT, ARTIFACTS, ERROR>     mapper;\r
98         private Slot sCertAuth;\r
99         private CertManAPI certman;\r
100         private final String voidResp;\r
101 \r
102         public FacadeImpl(CertManAPI certman,\r
103                                           CMService service, \r
104                                           Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper, \r
105                                           Data.TYPE dataType) throws APIException {\r
106                 this.service = service;\r
107                 this.mapper = mapper;\r
108                 this.certman = certman;\r
109                 AuthzEnv env = certman.env;\r
110                 (errDF                          = env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType);\r
111                 (certRequestDF          = env.newDataFactory(mapper.getClass(API.CERT_REQ))).in(dataType).out(dataType);\r
112                 (certRenewDF            = env.newDataFactory(mapper.getClass(API.CERT_RENEW))).in(dataType).out(dataType);\r
113                 (certDropDF             = env.newDataFactory(mapper.getClass(API.CERT_DROP))).in(dataType).out(dataType);\r
114                 (certDF                         = env.newDataFactory(mapper.getClass(API.CERT))).in(dataType).out(dataType);\r
115                 (artiDF                         = env.newDataFactory(mapper.getClass(API.ARTIFACTS))).in(dataType).out(dataType);\r
116                 sCertAuth = env.slot(API_Cert.CERT_AUTH);\r
117                 if(artiDF.getOutType().name().contains("xml")) {\r
118                         voidResp = "application/Void+xml;charset=utf-8;version=1.0,application/xml;version=1.0,*/*";\r
119                 } else {\r
120                         voidResp = "application/Void+json;charset=utf-8;version=1.0,application/json;version=1.0,*/*";\r
121                 }\r
122         }\r
123         \r
124         public Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper() {\r
125                 return mapper;\r
126         }\r
127         \r
128         /* (non-Javadoc)\r
129          * @see com.att.authz.facade.AuthzFacade#error(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)\r
130          * \r
131          * Note: Conforms to AT&T TSS RESTful Error Structure\r
132          */\r
133         @Override\r
134         public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {\r
135                 error(trans, response, result.status,\r
136                                 result.details==null?"":result.details.trim(),\r
137                                 result.variables==null?new String[0]:result.variables);\r
138         }\r
139                 \r
140         @Override\r
141         public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) {\r
142                 String msgId;\r
143                 String prefix;\r
144                 switch(status) {\r
145                         case 202:\r
146                         case ERR_ActionNotCompleted:\r
147                                 msgId = "SVC1202";\r
148                                 prefix = "Accepted, Action not complete";\r
149                                 response.setStatus(/*httpstatus=*/202);\r
150                                 break;\r
151 \r
152                         case 403:\r
153                         case ERR_Policy:\r
154                         case ERR_Security:\r
155                         case ERR_Denied:\r
156                                 msgId = "SVC1403";\r
157                                 prefix = "Forbidden";\r
158                                 response.setStatus(/*httpstatus=*/403);\r
159                                 break;\r
160                                 \r
161                         case 404:\r
162                         case ERR_NotFound:\r
163                                 msgId = "SVC1404";\r
164                                 prefix = "Not Found";\r
165                                 response.setStatus(/*httpstatus=*/404);\r
166                                 break;\r
167 \r
168                         case 406:\r
169                         case ERR_BadData:\r
170                                 msgId="SVC1406";\r
171                                 prefix = "Not Acceptable";\r
172                                 response.setStatus(/*httpstatus=*/406);\r
173                                 break;\r
174                                 \r
175                         case 409:\r
176                         case ERR_ConflictAlreadyExists:\r
177                                 msgId = "SVC1409";\r
178                                 prefix = "Conflict Already Exists";\r
179                                 response.setStatus(/*httpstatus=*/409);\r
180                                 break;\r
181                         \r
182                         case 501:\r
183                         case ERR_NotImplemented:\r
184                                 msgId = "SVC1501";\r
185                                 prefix = "Not Implemented"; \r
186                                 response.setStatus(/*httpstatus=*/501);\r
187                                 break;\r
188                                 \r
189 \r
190                         default:\r
191                                 msgId = "SVC1500";\r
192                                 prefix = "General Service Error";\r
193                                 response.setStatus(/*httpstatus=*/500);\r
194                                 break;\r
195                 }\r
196 \r
197                 try {\r
198                         StringBuilder holder = new StringBuilder();\r
199                         errDF.newData(trans).load(\r
200                                 mapper().errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail)).to(response.getOutputStream());\r
201                         \r
202                         holder.append(']');\r
203                         trans.checkpoint(\r
204                                         "ErrResp [" + \r
205                                         holder,\r
206                                         Env.ALWAYS);\r
207                 } catch (Exception e) {\r
208                         trans.error().log(e,"unable to send response for",_msg);\r
209                 }\r
210         }\r
211 \r
212         @Override\r
213         public Result<Void> check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException {\r
214                 String[] p = Split.split('|',perm);\r
215                 if(p.length!=3) {\r
216                         return Result.err(Result.ERR_BadData,"Invalid Perm String");\r
217                 }\r
218                 AAFPermission ap = new AAFPermission(p[0],p[1],p[2]);\r
219                 if(certman.aafLurPerm.fish(trans.getUserPrincipal(), ap)) {\r
220                         resp.setContentType(voidResp);\r
221                         resp.getOutputStream().write(0);\r
222                         return Result.ok();\r
223                 } else {\r
224                         return Result.err(Result.ERR_Denied,"%s does not have %s",trans.user(),ap.getKey());\r
225                 }\r
226         }\r
227 \r
228         /* (non-Javadoc)\r
229          * @see com.att.auth.certman.facade.Facade#requestCert(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)\r
230          */\r
231         @Override\r
232         public Result<Void> requestCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust) {\r
233                 TimeTaken tt = trans.start(REQUEST_CERT, Env.SUB|Env.ALWAYS);\r
234                 try {\r
235                         REQ request;\r
236                         try {\r
237                                 Data<REQ> rd = certRequestDF.newData().load(req.getInputStream());\r
238                                 request = rd.asObject();\r
239                         } catch(APIException e) {\r
240                                 trans.error().log("Invalid Input",IN,REQUEST_CERT);\r
241                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
242                         }\r
243                         \r
244                         Result<CertResp> rcr = service.requestCert(trans,mapper.toReq(trans,request));\r
245                         if(rcr.notOK()) {\r
246                                 return Result.err(rcr);\r
247                         }\r
248                         \r
249                         CA certAuth = trans.get(sCertAuth,null);\r
250                         Result<CERT> rc = mapper.toCert(trans, rcr, withTrust?certAuth.getTrustChain():null);\r
251                         switch(rc.status) {\r
252                         case OK: \r
253                                 RosettaData<CERT> data = certDF.newData(trans).load(rc.value);\r
254                                 data.to(resp.getOutputStream());\r
255 \r
256                                 setContentType(resp,certDF.getOutType());\r
257                                 return Result.ok();\r
258                         default:\r
259                                 return Result.err(rc);\r
260                 }\r
261 \r
262                 } catch (Exception e) {\r
263                         trans.error().log(e,IN,REQUEST_CERT);\r
264                         return Result.err(e);\r
265                 } finally {\r
266                         tt.done();\r
267                 }\r
268         }\r
269         \r
270         @Override\r
271         public Result<Void> renewCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust) {\r
272                 TimeTaken tt = trans.start(RENEW_CERT, Env.SUB|Env.ALWAYS);\r
273                 try {\r
274                         REQ request;\r
275                         try {\r
276                                 Data<REQ> rd = certRenewDF.newData().load(req.getInputStream());\r
277                                 request = rd.asObject();\r
278                         } catch(APIException e) {\r
279                                 trans.error().log("Invalid Input",IN,RENEW_CERT);\r
280                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
281                         }\r
282                         \r
283                         String certAuth = trans.get(sCertAuth,null);\r
284                         Result<CertResp> rcr = service.renewCert(trans,mapper.toRenew(trans,request));\r
285                         Result<CERT> rc = mapper.toCert(trans, rcr, certman.getTrustChain(certAuth));\r
286 \r
287                         switch(rc.status) {\r
288                                 case OK: \r
289                                         RosettaData<CERT> data = certDF.newData(trans).load(rc.value);\r
290                                         data.to(resp.getOutputStream());\r
291 \r
292                                         setContentType(resp,certDF.getOutType());\r
293                                         return Result.ok();\r
294                                 default:\r
295                                         return Result.err(rc);\r
296                         }\r
297                 } catch (Exception e) {\r
298                         trans.error().log(e,IN,RENEW_CERT);\r
299                         return Result.err(e);\r
300                 } finally {\r
301                         tt.done();\r
302                 }\r
303 \r
304         }\r
305 \r
306         @Override\r
307         public Result<Void> dropCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {\r
308                 TimeTaken tt = trans.start(DROP_CERT, Env.SUB|Env.ALWAYS);\r
309                 try {\r
310                         REQ request;\r
311                         try {\r
312                                 Data<REQ> rd = certDropDF.newData().load(req.getInputStream());\r
313                                 request = rd.asObject();\r
314                         } catch(APIException e) {\r
315                                 trans.error().log("Invalid Input",IN,DROP_CERT);\r
316                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
317                         }\r
318                         \r
319                         Result<Void> rv = service.dropCert(trans,mapper.toDrop(trans, request));\r
320                         switch(rv.status) {\r
321                                 case OK: \r
322                                         setContentType(resp,certRequestDF.getOutType());\r
323                                         return Result.ok();\r
324                                 default:\r
325                                         return Result.err(rv);\r
326                         }\r
327                 } catch (Exception e) {\r
328                         trans.error().log(e,IN,DROP_CERT);\r
329                         return Result.err(e);\r
330                 } finally {\r
331                         tt.done();\r
332                 }\r
333         }\r
334 \r
335         ////////////////////////////\r
336         // Artifacts\r
337         ////////////////////////////\r
338         @Override\r
339         public Result<Void> createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {\r
340                 TimeTaken tt = trans.start(CREATE_ARTIFACTS, Env.SUB);\r
341                 try {\r
342                         ARTIFACTS arti;\r
343                         try {\r
344                                 Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());\r
345                                 arti = rd.asObject();\r
346                         } catch(APIException e) {\r
347                                 trans.error().log("Invalid Input",IN,CREATE_ARTIFACTS);\r
348                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
349                         }\r
350                         \r
351                         return service.createArtifact(trans,mapper.toArtifact(trans,arti));\r
352                 } catch (Exception e) {\r
353 \r
354                         trans.error().log(e,IN,CREATE_ARTIFACTS);\r
355                         return Result.err(e);\r
356                 } finally {\r
357                         tt.done();\r
358                 }\r
359         }\r
360 \r
361         @Override\r
362         public Result<Void> readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {\r
363                 TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);\r
364                 try {\r
365                         String mechid = req.getParameter("mechid");\r
366                         String machine = req.getParameter("machine");\r
367                         \r
368                         Result<ARTIFACTS> ra;\r
369                         if( machine !=null && mechid == null) {\r
370                                 ra = mapper.fromArtifacts(service.readArtifactsByMachine(trans, machine));\r
371                         } else if(mechid!=null && machine==null) {\r
372                                 ra = mapper.fromArtifacts(service.readArtifactsByMechID(trans, mechid));\r
373                         } else if(mechid!=null && machine!=null) {\r
374                                 ArtiDAO.Data add = new ArtiDAO.Data();\r
375                                 add.mechid = mechid;\r
376                                 add.machine = machine;\r
377                                 ra = mapper.fromArtifacts(service.readArtifacts(trans,add));\r
378                         } else {\r
379                                 ra = Result.err(Status.ERR_BadData,"Invalid request inputs");\r
380                         }\r
381                         \r
382                         if(ra.isOK()) {\r
383                                 RosettaData<ARTIFACTS> data = artiDF.newData(trans).load(ra.value);\r
384                                 data.to(resp.getOutputStream());\r
385                                 setContentType(resp,artiDF.getOutType());\r
386                                 return Result.ok();\r
387                         } else {\r
388                                 return Result.err(ra);\r
389                         }\r
390 \r
391                 } catch (Exception e) {\r
392                         trans.error().log(e,IN,READ_ARTIFACTS);\r
393                         return Result.err(e);\r
394                 } finally {\r
395                         tt.done();\r
396                 }\r
397         }\r
398 \r
399         @Override\r
400         public Result<Void> readArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) {\r
401                 TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);\r
402                 try {\r
403                         ArtiDAO.Data add = new ArtiDAO.Data();\r
404                         add.mechid = mechid;\r
405                         add.machine = machine;\r
406                         Result<ARTIFACTS> ra = mapper.fromArtifacts(service.readArtifacts(trans,add));\r
407                         if(ra.isOK()) {\r
408                                 RosettaData<ARTIFACTS> data = artiDF.newData(trans).load(ra.value);\r
409                                 data.to(resp.getOutputStream());\r
410                                 setContentType(resp,artiDF.getOutType());\r
411                                 return Result.ok();\r
412                         } else {\r
413                                 return Result.err(ra);\r
414                         }\r
415                 } catch (Exception e) {\r
416                         trans.error().log(e,IN,READ_ARTIFACTS);\r
417                         return Result.err(e);\r
418                 } finally {\r
419                         tt.done();\r
420                 }\r
421         }\r
422 \r
423 \r
424         @Override\r
425         public Result<Void> updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {\r
426                 TimeTaken tt = trans.start(UPDATE_ARTIFACTS, Env.SUB);\r
427                 try {\r
428                         ARTIFACTS arti;\r
429                         try {\r
430                                 Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());\r
431                                 arti = rd.asObject();\r
432                         } catch(APIException e) {\r
433                                 trans.error().log("Invalid Input",IN,UPDATE_ARTIFACTS);\r
434                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
435                         }\r
436                         \r
437                         return service.updateArtifact(trans,mapper.toArtifact(trans,arti));\r
438                 } catch (Exception e) {\r
439                         trans.error().log(e,IN,UPDATE_ARTIFACTS);\r
440                         return Result.err(e);\r
441                 } finally {\r
442                         tt.done();\r
443                 }\r
444         }\r
445 \r
446         @Override\r
447         public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {\r
448                 TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);\r
449                 try {\r
450                         ARTIFACTS arti;\r
451                         try {\r
452                                 Data<ARTIFACTS> rd = artiDF.newData().load(req.getInputStream());\r
453                                 arti = rd.asObject();\r
454                         } catch(APIException e) {\r
455                                 trans.error().log("Invalid Input",IN,DELETE_ARTIFACTS);\r
456                                 return Result.err(Result.ERR_BadData,"Invalid Input");\r
457                         }\r
458                         \r
459                         Result<Void> rv = service.deleteArtifact(trans,mapper.toArtifact(trans,arti));\r
460                         switch(rv.status) {\r
461                                 case OK: \r
462                                         setContentType(resp,artiDF.getOutType());\r
463                         } \r
464                         return rv;\r
465                 } catch (Exception e) {\r
466                         trans.error().log(e,IN,DELETE_ARTIFACTS);\r
467                         return Result.err(e);\r
468                 } finally {\r
469                         tt.done();\r
470                 }\r
471         }\r
472 \r
473         @Override\r
474         public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) {\r
475                 TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);\r
476                 try {\r
477                         Result<Void> rv = service.deleteArtifact(trans, mechid, machine);\r
478                         switch(rv.status) {\r
479                                 case OK: \r
480                                         setContentType(resp,artiDF.getOutType());\r
481                         } \r
482                         return rv;\r
483                 } catch (Exception e) {\r
484                         trans.error().log(e,IN,DELETE_ARTIFACTS);\r
485                         return Result.err(e);\r
486                 } finally {\r
487                         tt.done();\r
488                 }\r
489         }\r
490 \r
491 \r
492 }\r