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 com.att.authz.cm.facade;
\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
35 import java.io.IOException;
\r
37 import javax.servlet.http.HttpServletRequest;
\r
38 import javax.servlet.http.HttpServletResponse;
\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
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
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
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
81 public abstract class FacadeImpl<REQ,CERT,ARTIFACTS,ERROR> extends com.att.authz.layer.FacadeImpl implements Facade<REQ,CERT,ARTIFACTS,ERROR>
\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
91 private CMService service;
\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
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
120 voidResp = "application/Void+json;charset=utf-8;version=1.0,application/json;version=1.0,*/*";
\r
124 public Mapper<REQ,CERT,ARTIFACTS,ERROR> mapper() {
\r
129 * @see com.att.authz.facade.AuthzFacade#error(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletResponse, int)
\r
131 * Note: Conforms to AT&T TSS RESTful Error Structure
\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
141 public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) {
\r
146 case ERR_ActionNotCompleted:
\r
148 prefix = "Accepted, Action not complete";
\r
149 response.setStatus(/*httpstatus=*/202);
\r
157 prefix = "Forbidden";
\r
158 response.setStatus(/*httpstatus=*/403);
\r
164 prefix = "Not Found";
\r
165 response.setStatus(/*httpstatus=*/404);
\r
171 prefix = "Not Acceptable";
\r
172 response.setStatus(/*httpstatus=*/406);
\r
176 case ERR_ConflictAlreadyExists:
\r
178 prefix = "Conflict Already Exists";
\r
179 response.setStatus(/*httpstatus=*/409);
\r
183 case ERR_NotImplemented:
\r
185 prefix = "Not Implemented";
\r
186 response.setStatus(/*httpstatus=*/501);
\r
192 prefix = "General Service Error";
\r
193 response.setStatus(/*httpstatus=*/500);
\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
202 holder.append(']');
\r
207 } catch (Exception e) {
\r
208 trans.error().log(e,"unable to send response for",_msg);
\r
213 public Result<Void> check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException {
\r
214 String[] p = Split.split('|',perm);
\r
216 return Result.err(Result.ERR_BadData,"Invalid Perm String");
\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
224 return Result.err(Result.ERR_Denied,"%s does not have %s",trans.user(),ap.getKey());
\r
229 * @see com.att.auth.certman.facade.Facade#requestCert(com.att.authz.env.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
\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
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
244 Result<CertResp> rcr = service.requestCert(trans,mapper.toReq(trans,request));
\r
246 return Result.err(rcr);
\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
253 RosettaData<CERT> data = certDF.newData(trans).load(rc.value);
\r
254 data.to(resp.getOutputStream());
\r
256 setContentType(resp,certDF.getOutType());
\r
257 return Result.ok();
\r
259 return Result.err(rc);
\r
262 } catch (Exception e) {
\r
263 trans.error().log(e,IN,REQUEST_CERT);
\r
264 return Result.err(e);
\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
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
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
287 switch(rc.status) {
\r
289 RosettaData<CERT> data = certDF.newData(trans).load(rc.value);
\r
290 data.to(resp.getOutputStream());
\r
292 setContentType(resp,certDF.getOutType());
\r
293 return Result.ok();
\r
295 return Result.err(rc);
\r
297 } catch (Exception e) {
\r
298 trans.error().log(e,IN,RENEW_CERT);
\r
299 return Result.err(e);
\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
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
319 Result<Void> rv = service.dropCert(trans,mapper.toDrop(trans, request));
\r
320 switch(rv.status) {
\r
322 setContentType(resp,certRequestDF.getOutType());
\r
323 return Result.ok();
\r
325 return Result.err(rv);
\r
327 } catch (Exception e) {
\r
328 trans.error().log(e,IN,DROP_CERT);
\r
329 return Result.err(e);
\r
335 ////////////////////////////
\r
337 ////////////////////////////
\r
339 public Result<Void> createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
340 TimeTaken tt = trans.start(CREATE_ARTIFACTS, Env.SUB);
\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
351 return service.createArtifact(trans,mapper.toArtifact(trans,arti));
\r
352 } catch (Exception e) {
\r
354 trans.error().log(e,IN,CREATE_ARTIFACTS);
\r
355 return Result.err(e);
\r
362 public Result<Void> readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
363 TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB);
\r
365 String mechid = req.getParameter("mechid");
\r
366 String machine = req.getParameter("machine");
\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
379 ra = Result.err(Status.ERR_BadData,"Invalid request inputs");
\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
388 return Result.err(ra);
\r
391 } catch (Exception e) {
\r
392 trans.error().log(e,IN,READ_ARTIFACTS);
\r
393 return Result.err(e);
\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
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
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
413 return Result.err(ra);
\r
415 } catch (Exception e) {
\r
416 trans.error().log(e,IN,READ_ARTIFACTS);
\r
417 return Result.err(e);
\r
425 public Result<Void> updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
426 TimeTaken tt = trans.start(UPDATE_ARTIFACTS, Env.SUB);
\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
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
447 public Result<Void> deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
\r
448 TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB);
\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
459 Result<Void> rv = service.deleteArtifact(trans,mapper.toArtifact(trans,arti));
\r
460 switch(rv.status) {
\r
462 setContentType(resp,artiDF.getOutType());
\r
465 } catch (Exception e) {
\r
466 trans.error().log(e,IN,DELETE_ARTIFACTS);
\r
467 return Result.err(e);
\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
477 Result<Void> rv = service.deleteArtifact(trans, mechid, machine);
\r
478 switch(rv.status) {
\r
480 setContentType(resp,artiDF.getOutType());
\r
483 } catch (Exception e) {
\r
484 trans.error().log(e,IN,DELETE_ARTIFACTS);
\r
485 return Result.err(e);
\r