1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\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
11 * * http://www.apache.org/licenses/LICENSE-2.0
\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
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.authz.cm.facade;
\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
35 import java.io.IOException;
\r
37 import javax.servlet.http.HttpServletRequest;
\r
38 import javax.servlet.http.HttpServletResponse;
\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
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
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
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
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
82 public abstract class FacadeImpl<REQ,CERT,ARTIFACTS,ERROR> extends org.onap.aaf.authz.layer.FacadeImpl implements Facade<REQ,CERT,ARTIFACTS,ERROR>
\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
92 private CMService service;
\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
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
121 voidResp = "application/Void+json;charset=utf-8;version=1.0,application/json;version=1.0,*/*";
\r
125 public Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper() {
\r
130 * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)
\r
132 * Note: Conforms to AT&T TSS RESTful Error Structure
\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
142 public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) {
\r
147 case ERR_ActionNotCompleted:
\r
149 prefix = "Accepted, Action not complete";
\r
150 response.setStatus(/*httpstatus=*/202);
\r
158 prefix = "Forbidden";
\r
159 response.setStatus(/*httpstatus=*/403);
\r
165 prefix = "Not Found";
\r
166 response.setStatus(/*httpstatus=*/404);
\r
172 prefix = "Not Acceptable";
\r
173 response.setStatus(/*httpstatus=*/406);
\r
177 case ERR_ConflictAlreadyExists:
\r
179 prefix = "Conflict Already Exists";
\r
180 response.setStatus(/*httpstatus=*/409);
\r
184 case ERR_NotImplemented:
\r
186 prefix = "Not Implemented";
\r
187 response.setStatus(/*httpstatus=*/501);
\r
193 prefix = "General Service Error";
\r
194 response.setStatus(/*httpstatus=*/500);
\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
203 holder.append(']');
\r
208 } catch (Exception e) {
\r
209 trans.error().log(e,"unable to send response for",_msg);
\r
214 public Result<Void> check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException {
\r
215 String[] p = Split.split('|',perm);
\r
217 return Result.err(Result.ERR_BadData,"Invalid Perm String");
\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
225 return Result.err(Result.ERR_Denied,"%s does not have %s",trans.user(),ap.getKey());
\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
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
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
245 Result<CertResp> rcr = service.requestCert(trans,mapper.toReq(trans,request));
\r
247 return Result.err(rcr);
\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
254 RosettaData<CERT> data = certDF.newData(trans).load(rc.value);
\r
255 data.to(resp.getOutputStream());
\r
257 setContentType(resp,certDF.getOutType());
\r
258 return Result.ok();
\r
260 return Result.err(rc);
\r
263 } catch (Exception e) {
\r
264 trans.error().log(e,IN,REQUEST_CERT);
\r
265 return Result.err(e);
\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
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
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
288 switch(rc.status) {
\r
290 RosettaData<CERT> data = certDF.newData(trans).load(rc.value);
\r
291 data.to(resp.getOutputStream());
\r
293 setContentType(resp,certDF.getOutType());
\r
294 return Result.ok();
\r
296 return Result.err(rc);
\r
298 } catch (Exception e) {
\r
299 trans.error().log(e,IN,RENEW_CERT);
\r
300 return Result.err(e);
\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
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
320 Result<Void> rv = service.dropCert(trans,mapper.toDrop(trans, request));
\r
321 switch(rv.status) {
\r
323 setContentType(resp,certRequestDF.getOutType());
\r
324 return Result.ok();
\r
326 return Result.err(rv);
\r
328 } catch (Exception e) {
\r
329 trans.error().log(e,IN,DROP_CERT);
\r
330 return Result.err(e);
\r
336 ////////////////////////////
\r
338 ////////////////////////////
\r
340 public Result<Void> createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
341 TimeTaken tt = trans.start(CREATE_ARTIFACTS, Env.SUB);
\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
352 return service.createArtifact(trans,mapper.toArtifact(trans,arti));
\r
353 } catch (Exception e) {
\r
355 trans.error().log(e,IN,CREATE_ARTIFACTS);
\r
356 return Result.err(e);
\r
363 public Result<Void> readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
364 TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);
\r
366 String mechid = req.getParameter("mechid");
\r
367 String machine = req.getParameter("machine");
\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
380 ra = Result.err(Status.ERR_BadData,"Invalid request inputs");
\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
389 return Result.err(ra);
\r
392 } catch (Exception e) {
\r
393 trans.error().log(e,IN,READ_ARTIFACTS);
\r
394 return Result.err(e);
\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
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
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
414 return Result.err(ra);
\r
416 } catch (Exception e) {
\r
417 trans.error().log(e,IN,READ_ARTIFACTS);
\r
418 return Result.err(e);
\r
426 public Result<Void> updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
427 TimeTaken tt = trans.start(UPDATE_ARTIFACTS, Env.SUB);
\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
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
448 public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
449 TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);
\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
460 Result<Void> rv = service.deleteArtifact(trans,mapper.toArtifact(trans,arti));
\r
461 switch(rv.status) {
\r
463 setContentType(resp,artiDF.getOutType());
\r
466 } catch (Exception e) {
\r
467 trans.error().log(e,IN,DELETE_ARTIFACTS);
\r
468 return Result.err(e);
\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
478 Result<Void> rv = service.deleteArtifact(trans, mechid, machine);
\r
479 switch(rv.status) {
\r
481 setContentType(resp,artiDF.getOutType());
\r
484 } catch (Exception e) {
\r
485 trans.error().log(e,IN,DELETE_ARTIFACTS);
\r
486 return Result.err(e);
\r