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