DR AAF CADI integration
[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(SubscribeServlet.class);
60
61     /**
62      * DELETE on the <subscribeUrl> -- not supported.
63      */
64     @Override
65     public void doDelete(HttpServletRequest req, HttpServletResponse resp) {
66         setIpFqdnRequestIDandInvocationIDForEelf("doDelete", req);
67         eelflogger.info(EelfMsgs.ENTRY);
68         try {
69             eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
70             String message = "DELETE not allowed for the subscribeURL.";
71             EventLogRecord elr = new EventLogRecord(req);
72             elr.setMessage(message);
73             elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
74             eventlogger.info(elr);
75             sendResponseError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED, message, eventlogger);
76         } finally {
77             eelflogger.info(EelfMsgs.EXIT);
78         }
79     }
80
81     /**
82      * GET on the &lt;subscribeUrl&gt; -- get the list of subscriptions to a feed. See the <i>Subscription Collection
83      * Query</i> section in the <b>Provisioning API</b> document for details on how this method should be invoked.
84      */
85     @Override
86     public void doGet(HttpServletRequest req, HttpServletResponse resp) {
87         setIpFqdnRequestIDandInvocationIDForEelf("doGet", req);
88         eelflogger.info(EelfMsgs.ENTRY);
89         try {
90             eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
91             EventLogRecord elr = new EventLogRecord(req);
92             String message = isAuthorizedForProvisioning(req);
93             if (message != null) {
94                 elr.setMessage(message);
95                 elr.setResult(HttpServletResponse.SC_FORBIDDEN);
96                 eventlogger.info(elr);
97                 sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
98                 return;
99             }
100             if (isProxyServer()) {
101                 super.doGet(req, resp);
102                 return;
103             }
104             String bhdr = req.getHeader(BEHALF_HEADER);
105             if (bhdr == null) {
106                 message = "Missing " + BEHALF_HEADER + " header.";
107                 elr.setMessage(message);
108                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
109                 eventlogger.info(elr);
110                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
111                 return;
112             }
113             int feedid = getIdFromPath(req);
114             if (feedid < 0) {
115                 message = "Missing or bad feed number.";
116                 elr.setMessage(message);
117                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
118                 eventlogger.info(elr);
119                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
120                 return;
121             }
122             Feed feed = Feed.getFeedById(feedid);
123             if (feed == null || feed.isDeleted()) {
124                 message = "Missing or bad feed number.";
125                 elr.setMessage(message);
126                 elr.setResult(HttpServletResponse.SC_NOT_FOUND);
127                 eventlogger.info(elr);
128                 sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger);
129                 return;
130             }
131             // Display a list of URLs
132             Collection<String> list = Subscription.getSubscriptionUrlList(feedid);
133             String t = JSONUtilities.createJSONArray(list);
134
135             // send response
136             elr.setResult(HttpServletResponse.SC_OK);
137             eventlogger.info(elr);
138             resp.setStatus(HttpServletResponse.SC_OK);
139             resp.setContentType(SUBLIST_CONTENT_TYPE);
140             try {
141                 resp.getOutputStream().print(t);
142             } catch (IOException ioe) {
143                 eventlogger.error("IOException: " + ioe.getMessage());
144             }
145         } finally {
146             eelflogger.info(EelfMsgs.EXIT);
147         }
148     }
149
150     /**
151      * PUT on the &lt;subscribeUrl&gt; -- not supported.
152      */
153     @Override
154     public void doPut(HttpServletRequest req, HttpServletResponse resp) {
155         setIpFqdnRequestIDandInvocationIDForEelf("doPut", req);
156         eelflogger.info(EelfMsgs.ENTRY);
157         try {
158             eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF_AND_SUBID, req.getHeader(BEHALF_HEADER), getIdFromPath(req) + "");
159             String message = "PUT not allowed for the subscribeURL.";
160             EventLogRecord elr = new EventLogRecord(req);
161             elr.setMessage(message);
162             elr.setResult(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
163             eventlogger.info(elr);
164             sendResponseError(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED, message, eventlogger);
165         } finally {
166             eelflogger.info(EelfMsgs.EXIT);
167         }
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) {
176         setIpFqdnRequestIDandInvocationIDForEelf("doPost", req);
177         eelflogger.info(EelfMsgs.ENTRY);
178         try {
179             eelflogger.info(EelfMsgs.MESSAGE_WITH_BEHALF, req.getHeader(BEHALF_HEADER));
180             EventLogRecord elr = new EventLogRecord(req);
181             String message = isAuthorizedForProvisioning(req);
182             if (message != null) {
183                 elr.setMessage(message);
184                 elr.setResult(HttpServletResponse.SC_FORBIDDEN);
185                 eventlogger.info(elr);
186                 sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
187                 return;
188             }
189             if (isProxyServer()) {
190                 super.doPost(req, resp);
191                 return;
192             }
193             String bhdr = req.getHeader(BEHALF_HEADER);
194             if (bhdr == null) {
195                 message = "Missing " + BEHALF_HEADER + " header.";
196                 elr.setMessage(message);
197                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
198                 eventlogger.info(elr);
199                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
200                 return;
201             }
202             int feedid = getIdFromPath(req);
203             if (feedid < 0) {
204                 message = "Missing or bad feed number.";
205                 elr.setMessage(message);
206                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
207                 eventlogger.info(elr);
208                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
209                 return;
210             }
211             Feed feed = Feed.getFeedById(feedid);
212             if (feed == null || feed.isDeleted()) {
213                 message = "Missing or bad feed number.";
214                 elr.setMessage(message);
215                 elr.setResult(HttpServletResponse.SC_NOT_FOUND);
216                 eventlogger.info(elr);
217                 sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, message, eventlogger);
218                 return;
219             }
220             // check content type is SUB_CONTENT_TYPE, version 1.0
221             ContentHeader ch = getContentHeader(req);
222             String ver = ch.getAttribute("version");
223             if (!ch.getType().equals(SUB_BASECONTENT_TYPE) || !(ver.equals("1.0") || ver.equals("2.0"))) {
224                 intlogger.debug("Content-type is: " + req.getHeader("Content-Type"));
225                 message = "Incorrect content-type";
226                 elr.setMessage(message);
227                 elr.setResult(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
228                 eventlogger.info(elr);
229                 sendResponseError(resp, HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, message, eventlogger);
230                 return;
231             }
232             JSONObject jo = getJSONfromInput(req);
233             if (jo == null) {
234                 message = "Badly formed JSON";
235                 elr.setMessage(message);
236                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
237                 eventlogger.info(elr);
238                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
239                 return;
240             }
241             if (intlogger.isDebugEnabled()) {
242                 intlogger.debug(jo.toString());
243             }
244             if (++activeSubs > maxSubs) {
245                 activeSubs--;
246                 message = "Cannot create subscription; the maximum number of subscriptions has been configured.";
247                 elr.setMessage(message);
248                 elr.setResult(HttpServletResponse.SC_CONFLICT);
249                 eventlogger.info(elr);
250                 sendResponseError(resp, HttpServletResponse.SC_CONFLICT, message, eventlogger);
251                 return;
252             }
253             Subscription sub;
254             try {
255                 sub = new Subscription(jo);
256             } catch (InvalidObjectException e) {
257                 activeSubs--;
258                 message = e.getMessage();
259                 elr.setMessage(message);
260                 elr.setResult(HttpServletResponse.SC_BAD_REQUEST);
261                 eventlogger.info(elr);
262                 sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, message, eventlogger);
263                 return;
264             }
265             sub.setFeedid(feedid);
266             sub.setSubscriber(bhdr);    // set from X-DMAAP-DR-ON-BEHALF-OF header
267             /*
268              * START - AAF changes
269              * TDP EPIC US# 307413
270              * CADI code - check on permissions based on Legacy/AAF users to allow to create/add subscription
271              */
272             String feedAafInstance = feed.getAafInstance();
273             String subAafInstance = sub.getAafInstance();
274             boolean subAafLegacyEmptyOrNull = (subAafInstance == null || subAafInstance.equals("") || subAafInstance.equalsIgnoreCase("legacy"));
275
276             // This extra check added to verify AAF feed with AAF subscriber having empty aaf instance check
277             if (feedAafInstance == null || feedAafInstance.equals("") || feedAafInstance.equalsIgnoreCase("legacy")) {
278                 if (subAafLegacyEmptyOrNull) {
279                     AuthorizationResponse aresp = authz.decide(req);
280                     if (!aresp.isAuthorized()) {
281                         message = "Policy Engine disallows access";
282                         elr.setMessage(message);
283                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);
284                         eventlogger.info(elr);
285                         sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
286                         return;
287                     }
288                 } else {
289                     //If Legacy Feed and AAF instance provided in Subscriber JSON
290                     message = "AAF Subscriber can not be added to legacy Feed- " + feedid;
291                     elr.setMessage(message);
292                     elr.setResult(HttpServletResponse.SC_FORBIDDEN);
293                     eventlogger.info(elr);
294                     sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
295                     return;
296                 }
297             } else {
298                 //New AAF Requirement to add legacy subscriber to AAF Feed
299                 if (subAafLegacyEmptyOrNull) {
300                     AuthorizationResponse aresp = authz.decide(req);
301                     if (!aresp.isAuthorized()) {
302                         message = "Policy Engine disallows access.";
303                         elr.setMessage(message);
304                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);
305                         eventlogger.info(elr);
306                         sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
307                         return;
308                     }
309                 } else {
310                     //New AAF Requirement to add subscriber by publisher on publisher approval only
311                     String permission = getSubscriberPermission(subAafInstance, BaseServlet.APPROVE_SUB_PERMISSION);
312                     eventlogger.info("SubscribeServlet.doPost().. Permission String - " + permission);
313                     if (!req.isUserInRole(permission)) {
314                         message = "AAF disallows access to permission - " + permission;
315                         elr.setMessage(message);
316                         elr.setResult(HttpServletResponse.SC_FORBIDDEN);
317                         eventlogger.info(elr);
318                         sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, message, eventlogger);
319                         return;
320                     }
321                 }
322             }
323             /*
324              * END - AAF changes
325              */
326             // Check if this subscription already exists; not an error (yet), just warn
327             Subscription sub2 = Subscription.getSubscriptionMatching(sub);
328             if (sub2 != null) {
329                 intlogger.warn(
330                     "PROV0011 Creating a duplicate subscription: new subid=" + sub.getSubid() + ", old subid=" + sub2.getSubid());
331             }
332
333             // Create SUBSCRIPTIONS table entries
334             if (doInsert(sub)) {
335                 // send response
336                 elr.setResult(HttpServletResponse.SC_CREATED);
337                 eventlogger.info(elr);
338                 resp.setStatus(HttpServletResponse.SC_CREATED);
339                 resp.setContentType(SUBFULL_CONTENT_TYPE);
340                 resp.setHeader("Location", sub.getLinks().getSelf());
341                 try {
342                     resp.getOutputStream().print(sub.asLimitedJSONObject().toString());
343                 } catch (IOException ioe) {
344                     eventlogger.error("IOException: " + ioe.getMessage());
345                 }
346
347                 provisioningDataChanged();
348             } else {
349                 // Something went wrong with the INSERT
350                 activeSubs--;
351                 elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
352                 eventlogger.info(elr);
353                 sendResponseError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG, eventlogger);
354             }
355         } finally {
356             eelflogger.info(EelfMsgs.EXIT);
357         }
358     }
359 }