Enhancement to use the common CryptoUtils
[policy/engine.git] / ONAP-PAP-REST / src / main / java / org / onap / policy / pap / xacml / rest / components / NotifyOtherPaps.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP-PAP-REST
4  * ================================================================================
5  * Copyright (C) 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.components;
22
23 import com.att.research.xacml.util.XACMLProperties;
24 import java.net.HttpURLConnection;
25 import java.net.MalformedURLException;
26 import java.net.ProtocolException;
27 import java.net.URL;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.Base64;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.UUID;
34 import org.onap.policy.common.logging.flexlogger.FlexLogger;
35 import org.onap.policy.common.logging.flexlogger.Logger;
36 import org.onap.policy.rest.XACMLRestProperties;
37 import org.onap.policy.rest.jpa.PolicyDBDaoEntity;
38 import org.onap.policy.utils.PeCryptoUtils;
39
40 public class NotifyOtherPaps {
41
42     private static final Logger LOGGER = FlexLogger.getLogger(NotifyOtherPaps.class);
43     private List<PolicyDBDaoEntity> failedPaps = null;
44
45     public void notifyOthers(long entityId, String entityType) {
46         notifyOthers(entityId, entityType, null);
47     }
48
49     /**
50      * Notify others.
51      *
52      * @param entityId the entity id
53      * @param entityType the entity type
54      * @param newGroupId the new group id
55      */
56     public void notifyOthers(long entityId, String entityType, String newGroupId) {
57         LOGGER.debug("notifyOthers(long entityId, String entityType, long newGroupId) as notifyOthers(" + entityId + ","
58                 + entityType + "," + newGroupId + ") called");
59         failedPaps = new ArrayList<>();
60
61         List<?> otherServers = PolicyDBDao.getPolicyDBDaoInstance().getOtherServers();
62         // Notify other paps
63         startNotifyThreads(otherServers, entityId, entityType, newGroupId);
64         // Retry for failed paps
65         if (!failedPaps.isEmpty()) {
66             startNotifyThreads(failedPaps, entityId, entityType, newGroupId);
67         }
68     }
69
70     private void startNotifyThreads(List<?> otherServers, long entityId, String entityType, String newGroupId) {
71         LinkedList<Thread> notifyThreads = new LinkedList<>();
72         // we're going to run notifications in parallel threads to speed things
73         // up
74         for (Object obj : otherServers) {
75             Thread newNotifyThread = new Thread(new NotifyOtherThread(obj, entityId, entityType, newGroupId));
76             newNotifyThread.start();
77             notifyThreads.add(newNotifyThread);
78         }
79         // we want to wait for all notifications to complete or timeout before
80         // we unlock the interface and allow more changes
81         for (Thread t : notifyThreads) {
82             try {
83                 t.join();
84             } catch (Exception e) {
85                 LOGGER.warn("Could not join a notifcation thread" + e);
86             }
87         }
88     }
89
90     private class NotifyOtherThread implements Runnable {
91         public NotifyOtherThread(Object obj, long entityId, String entityType, String newGroupId) {
92             this.obj = obj;
93             this.entityId = entityId;
94             this.entityType = entityType;
95             this.newGroupId = newGroupId;
96         }
97
98         private Object obj;
99         private long entityId;
100         private String entityType;
101         private String newGroupId;
102
103         @Override
104         public void run() {
105             PolicyDBDao dao = new PolicyDBDao();
106             PolicyDBDaoEntity dbdEntity = (PolicyDBDaoEntity) obj;
107             String otherPap = dbdEntity.getPolicyDBDaoUrl();
108             String username = dbdEntity.getUsername();
109             String txt;
110             try {
111                 txt = PeCryptoUtils.decrypt(dbdEntity.getPassword());
112             } catch (Exception e) {
113                 LOGGER.debug(e);
114                 // if we can't decrypt, might as well try it anyway
115                 txt = dbdEntity.getPassword();
116             }
117
118             HttpURLConnection connection = null;
119             UUID requestId = UUID.randomUUID();
120             URL url;
121             String papUrl;
122             try {
123                 String[] papUrlUserPass = dao.getPapUrlUserPass();
124                 if (papUrlUserPass == null) {
125                     papUrl = "undefined";
126                 } else {
127                     papUrl = papUrlUserPass[0];
128                 }
129                 LOGGER.debug("We are going to try to notify " + otherPap);
130                 // is this our own url?
131                 String ourUrl = otherPap;
132                 try {
133                     ourUrl = dao.splitPapUrlUserPass(otherPap)[0];
134                 } catch (Exception e) {
135                     ourUrl = otherPap;
136                     LOGGER.debug(e);
137                 }
138                 if (otherPap == null) {
139                     otherPap = "undefined";
140                 }
141                 if (papUrl.equals(ourUrl)) {
142                     LOGGER.debug(otherPap + " is our url, skipping notify");
143                     return;
144                 }
145                 if (newGroupId == null) {
146                     url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
147                             + entityType);
148                 } else {
149                     url = new URL(otherPap + "?policydbdaourl=" + papUrl + "&entityid=" + entityId + "&entitytype="
150                             + entityType + "&extradata=" + newGroupId);
151                 }
152             } catch (MalformedURLException e) {
153                 LOGGER.warn("Caught MalformedURLException on: new URL()", e);
154                 return;
155             }
156             //
157             // Open up the connection
158             //
159             LOGGER.info("PolicyDBDao: NotifyOtherThread: notifying other PAPs of an update");
160             LOGGER.info("Connecting with url: " + url);
161             try {
162                 connection = (HttpURLConnection) url.openConnection();
163             } catch (Exception e) {
164                 LOGGER.warn("Caught exception on: url.openConnection()", e);
165                 return;
166             }
167             //
168             // Setup our method and headers
169             //
170             try {
171                 connection.setRequestMethod("PUT");
172             } catch (ProtocolException e) {
173                 // why would this error ever occur?
174                 LOGGER.warn("Caught ProtocolException on connection.setRequestMethod(\"PUT\");", e);
175                 return;
176             }
177             Base64.Encoder encoder = Base64.getEncoder();
178             String encoding = encoder.encodeToString((username + ":" + txt).getBytes(StandardCharsets.UTF_8));
179             connection.setRequestProperty("Authorization", "Basic " + encoding);
180             connection.setRequestProperty("Accept", "text/x-java-properties");
181             connection.setRequestProperty("Content-Type", "text/x-java-properties");
182             connection.setRequestProperty("requestID", requestId.toString());
183             int readTimeout;
184             try {
185                 readTimeout =
186                         Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_NOTIFY_TIMEOUT));
187             } catch (Exception e) {
188                 LOGGER.error("xacml.rest.pap.notify.timeoutms property not set, using a default.", e);
189                 readTimeout = 10000;
190             }
191             connection.setReadTimeout(readTimeout);
192             connection.setConnectTimeout(readTimeout);
193             connection.setUseCaches(false);
194             //
195             // Adding this in. It seems the HttpUrlConnection class does NOT
196             // properly forward our headers for POST re-direction. It does so
197             // for a GET re-direction.
198             //
199             // So we need to handle this ourselves.
200             //
201             connection.setInstanceFollowRedirects(false);
202             connection.setDoOutput(true);
203             connection.setDoInput(true);
204             try {
205                 connection.connect();
206             } catch (Exception e) {
207                 LOGGER.warn("Caught exception on: connection.connect()", e);
208                 return;
209             }
210             try {
211                 if (connection.getResponseCode() == 200) {
212                     LOGGER.info("PolicyDBDao: NotifyOtherThread received response 200 from pap server on notify");
213                 } else {
214                     LOGGER.warn("PolicyDBDao: NotifyOtherThread connection response code not 200, received: "
215                             + connection.getResponseCode());
216                     failedPaps.add(dbdEntity);
217                 }
218             } catch (Exception e) {
219                 LOGGER.warn("Caught Exception on: connection.getResponseCode() ", e);
220             }
221
222             connection.disconnect();
223         }
224     }
225 }