Merge "Fix SubscribeServlet Vulnerabilities"
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / SubscribeServlet.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 2017 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  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24
25 package org.onap.dmaap.datarouter.provisioning;
26
27 import java.io.IOException;
28 import java.io.InvalidObjectException;
29 import java.util.Collection;
30
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.json.JSONObject;
35 import org.onap.dmaap.datarouter.authz.AuthorizationResponse;
36 import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord;
37 import org.onap.dmaap.datarouter.provisioning.beans.Feed;
38 import org.onap.dmaap.datarouter.provisioning.beans.Subscription;
39 import org.onap.dmaap.datarouter.provisioning.eelf.EelfMsgs;
40 import org.onap.dmaap.datarouter.provisioning.utils.JSONUtilities;
41
42 import com.att.eelf.configuration.EELFLogger;
43 import com.att.eelf.configuration.EELFManager;
44
45 import static org.onap.dmaap.datarouter.provisioning.utils.HttpServletUtils.sendResponseError;
46
47 /**
48  * This servlet handles provisioning for the <subscribeURL> which is generated by the provisioning server to
49  * handle the creation and inspection of subscriptions to a specific feed.
50  *
51  * @author Robert Eby
52  * @version $Id$
53  */
54 @SuppressWarnings("serial")
55 public class SubscribeServlet extends ProxyServlet {
56
57     //Adding EELF Logger Rally:US664892
58     private static EELFLogger eelflogger = EELFManager.getInstance()
59         .getLogger("org.onap.dmaap.datarouter.provisioning.SubscribeServlet");
60
61     /**
62      * DELETE on the <subscribeUrl> -- not supported.
63      */
64     @Override
65     public void doDelete(HttpServletRequest req, HttpServletResponse resp) {
66         setIpAndFqdnForEelf("doDelete");
67         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
68         String message = "DELETE not allowed for the subscribeURL.";
69         EventLogRecord elr = new EventLogRecord(req);
70         elr.setMessage(message);
71         elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
72         eventlogger.info(elr);
73         sendResponseError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED, message, eventlogger);
74     }
75
76     /**
77      * GET on the &lt;subscribeUrl&gt; -- get the list of subscriptions to a feed. See the <i>Subscription Collection
78      * Query</i> section in the <b>Provisioning API</b> document for details on how this method should be invoked.
79      */
80     @Override
81     public void doGet(HttpServletRequest req, HttpServletResponse resp) {
82         setIpAndFqdnForEelf("doGet");
83         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
84         EventLogRecord elr = new EventLogRecord(req);
85         String message = isAuthorizedForProvisioning(req);
86         if (message != null) {
87             elr.setMessage(message);
88             elr.setResult(HttpServletResponse.SC_FORBIDDEN);
89             eventlogger.info(elr);
90             sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
91             return;
92         }
93         if (isProxyServer()) {
94             try {
95                 super.doGet(req, resp);
96             } catch (IOException ioe) {
97                 eventlogger.error("IOException: " + ioe.getMessage());
98             }
99             return;
100         }
101         String bhdr = req.getHeader(BEHALF_HEADER);
102         if (bhdr == null) {
103             message = "Missing " + BEHALF_HEADER + " header.";
104             elr.setMessage(message);
105             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
106             eventlogger.info(elr);
107             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
108             return;
109         }
110         int feedid = getIdFromPath(req);
111         if (feedid < 0) {
112             message = "Missing or bad feed number.";
113             elr.setMessage(message);
114             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
115             eventlogger.info(elr);
116             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
117             return;
118         }
119         Feed feed = Feed.getFeedById(feedid);
120         if (feed == null || feed.isDeleted()) {
121             message = "Missing or bad feed number.";
122             elr.setMessage(message);
123             elr.setResult(HttpServletResponse.SC_NOT_FOUND);
124             eventlogger.info(elr);
125             sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger);
126             return;
127         }
128         // Check with the Authorizer
129         AuthorizationResponse aresp = authz.decide(req);
130         if (!aresp.isAuthorized()) {
131             message = "Policy Engine disallows access.";
132             elr.setMessage(message);
133             elr.setResult(HttpServletResponse.SC_FORBIDDEN);
134             eventlogger.info(elr);
135             sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
136             return;
137         }
138
139         // Display a list of URLs
140         Collection<String> list = Subscription.getSubscriptionUrlList(feedid);
141         String t = JSONUtilities.createJSONArray(list);
142
143         // send response
144         elr.setResult(HttpServletResponse.SC_OK);
145         eventlogger.info(elr);
146         resp.setStatus(HttpServletResponse.SC_OK);
147         resp.setContentType(SUBLIST_CONTENT_TYPE);
148         try {
149             resp.getOutputStream().print(t);
150         } catch (IOException ioe) {
151             eventlogger.error("IOException: " + ioe.getMessage());
152         }
153     }
154
155     /**
156      * PUT on the &lt;subscribeUrl&gt; -- not supported.
157      */
158     @Override
159     public void doPut(HttpServletRequest req, HttpServletResponse resp) {
160         setIpAndFqdnForEelf("doPut");
161         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
162         String message = "PUT not allowed for the subscribeURL.";
163         EventLogRecord elr = new EventLogRecord(req);
164         elr.setMessage(message);
165         elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
166         eventlogger.info(elr);
167         sendResponseError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED, message, eventlogger);
168     }
169
170     /**
171      * POST on the &lt;subscribeUrl&gt; -- create a new subscription to a feed. See the <i>Creating a Subscription</i>
172      * section in the <b>Provisioning API</b> document for details on how this method should be invoked.
173      */
174     @Override
175     public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
176         setIpAndFqdnForEelf("doPost");
177         eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF, req.getHeader(BEHALF_HEADER));
178         EventLogRecord elr = new EventLogRecord(req);
179         String message = isAuthorizedForProvisioning(req);
180         if (message != null) {
181             elr.setMessage(message);
182             elr.setResult(HttpServletResponse.SC_FORBIDDEN);
183             eventlogger.info(elr);
184             sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
185             return;
186         }
187         if (isProxyServer()) {
188             try {
189                 super.doPost(req, resp);
190             } catch (IOException ioe) {
191                 eventlogger.error("IOException: " + ioe.getMessage());
192             }
193             return;
194         }
195         String bhdr = req.getHeader(BEHALF_HEADER);
196         if (bhdr == null) {
197             message = "Missing " + BEHALF_HEADER + " header.";
198             elr.setMessage(message);
199             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
200             eventlogger.info(elr);
201             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
202             return;
203         }
204         int feedid = getIdFromPath(req);
205         if (feedid < 0) {
206             message = "Missing or bad feed number.";
207             elr.setMessage(message);
208             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
209             eventlogger.info(elr);
210             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
211             return;
212         }
213         Feed feed = Feed.getFeedById(feedid);
214         if (feed == null || feed.isDeleted()) {
215             message = "Missing or bad feed number.";
216             elr.setMessage(message);
217             elr.setResult(HttpServletResponse.SC_NOT_FOUND);
218             eventlogger.info(elr);
219             sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger);
220             return;
221         }
222         // Check with the Authorizer
223         AuthorizationResponse aresp = authz.decide(req);
224         if (!aresp.isAuthorized()) {
225             message = "Policy Engine disallows access.";
226             elr.setMessage(message);
227             elr.setResult(HttpServletResponse.SC_FORBIDDEN);
228             eventlogger.info(elr);
229             sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
230             return;
231         }
232
233         // check content type is SUB_CONTENT_TYPE, version 1.0
234         ContentHeader ch = getContentHeader(req);
235         String ver = ch.getAttribute("version");
236         if (!ch.getType().equals(SUB_BASECONTENT_TYPE) || !(ver.equals("1.0") || ver.equals("2.0"))) {
237             intlogger.debug("Content-type is: " + req.getHeader("Content-Type"));
238             message = "Incorrect content-type";
239             elr.setMessage(message);
240             elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
241             eventlogger.info(elr);
242             sendResponseError(resp, HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message, eventlogger);
243             return;
244         }
245         JSONObject jo = getJSONfromInput(req);
246         if (jo == null) {
247             message = "Badly formed JSON";
248             elr.setMessage(message);
249             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
250             eventlogger.info(elr);
251             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
252             return;
253         }
254         if (intlogger.isDebugEnabled()) {
255             intlogger.debug(jo.toString());
256         }
257         if (++activeSubs > maxSubs) {
258             activeSubs--;
259             message = "Cannot create subscription; the maximum number of subscriptions has been configured.";
260             elr.setMessage(message);
261             elr.setResult(HttpServletResponse.SC_CONFLICT);
262             eventlogger.info(elr);
263             sendResponseError(resp, HttpServletResponse.SC_CONFLICT, message, eventlogger);
264             return;
265         }
266         Subscription sub = null;
267         try {
268             sub = new Subscription(jo);
269         } catch (InvalidObjectException e) {
270             activeSubs--;
271             message = e.getMessage();
272             elr.setMessage(message);
273             elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
274             eventlogger.info(elr);
275             sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
276             return;
277         }
278         sub.setFeedid(feedid);
279         sub.setSubscriber(bhdr);    // set from X-ATT-DR-ON-BEHALF-OF header
280
281         // Check if this subscription already exists; not an error (yet), just warn
282         Subscription sub2 = Subscription.getSubscriptionMatching(sub);
283         if (sub2 != null) {
284             intlogger.warn(
285                 "PROV0011 Creating a duplicate subscription: new subid=" + sub.getSubid() + ", old subid=" + sub2
286                     .getSubid());
287         }
288
289         // Create SUBSCRIPTIONS table entries
290         if (doInsert(sub)) {
291             // send response
292             elr.setResult(HttpServletResponse.SC_CREATED);
293             eventlogger.info(elr);
294             resp.setStatus(HttpServletResponse.SC_CREATED);
295             resp.setContentType(SUBFULL_CONTENT_TYPE);
296             resp.setHeader("Location", sub.getLinks().getSelf());
297             try {
298                 resp.getOutputStream().print(sub.asLimitedJSONObject().toString());
299             } catch (IOException ioe) {
300                 eventlogger.error("IOException: " + ioe.getMessage());
301             }
302
303             provisioningDataChanged();
304         } else {
305             // Something went wrong with the INSERT
306             activeSubs--;
307             elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
308             eventlogger.info(elr);
309             sendResponseError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG, eventlogger);
310         }
311     }
312 }