DR AAF CADI integration
[dmaap/datarouter.git] / datarouter-prov / src / test / java / org / onap / dmaap / datarouter / provisioning / SubscribeServletTest.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 package org.onap.dmaap.datarouter.provisioning;
24
25 import ch.qos.logback.classic.spi.ILoggingEvent;
26 import ch.qos.logback.core.read.ListAppender;
27 import org.apache.commons.lang3.reflect.FieldUtils;
28 import org.jetbrains.annotations.NotNull;
29 import org.json.JSONObject;
30 import org.junit.AfterClass;
31 import org.junit.Before;
32 import org.junit.BeforeClass;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.mockito.Mock;
36 import org.onap.dmaap.datarouter.authz.AuthorizationResponse;
37 import org.onap.dmaap.datarouter.authz.Authorizer;
38 import org.onap.dmaap.datarouter.provisioning.beans.Insertable;
39 import org.onap.dmaap.datarouter.provisioning.beans.Subscription;
40 import org.onap.dmaap.datarouter.provisioning.utils.DB;
41 import org.powermock.api.mockito.PowerMockito;
42 import org.powermock.core.classloader.annotations.PrepareForTest;
43 import org.powermock.modules.junit4.PowerMockRunner;
44
45 import javax.persistence.EntityManager;
46 import javax.persistence.EntityManagerFactory;
47 import javax.persistence.Persistence;
48 import javax.servlet.ServletOutputStream;
49 import javax.servlet.http.HttpServletRequest;
50 import javax.servlet.http.HttpServletResponse;
51 import java.util.ArrayList;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Set;
55
56 import static org.hamcrest.Matchers.notNullValue;
57 import static org.mockito.Mockito.*;
58 import static org.onap.dmaap.datarouter.provisioning.BaseServlet.BEHALF_HEADER;
59
60
61 @RunWith(PowerMockRunner.class)
62 @PrepareForTest(Subscription.class)
63 public class SubscribeServletTest extends DrServletTestBase {
64     private static SubscribeServlet subscribeServlet;
65     private static EntityManagerFactory emf;
66     private static EntityManager em;
67     private DB db;
68
69     @Mock
70     private HttpServletRequest request;
71     @Mock
72     private HttpServletResponse response;
73
74     private ListAppender<ILoggingEvent> listAppender;
75
76     @BeforeClass
77     public static void init() {
78         emf = Persistence.createEntityManagerFactory("dr-unit-tests");
79         em = emf.createEntityManager();
80         System.setProperty(
81                 "org.onap.dmaap.datarouter.provserver.properties",
82                 "src/test/resources/h2Database.properties");
83     }
84
85     @AfterClass
86     public static void tearDownClass() {
87         em.clear();
88         em.close();
89         emf.close();
90     }
91
92     @Before
93     public void setUp() throws Exception {
94         db = new DB();
95         listAppender = setTestLogger(SubscribeServlet.class);
96         subscribeServlet = new SubscribeServlet();
97         setAuthoriserToReturnRequestIsAuthorized();
98         setPokerToNotCreateTimersWhenDeleteFeedIsCalled();
99         setupValidAuthorisedRequest();
100         setUpValidSecurityOnHttpRequest();
101         setUpValidContentHeadersAndJSONOnHttpRequest();
102     }
103
104     @Test
105     public void Given_Request_Is_HTTP_DELETE_SC_METHOD_NOT_ALLOWED_Response_Is_Generated() throws Exception {
106         subscribeServlet.doDelete(request, response);
107         verify(response).sendError(eq(HttpServletResponse.SC_METHOD_NOT_ALLOWED), argThat(notNullValue(String.class)));
108         verifyEnteringExitCalled(listAppender);
109     }
110
111     @Test
112     public void Given_Request_Is_HTTP_GET_And_Is_Not_Secure_When_HTTPS_Is_Required_Then_Forbidden_Response_Is_Generated() throws Exception {
113         when(request.isSecure()).thenReturn(false);
114         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isAddressAuthEnabled", "true", true);
115         subscribeServlet.doGet(request, response);
116         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class)));
117         verifyEnteringExitCalled(listAppender);
118     }
119
120     @Test
121     public void Given_Request_Is_HTTP_GET_And_BEHALF_HEADER_Is_Not_Set_In_Request_Then_Bad_Request_Response_Is_Generated() throws Exception {
122         setBehalfHeader(null);
123         subscribeServlet.doGet(request, response);
124         verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class)));
125     }
126
127
128     @Test
129     public void Given_Request_Is_HTTP_GET_And_Path_Header_Is_Not_Set_In_Request_With_Valid_Path_Then_Bad_Request_Response_Is_Generated() throws Exception {
130         when(request.getPathInfo()).thenReturn(null);
131         subscribeServlet.doGet(request, response);
132         verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class)));
133     }
134
135     @Test
136     public void Given_Request_Is_HTTP_GET_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception {
137         when(request.getPathInfo()).thenReturn("/123");
138         subscribeServlet.doGet(request, response);
139         verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class)));
140     }
141
142     @Test
143     public void Given_Request_Is_HTTP_GET_And_Request_Succeeds() throws Exception {
144         ServletOutputStream outStream = mock(ServletOutputStream.class);
145         when(response.getOutputStream()).thenReturn(outStream);
146         when(request.getPathInfo()).thenReturn("/1");
147         PowerMockito.mockStatic(Subscription.class);
148         List<String> list = new ArrayList<>();
149         list.add("{}");
150         PowerMockito.when(Subscription.getSubscriptionUrlList(anyInt())).thenReturn(list);
151         subscribeServlet.doGet(request, response);
152         verify(response).setStatus(eq(HttpServletResponse.SC_OK));
153         verifyEnteringExitCalled(listAppender);
154     }
155
156
157     @Test
158     public void Given_Request_Is_HTTP_PUT_SC_METHOD_NOT_ALLOWED_Response_Is_Generated() throws Exception {
159         subscribeServlet.doPut(request, response);
160         verify(response).sendError(eq(HttpServletResponse.SC_METHOD_NOT_ALLOWED), argThat(notNullValue(String.class)));
161         verifyEnteringExitCalled(listAppender);
162     }
163     @Test
164     public void Given_Request_Is_HTTP_POST_And_Is_Not_Secure_When_HTTPS_Is_Required_Then_Forbidden_Response_Is_Generated() throws Exception {
165         when(request.isSecure()).thenReturn(false);
166         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "isAddressAuthEnabled", "true", true);
167         subscribeServlet.doPost(request, response);
168         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class)));
169         verifyEnteringExitCalled(listAppender);
170     }
171
172     @Test
173     public void Given_Request_Is_HTTP_POST_And_BEHALF_HEADER_Is_Not_Set_In_Request_Then_Bad_Request_Response_Is_Generated() throws Exception {
174         setBehalfHeader(null);
175         subscribeServlet.doPost(request, response);
176         verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class)));
177     }
178
179
180     @Test
181     public void Given_Request_Is_HTTP_POST_And_Path_Header_Is_Not_Set_In_Request_With_Valid_Path_Then_Bad_Request_Response_Is_Generated() throws Exception {
182         when(request.getPathInfo()).thenReturn(null);
183         subscribeServlet.doPost(request, response);
184         verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class)));
185     }
186
187
188     @Test
189     public void Given_Request_Is_HTTP_POST_And_Feed_Id_Is_Invalid_Then_Not_Found_Response_Is_Generated() throws Exception {
190         when(request.getPathInfo()).thenReturn("/123");
191         subscribeServlet.doPost(request, response);
192         verify(response).sendError(eq(HttpServletResponse.SC_NOT_FOUND), argThat(notNullValue(String.class)));
193     }
194
195     @Test
196     public void Given_Request_Is_HTTP_POST_And_Request_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception {
197         setAuthoriserToReturnRequestNotAuthorized();
198         when(request.getPathInfo()).thenReturn("/1");
199         JSONObject JSObject = buildRequestJsonObject();
200         SubscribeServlet subscribeServlet = new SubscribeServlet() {
201             protected JSONObject getJSONfromInput(HttpServletRequest req) {
202                 JSONObject jo = new JSONObject();
203                 jo.put("name", "stub_name");
204                 jo.put("version", "2.0");
205                 jo.put("metadataOnly", true);
206                 jo.put("suspend", true);
207                 jo.put("delivery", JSObject);
208                 jo.put("sync", false);
209                 return jo;
210             }
211             @Override
212             protected boolean doInsert(Insertable bean) {
213                 return false;
214             }
215         };
216         subscribeServlet.doPost(request, response);
217         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), argThat(notNullValue(String.class)));
218     }
219
220     @Test
221     public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_Legacy_Feed_Then_Forbidden_Response_Is_Generated() throws Exception {
222         when(request.getPathInfo()).thenReturn("/1");
223         JSONObject JSObject = buildRequestJsonObject();
224         SubscribeServlet subscribeServlet = new SubscribeServlet() {
225             protected JSONObject getJSONfromInput(HttpServletRequest req) {
226                 JSONObject jo = new JSONObject();
227                 jo.put("name", "stub_name");
228                 jo.put("version", "2.0");
229                 jo.put("metadataOnly", true);
230                 jo.put("suspend", true);
231                 jo.put("delivery", JSObject);
232                 jo.put("aaf_instance", "*");
233                 jo.put("follow_redirect", false);
234                 jo.put("sync", false);
235                 return jo;
236             }
237             @Override
238             protected boolean doInsert(Insertable bean) {
239                 return false;
240             }
241         };
242         subscribeServlet.doPost(request, response);
243         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF Subscriber can not be added to legacy Feed"));
244     }
245
246     @Test
247     public void Given_Request_Is_HTTP_POST_And_Legacy_Subscriber_Added_To_AAF_Feed_And_Is_Not_Authorized_Then_Forbidden_Response_Is_Generated() throws Exception {
248         setAuthoriserToReturnRequestNotAuthorized();
249         when(request.getPathInfo()).thenReturn("/2");
250         JSONObject JSObject = buildRequestJsonObject();
251         SubscribeServlet subscribeServlet = new SubscribeServlet() {
252             protected JSONObject getJSONfromInput(HttpServletRequest req) {
253                 JSONObject jo = new JSONObject();
254                 jo.put("name", "stub_name");
255                 jo.put("version", "2.0");
256                 jo.put("metadataOnly", true);
257                 jo.put("suspend", true);
258                 jo.put("delivery", JSObject);
259                 jo.put("aaf_instance", "legacy");
260                 jo.put("follow_redirect", false);
261                 jo.put("sync", false);
262                 return jo;
263             }
264         };
265         subscribeServlet.doPost(request, response);
266         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("Policy Engine disallows access."));
267     }
268
269     @Test
270     public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_AAF_Feed_Without_Permissions_Then_Forbidden_Response_Is_Generated() throws Exception {
271         when(request.getPathInfo()).thenReturn("/2");
272         JSONObject JSObject = buildRequestJsonObject();
273         SubscribeServlet subscribeServlet = new SubscribeServlet() {
274             protected JSONObject getJSONfromInput(HttpServletRequest req) {
275                 JSONObject jo = new JSONObject();
276                 jo.put("name", "stub_name");
277                 jo.put("version", "2.0");
278                 jo.put("metadataOnly", true);
279                 jo.put("suspend", true);
280                 jo.put("delivery", JSObject);
281                 jo.put("aaf_instance", "*");
282                 jo.put("follow_redirect", false);
283                 jo.put("sync", false);
284                 return jo;
285             }
286         };
287         subscribeServlet.doPost(request, response);
288         verify(response).sendError(eq(HttpServletResponse.SC_FORBIDDEN), contains("AAF disallows access to permission"));
289     }
290
291     @Test
292     public void Given_Request_Is_HTTP_POST_And_AAF_Subscriber_Added_To_AAF_Feed_With_Permissions_Then_OK_Response_Is_Generated() throws Exception {
293         ServletOutputStream outStream = mock(ServletOutputStream.class);
294         when(response.getOutputStream()).thenReturn(outStream);
295         when(request.getPathInfo()).thenReturn("/2");
296         when(request.isUserInRole("org.onap.dmaap-dr.feed|*|approveSub")).thenReturn(true);
297         PowerMockito.mockStatic(Subscription.class);
298         PowerMockito.when(Subscription.getSubscriptionMatching(new Subscription())).thenReturn(null);
299         JSONObject JSObject = buildRequestJsonObject();
300         SubscribeServlet subscribeServlet = new SubscribeServlet() {
301             protected JSONObject getJSONfromInput(HttpServletRequest req) {
302                 JSONObject jo = new JSONObject();
303                 jo.put("name", "stub_name");
304                 jo.put("version", "2.0");
305                 jo.put("metadataOnly", true);
306                 jo.put("suspend", true);
307                 jo.put("delivery", JSObject);
308                 jo.put("aaf_instance", "*");
309                 jo.put("follow_redirect", false);
310                 jo.put("sync", false);
311                 return jo;
312             }
313
314             @Override
315             protected boolean doInsert(Insertable bean) {
316                 return true;
317             }
318         };
319         subscribeServlet.doPost(request, response);
320         verify(response).setStatus(eq(HttpServletResponse.SC_CREATED));
321         verifyEnteringExitCalled(listAppender);
322     }
323
324     @Test
325     public void Given_Request_Is_HTTP_POST_And_Content_Header_Is_Not_Supported_Type_Then_Unsupported_Media_Type_Response_Is_Generated() throws Exception {
326         when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.feed; version=1.1");
327         when(request.getContentType()).thenReturn("stub_contentType");
328         when(request.getPathInfo()).thenReturn("/1");
329         subscribeServlet.doPost(request, response);
330         verify(response).sendError(eq(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE), argThat(notNullValue(String.class)));
331     }
332
333     @Test
334     public void Given_Request_Is_HTTP_POST_And_Request_Contains_Badly_Formed_JSON_Then_Bad_Request_Response_Is_Generated() throws Exception {
335         when(request.getPathInfo()).thenReturn("/1");
336         subscribeServlet.doPost(request, response);
337         verify(response).sendError(eq(HttpServletResponse.SC_BAD_REQUEST), argThat(notNullValue(String.class)));
338     }
339
340     @Test
341     public void Given_Request_Is_HTTP_POST_And_Active_Feeds_Equals_Max_Feeds_Then_Bad_Request_Response_Is_Generated() throws Exception {
342         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxSubs", 0, true);
343         when(request.getPathInfo()).thenReturn("/1");
344         SubscribeServlet subscribeServlet = new SubscribeServlet() {
345             protected JSONObject getJSONfromInput(HttpServletRequest req) {
346                 return new JSONObject();
347             }
348         };
349         subscribeServlet.doPost(request, response);
350         verify(response).sendError(eq(HttpServletResponse.SC_CONFLICT), argThat(notNullValue(String.class)));
351     }
352
353     @Test
354     public void Given_Request_Is_HTTP_POST_And_POST_Fails_Bad_Request_Response_Is_Generated() throws Exception {
355         when(request.getPathInfo()).thenReturn("/2");
356         PowerMockito.mockStatic(Subscription.class);
357         PowerMockito.when(Subscription.getSubscriptionMatching(new Subscription())).thenReturn(null);
358         JSONObject JSObject = buildRequestJsonObject();
359         SubscribeServlet subscribeServlet = new SubscribeServlet() {
360             protected JSONObject getJSONfromInput(HttpServletRequest req) {
361                 JSONObject jo = new JSONObject();
362                 jo.put("name", "stub_name");
363                 jo.put("version", "2.0");
364                 jo.put("metadataOnly", true);
365                 jo.put("suspend", true);
366                 jo.put("delivery", JSObject);
367                 jo.put("aaf_instance", "legacy");
368                 jo.put("follow_redirect", false);
369                 jo.put("sync", false);
370                 return jo;
371             }
372
373             @Override
374             protected boolean doInsert(Insertable bean) {
375                 return false;
376             }
377         };
378         subscribeServlet.doPost(request, response);
379         verify(response).sendError(eq(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), argThat(notNullValue(String.class)));
380     }
381
382     @NotNull
383     private JSONObject buildRequestJsonObject() {
384         JSONObject JSObject = new JSONObject();
385         JSObject.put("url", "https://stub_address");
386         JSObject.put("use100", "true");
387         JSObject.put("password", "stub_password");
388         JSObject.put("user", "stub_user");
389         return JSObject;
390     }
391
392     private void setUpValidSecurityOnHttpRequest() throws Exception {
393         when(request.isSecure()).thenReturn(true);
394         Set<String> authAddressesAndNetworks = new HashSet<>();
395         authAddressesAndNetworks.add(("127.0.0.1"));
396         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "authorizedAddressesAndNetworks", authAddressesAndNetworks, true);
397         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "requireCert", false, true);
398         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "maxSubs", 100, true);
399     }
400
401     private void setBehalfHeader(String headerValue) {
402         when(request.getHeader(BEHALF_HEADER)).thenReturn(headerValue);
403     }
404
405     private void setAuthoriserToReturnRequestNotAuthorized() throws IllegalAccessException {
406         AuthorizationResponse authResponse = mock(AuthorizationResponse.class);
407         Authorizer authorizer = mock(Authorizer.class);
408         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "authz", authorizer, true);
409         when(authorizer.decide(request)).thenReturn(authResponse);
410         when(authResponse.isAuthorized()).thenReturn(false);
411     }
412
413     private void setAuthoriserToReturnRequestIsAuthorized() throws IllegalAccessException {
414         AuthorizationResponse authResponse = mock(AuthorizationResponse.class);
415         Authorizer authorizer = mock(Authorizer.class);
416         FieldUtils.writeDeclaredStaticField(BaseServlet.class, "authz", authorizer, true);
417         when(authorizer.decide(request)).thenReturn(authResponse);
418         when(authResponse.isAuthorized()).thenReturn(true);
419     }
420
421     private void setPokerToNotCreateTimersWhenDeleteFeedIsCalled() throws Exception {
422         Poker poker = mock(Poker.class);
423         FieldUtils.writeDeclaredStaticField(Poker.class, "poker", poker, true);
424     }
425
426     private void setupValidAuthorisedRequest() throws Exception {
427         setUpValidSecurityOnHttpRequest();
428         setBehalfHeader("Stub_Value");
429     }
430
431     private void setUpValidContentHeadersAndJSONOnHttpRequest() {
432         when(request.getHeader("Content-Type")).thenReturn("application/vnd.dmaap-dr.subscription; version=1.0");
433         when(request.getHeader("X-DMAAP-DR-ON-BEHALF-OF-GROUP")).thenReturn("stub_subjectGroup");
434
435     }
436 }