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