Push and unpush to support multiple policies
[policy/engine.git] / ONAP-PAP-REST / src / main / java / org / onap / policy / pap / xacml / rest / handler / DeleteHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PAP-REST
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.pap.xacml.rest.handler;
22
23 import com.att.research.xacml.api.pap.PAPException;
24 import com.att.research.xacml.api.pap.PDPPolicy;
25 import com.att.research.xacml.util.XACMLProperties;
26 import java.io.File;
27 import java.io.IOException;
28 import java.util.Arrays;
29 import java.util.List;
30 import javax.script.SimpleBindings;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33 import org.apache.commons.lang3.StringUtils;
34 import org.onap.policy.common.logging.ONAPLoggingContext;
35 import org.onap.policy.common.logging.eelf.MessageCodes;
36 import org.onap.policy.common.logging.eelf.PolicyLogger;
37 import org.onap.policy.common.logging.flexlogger.FlexLogger;
38 import org.onap.policy.common.logging.flexlogger.Logger;
39 import org.onap.policy.pap.xacml.rest.XACMLPapServlet;
40 import org.onap.policy.pap.xacml.rest.components.PolicyDBDaoTransaction;
41 import org.onap.policy.pap.xacml.rest.elk.client.PolicyElasticSearchController;
42 import org.onap.policy.pap.xacml.rest.model.RemoveGroupPolicy;
43 import org.onap.policy.pap.xacml.rest.util.JPAUtils;
44 import org.onap.policy.rest.adapter.PolicyRestAdapter;
45 import org.onap.policy.rest.dao.CommonClassDao;
46 import org.onap.policy.rest.jpa.PolicyEntity;
47 import org.onap.policy.rest.jpa.PolicyVersion;
48 import org.onap.policy.utils.PolicyUtils;
49 import org.onap.policy.xacml.api.XACMLErrorConstants;
50 import org.onap.policy.xacml.api.pap.OnapPDPGroup;
51 import org.onap.policy.xacml.std.pap.StdPAPPolicy;
52 import org.onap.policy.xacml.std.pap.StdPDPGroup;
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.stereotype.Component;
55
56 @Component
57 public class DeleteHandler {
58
59     private static CommonClassDao commonClassDao;
60
61     @Autowired
62     public DeleteHandler(CommonClassDao commonClassDao) {
63         DeleteHandler.commonClassDao = commonClassDao;
64     }
65
66     public DeleteHandler() {
67         // Default Constructor
68     }
69
70     private OnapPDPGroup newgroup;
71     private static final Logger LOGGER = FlexLogger.getLogger(DeleteHandler.class);
72     private static final String POLICY_IN_PDP = "PolicyInPDP";
73     private static final String ERROR = "error";
74     private static final String MESSAGE = "message";
75     private static final String UNKNOWN = "unknown";
76     private static final String SUCCESS = "success";
77     private static final String OPERATION = "operation";
78     private static final String CONFIG = "Config_";
79     private static final String REGEX = "[0-9a-zA-Z._]*";
80     private static final String DELETE = "delete";
81     private static final String ACTION = "Action_";
82
83     /**
84      * Do API delete from PAP.
85      *
86      * @param request the request
87      * @param response the response
88      * @throws IOException Signals that an I/O exception has occurred.
89      */
90     public void doApiDeleteFromPap(HttpServletRequest request, HttpServletResponse response) throws IOException {
91         // get the request content into a String
92         String json = null;
93         java.util.Scanner scanner = new java.util.Scanner(request.getInputStream());
94         scanner.useDelimiter("\\A");
95         json = scanner.hasNext() ? scanner.next() : "";
96         scanner.close();
97         PolicyLogger.info("JSON request from API to Delete Policy from the PAP: " + json);
98         // convert Object sent as JSON into local object
99         StdPAPPolicy policy = PolicyUtils.jsonStringToObject(json, StdPAPPolicy.class);
100         String policyName = policy.getPolicyName();
101         boolean policyVersionDeleted = false;
102         String removeXmlExtension;
103         int currentVersion;
104         String removeVersionExtension;
105         String splitPolicyName = null;
106         String[] split = null;
107         String status = ERROR;
108         PolicyEntity policyEntity = null;
109         JPAUtils jpaUtils = null;
110
111         try {
112             jpaUtils = JPAUtils.getJPAUtilsInstance();
113         } catch (Exception e) {
114             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "doAPIDeleteFromPAP",
115                     " Could not create JPAUtils instance on the PAP");
116             response.addHeader(ERROR, "jpautils");
117             response.addHeader(OPERATION, DELETE);
118             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
119             return;
120         }
121         if (jpaUtils.dbLockdownIgnoreErrors()) {
122             PolicyLogger.warn("Policies are locked down");
123             response.addHeader(OPERATION, DELETE);
124             response.addHeader("lockdown", "true");
125             response.setStatus(HttpServletResponse.SC_ACCEPTED);
126             return;
127         }
128         String policyEntityQuery = null;
129         try {
130             if (policyName.endsWith(".xml")) {
131                 removeXmlExtension = policyName.replace(".xml", "");
132                 currentVersion =
133                         Integer.parseInt(removeXmlExtension.substring(removeXmlExtension.lastIndexOf('.') + 1));
134                 removeVersionExtension = removeXmlExtension.substring(0, removeXmlExtension.lastIndexOf('.'));
135                 boolean queryCheck = true;
136                 if ("All Versions".equalsIgnoreCase(policy.getDeleteCondition())) {
137                     if (policyName.contains(CONFIG)) {
138                         splitPolicyName = removeVersionExtension.replace(".Config_", ":Config_");
139                     } else if (policyName.contains(ACTION)) {
140                         splitPolicyName = removeVersionExtension.replace(".Action_", ":Action_");
141                     } else if (policyName.contains("Decision_")) {
142                         splitPolicyName = removeVersionExtension.replace(".Decision_", ":Decision_");
143                     }
144                     if (splitPolicyName != null) {
145                         split = splitPolicyName.split(":");
146                     } else {
147                         PolicyLogger.error(MessageCodes.ERROR_UNKNOWN
148                                 + "Failed to delete the policy. Please, provide the valid policyname.");
149                         response.addHeader(ERROR, UNKNOWN);
150                         response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
151                         return;
152                     }
153                     policyEntityQuery =
154                             "SELECT p FROM PolicyEntity p WHERE p.policyName LIKE :pName and p.scope=:pScope";
155                 } else if ("Current Version".equalsIgnoreCase(policy.getDeleteCondition())) {
156                     if (policyName.contains(CONFIG)) {
157                         splitPolicyName = policyName.replace(".Config_", ":Config_");
158                     } else if (policyName.contains(ACTION)) {
159                         splitPolicyName = policyName.replace(".Action_", ":Action_");
160                     } else if (policyName.contains("Decision_")) {
161                         splitPolicyName = policyName.replace(".Decision_", ":Decision_");
162                     }
163                     split = splitPolicyName.split(":");
164                     queryCheck = false;
165                     policyEntityQuery = "SELECT p FROM PolicyEntity p WHERE p.policyName=:pName and p.scope=:pScope";
166                 }
167                 SimpleBindings params = new SimpleBindings();
168                 if (queryCheck) {
169                     params.put("pName", "%" + split[1] + "%");
170                 } else {
171                     params.put("pName", split[1]);
172                 }
173
174                 params.put("pScope", split[0]);
175                 List<?> peResult = commonClassDao.getDataByQuery(policyEntityQuery, params);
176                 if (!peResult.isEmpty()) {
177                     String getPolicyVersion = "Select p from PolicyVersion p where p.policyName=:pname";
178                     SimpleBindings pvParams = new SimpleBindings();
179                     pvParams.put("pname", removeVersionExtension.replace(".", File.separator));
180                     List<?> pvResult = commonClassDao.getDataByQuery(getPolicyVersion, pvParams);
181                     PolicyVersion polVersion = (PolicyVersion) pvResult.get(0);
182                     int newVersion = 0;
183                     if ("All Versions".equalsIgnoreCase(policy.getDeleteCondition())) {
184                         boolean groupCheck = checkPolicyGroupEntity(peResult);
185                         if (!groupCheck) {
186                             for (Object peData : peResult) {
187                                 policyEntity = (PolicyEntity) peData;
188                                 status = deletePolicyEntityData(policyEntity);
189                             }
190                         } else {
191                             status = POLICY_IN_PDP;
192                         }
193                         switch (status) {
194                             case ERROR:
195                                 PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE
196                                         + "Exception Occured while deleting the Entity from Database.");
197                                 response.addHeader(ERROR, UNKNOWN);
198                                 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
199                                 return;
200                             case POLICY_IN_PDP:
201                                 PolicyLogger.error(MessageCodes.GENERAL_WARNING
202                                         + "Policy can't be deleted, it is active in PDP Groups.");
203                                 response.addHeader(ERROR, POLICY_IN_PDP);
204                                 response.setStatus(HttpServletResponse.SC_CONFLICT);
205                                 return;
206                             default:
207                                 try {
208                                     policyVersionDeleted = true;
209                                     commonClassDao.delete(polVersion);
210                                 } catch (Exception e) {
211                                     LOGGER.error(e.getMessage(), e);
212                                     policyVersionDeleted = false;
213                                 }
214                                 break;
215                         }
216                     } else if ("Current Version".equalsIgnoreCase(policy.getDeleteCondition())) {
217                         boolean groupCheck = checkPolicyGroupEntity(peResult);
218                         if (!groupCheck) {
219                             policyEntity = (PolicyEntity) peResult.get(0);
220                             status = deletePolicyEntityData(policyEntity);
221                         } else {
222                             status = POLICY_IN_PDP;
223                         }
224
225                         if (ERROR.equals(status)) {
226                             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE
227                                     + "Exception Occured while deleting the Entity from Database.");
228                             response.addHeader(ERROR, UNKNOWN);
229                             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
230                             return;
231                         } else if (POLICY_IN_PDP.equals(status)) {
232                             PolicyLogger.error(MessageCodes.GENERAL_WARNING
233                                     + "Policy can't be deleted, it is active in PDP Groups.");
234                             response.addHeader(ERROR, POLICY_IN_PDP);
235                             response.setStatus(HttpServletResponse.SC_CONFLICT);
236                             return;
237                         } else {
238                             if (currentVersion > 1) {
239                                 if (!peResult.isEmpty()) {
240                                     for (Object object : peResult) {
241                                         policyEntity = (PolicyEntity) object;
242                                         String policyEntityName = policyEntity.getPolicyName().replace(".xml", "");
243                                         int policyEntityVersion = Integer.parseInt(
244                                                 policyEntityName.substring(policyEntityName.lastIndexOf('.') + 1));
245                                         if (policyEntityVersion > newVersion) {
246                                             newVersion = policyEntityVersion - 1;
247                                         }
248                                     }
249                                 }
250                                 polVersion.setActiveVersion(newVersion);
251                                 polVersion.setHigherVersion(newVersion);
252                                 try {
253                                     policyVersionDeleted = true;
254                                     commonClassDao.save(polVersion);
255                                 } catch (Exception e) {
256                                     LOGGER.error(e.getMessage(), e);
257                                     policyVersionDeleted = false;
258                                 }
259                             } else {
260                                 try {
261                                     policyVersionDeleted = true;
262                                     commonClassDao.delete(polVersion);
263                                 } catch (Exception e) {
264                                     LOGGER.error(e.getMessage(), e);
265                                     policyVersionDeleted = false;
266                                 }
267                             }
268                         }
269                     }
270                 } else {
271                     PolicyLogger.error(MessageCodes.ERROR_UNKNOWN
272                             + "Failed to delete the policy for an unknown reason.  Check the file system and other logs"
273                             + " for further information.");
274                     response.addHeader(ERROR, UNKNOWN);
275                     response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
276                     return;
277                 }
278             }
279         } catch (Exception e) {
280             PolicyLogger.error(MessageCodes.EXCEPTION_ERROR, e, "XACMLPapServlet", " ERROR");
281             response.addHeader(ERROR, "deleteDB");
282             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
283             return;
284         }
285
286         if (policyVersionDeleted) {
287             response.setStatus(HttpServletResponse.SC_OK);
288             response.addHeader("successMapKey", SUCCESS);
289             response.addHeader(OPERATION, DELETE);
290         } else {
291             PolicyLogger.error(MessageCodes.ERROR_UNKNOWN
292                     + "Failed to delete the policy for an unknown reason.  Check the file system and other logs for "
293                     + "further information.");
294             response.addHeader(ERROR, UNKNOWN);
295             response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
296         }
297     }
298
299     /**
300      * Delete policy entity data.
301      *
302      * @param policyEntity the policy entity
303      * @return the string
304      */
305     public static String deletePolicyEntityData(PolicyEntity policyEntity) {
306         PolicyElasticSearchController controller = new PolicyElasticSearchController();
307         PolicyRestAdapter policyData = new PolicyRestAdapter();
308         String policyName = policyEntity.getPolicyName();
309         try {
310             if (policyName.contains("CONFIG") || policyName.contains("Decision_MS_")) {
311                 commonClassDao.delete(policyEntity.getConfigurationData());
312             } else if (policyName.contains(ACTION)) {
313                 commonClassDao.delete(policyEntity.getActionBodyEntity());
314             }
315             String searchPolicyName = policyEntity.getScope() + "." + policyEntity.getPolicyName();
316             policyData.setNewFileName(searchPolicyName);
317             controller.deleteElk(policyData);
318             commonClassDao.delete(policyEntity);
319         } catch (Exception e) {
320             LOGGER.error(e.getMessage(), e);
321             return ERROR;
322         }
323         return SUCCESS;
324     }
325
326     /**
327      * Check policy group entity.
328      *
329      * @param peResult the pe result
330      * @return true, if successful
331      */
332     public static boolean checkPolicyGroupEntity(List<?> peResult) {
333         String groupEntityquery = "from PolicyGroupEntity where policyid = :policyEntityId";
334         for (Object peData : peResult) {
335             PolicyEntity policyEntity = (PolicyEntity) peData;
336             SimpleBindings geParams = new SimpleBindings();
337             geParams.put("policyEntityId", policyEntity.getPolicyId());
338             List<Object> groupobject = commonClassDao.getDataByQuery(groupEntityquery, geParams);
339             if (!groupobject.isEmpty()) {
340                 return true;
341             }
342         }
343         return false;
344     }
345
346     /**
347      * Do API delete from PDP.
348      *
349      * @param request the request
350      * @param response the response
351      * @param loggingContext the logging context
352      * @throws IOException Signals that an I/O exception has occurred.
353      */
354     public void doApiDeleteFromPdp(HttpServletRequest request, HttpServletResponse response,
355             ONAPLoggingContext loggingContext) throws IOException {
356         String groupId = request.getParameter("groupId");
357
358         if (groupId != null && !groupId.matches(REGEX)) {
359             response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
360             response.addHeader(ERROR, ERROR);
361             response.addHeader(MESSAGE, "Group Id is not valid");
362             return;
363         }
364         String requestId = request.getHeader("X-ECOMP-RequestID");
365         String polName = request.getParameter("policyName");
366         LOGGER.info("JSON request from API to Delete Policy from the PDP - " + polName + " -RequestId - " + requestId);
367
368         // for PUT operations the group may or may not need to exist before the operation can be
369         // done
370         OnapPDPGroup group = null;
371         try {
372             group = XACMLPapServlet.getPAPEngine().getGroup(groupId);
373         } catch (PAPException e) {
374             LOGGER.error("Exception occured While PUT operation is performing for PDP Group" + " -  RequestId - "
375                     + requestId + e);
376         }
377         if (group == null) {
378             String message = "Unknown groupId '" + groupId + "'.";
379             LOGGER.error(MessageCodes.ERROR_DATA_ISSUE + " - RequestId -  " + requestId + " - " + message);
380             loggingContext.transactionEnded();
381             PolicyLogger.audit("Transaction Failed - See Error.log");
382             response.addHeader(ERROR, "UnknownGroup");
383             response.addHeader(MESSAGE, message);
384             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
385             return;
386         }
387         loggingContext.setServiceName("API:PAP.deletPolicyFromPDPGroup");
388         RemoveGroupPolicy removePolicy = new RemoveGroupPolicy((StdPDPGroup) group);
389         removePolicy.prepareToRemove();
390         List<String> policyIdList = Arrays.asList(polName.split(","));
391         for (String policyName : policyIdList) {
392             if (!policyName.endsWith("xml")) {
393                 String message = XACMLErrorConstants.ERROR_DATA_ISSUE + "Invalid policyName... "
394                         + "policyName must be the full name of the file to be deleted including version and extension";
395                 LOGGER.error(message + "   - RequestId - " + requestId);
396                 response.addHeader(ERROR, message);
397                 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
398                 return;
399             }
400             PDPPolicy policy = group.getPolicy(policyName);
401             if (policy == null) {
402                 String message =
403                         XACMLErrorConstants.ERROR_DATA_ISSUE + "Policy does not exist on the PDP - " + policyName;
404                 LOGGER.error(message + " - RequestId   - " + requestId);
405                 response.addHeader(ERROR, message);
406                 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
407                 return;
408             }
409             if (StringUtils.indexOfAny(policy.getId(), "Config_MS_", "BRMS_Param") >= 0) {
410                 preSafetyCheck(policy);
411             }
412             LOGGER.info("Preparing to remove policy from group: " + group.getId() + "- RequestId - " + requestId);
413             removePolicy.removePolicy(policy);
414         }
415         OnapPDPGroup updatedGroup = removePolicy.getUpdatedObject();
416         String userId = request.getParameter("userId");
417         String responseString = deletePolicyFromPdpGroup(updatedGroup, loggingContext, userId);
418
419         switch (responseString) {
420             case SUCCESS:
421                 loggingContext.transactionEnded();
422                 LOGGER.info("Policy successfully removed from PDP - " + polName + " -   RequestId - " + requestId);
423                 PolicyLogger.audit("Policy successfully deleted!");
424                 response.setStatus(HttpServletResponse.SC_OK);
425                 response.addHeader("successMapKey", SUCCESS);
426                 response.addHeader(OPERATION, DELETE);
427                 break;
428             case "No Group":
429                 String message = XACMLErrorConstants.ERROR_DATA_ISSUE + "Group update had bad input.";
430                 LOGGER.error(message + " - RequestId - " + requestId);
431                 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
432                 response.addHeader(ERROR, "groupUpdate");
433                 response.addHeader(MESSAGE, message);
434                 break;
435             case "DB Error":
436                 LOGGER.error(MessageCodes.ERROR_PROCESS_FLOW + " Error while updating group in the database"
437                         + " - RequestId - " + requestId);
438                 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
439                 response.addHeader(ERROR, "deleteDB");
440                 break;
441             default:
442                 LOGGER.error(MessageCodes.ERROR_UNKNOWN
443                         + " Failed to delete the policy for an unknown reason.  Check the file system and other logs "
444                         + "for " + "further information.");
445                 response.addHeader(ERROR, UNKNOWN);
446                 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
447                 break;
448         }
449     }
450
451     private String deletePolicyFromPdpGroup(OnapPDPGroup group, ONAPLoggingContext loggingContext, String userId) {
452         PolicyDBDaoTransaction acPutTransaction = XACMLPapServlet.getDbDaoTransaction();
453         String response = null;
454         loggingContext.setServiceName("API:PAP.DeleteHandler");
455         OnapPDPGroup existingGroup = null;
456         try {
457             existingGroup = XACMLPapServlet.getPAPEngine().getGroup(group.getId());
458         } catch (PAPException e1) {
459             PolicyLogger.error("Exception occured While Deleting Policy From PDP Group" + e1);
460         }
461         if (!(group instanceof StdPDPGroup) || existingGroup == null
462                 || !(group.getId().equals(existingGroup.getId()))) {
463             String existingId = null;
464             if (existingGroup != null) {
465                 existingId = existingGroup.getId();
466             }
467             PolicyLogger.error(MessageCodes.ERROR_DATA_ISSUE + " Group update had bad input. id=" + existingId
468                     + " objectFromJSON=" + group);
469             loggingContext.transactionEnded();
470             PolicyLogger.audit("Transaction Failed - See Error.log");
471             response = "No Group";
472             return response;
473         }
474         // The Path on the PAP side is not carried on the RESTful interface with the AC
475         // (because it is local to the PAP)
476         // so we need to fill that in before submitting the group for update
477         ((StdPDPGroup) group).setDirectory(((StdPDPGroup) existingGroup).getDirectory());
478         try {
479             acPutTransaction.updateGroup(group, "XACMLPapServlet.doDelete", userId);
480         } catch (Exception e) {
481             PolicyLogger.error(MessageCodes.ERROR_PROCESS_FLOW, e, "XACMLPapServlet",
482                     " Error while updating group in the database: " + "group=" + existingGroup.getId());
483             response = "DB Error";
484             return response;
485         }
486         try {
487             XACMLPapServlet.getPAPEngine().updateGroup(group);
488         } catch (PAPException e) {
489             PolicyLogger.error("Exception occured While Updating PDP Groups" + e);
490             response = "error in updateGroup method";
491         }
492         PolicyLogger.debug("Group '" + group.getId() + "' updated");
493         acPutTransaction.commitTransaction();
494         // Group changed, which might include changing the policies
495         try {
496             newgroup = existingGroup;
497         } catch (Exception e) {
498             PolicyLogger.error("Exception occured in Group Change Method" + e);
499             response = "error in groupChanged method";
500         }
501         if (response == null) {
502             response = SUCCESS;
503             loggingContext.transactionEnded();
504             PolicyLogger.audit("Policy successfully deleted!");
505         }
506         loggingContext.transactionEnded();
507         PolicyLogger.audit("Transaction Ended");
508         return response;
509     }
510
511     public OnapPDPGroup getDeletedGroup() {
512         return newgroup;
513     }
514
515     public boolean preSafetyCheck(PDPPolicy policy) {
516         return true;
517     }
518
519     /**
520      * Gets the single instance of DeleteHandler.
521      *
522      * @return single instance of DeleteHandler
523      */
524     public static DeleteHandler getInstance() {
525         try {
526             Class<?> deleteHandler = Class
527                     .forName(XACMLProperties.getProperty("deletePolicy.impl.className", DeleteHandler.class.getName()));
528             return (DeleteHandler) deleteHandler.newInstance();
529         } catch (Exception e) {
530             LOGGER.error(e.getMessage(), e);
531         }
532         return null;
533     }
534
535 }