Inventory TreeView Fixed
[ccsdk/features.git] / sdnr / wt / oauth-provider / oauth-core / src / test / java / org / onap / ccsdk / features / sdnr / wt / oauthprovider / test / TestAuthHttpServlet.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk features
4  * ================================================================================
5  * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
6  * All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  */
22 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.test;
23
24 import java.util.Set;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.fail;
28 import org.junit.Ignore;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 import com.fasterxml.jackson.core.JsonParseException;
34 import com.fasterxml.jackson.core.JsonProcessingException;
35 import com.fasterxml.jackson.databind.JsonMappingException;
36 import com.google.common.util.concurrent.FluentFuture;
37 import java.io.File;
38 import java.io.IOException;
39 import java.nio.charset.StandardCharsets;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.Optional;
43 import javax.servlet.ServletException;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.servlet.http.HttpServletResponse;
46 import org.jolokia.osgi.security.Authenticator;
47 import org.json.JSONArray;
48 import org.junit.BeforeClass;
49 import org.junit.Test;
50 import org.mockito.internal.matchers.Any;
51 import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
52 import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToByteArrayOutputStream;
53 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
54 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.CustomObjectMapper;
55 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
56 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
57 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
58 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
59 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.HeadersOnlyHttpServletRequest;
60 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
61 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlJsonMapper;
62 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlXmlMapper;
63 import org.opendaylight.aaa.api.Claim;
64 import org.opendaylight.aaa.api.IdMService;
65 import org.apache.shiro.authc.BearerToken;
66 import org.opendaylight.aaa.api.PasswordCredentialAuth;
67 import org.opendaylight.aaa.api.PasswordCredentials;
68 import org.opendaylight.aaa.shiro.web.env.AAAShiroWebEnvironment;
69 import org.opendaylight.mdsal.binding.api.DataBroker;
70 import org.opendaylight.mdsal.binding.api.ReadTransaction;
71 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfigurationBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.Policies;
76 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78
79
80 public class TestAuthHttpServlet {
81
82     private static final String TESTCONFIGFILE = TestConfig.TEST_CONFIG_FILENAME;
83     private static final String TESTSHIROCONFIGFILE = "src/test/resources/aaa-app-config.test.xml";
84     private static final String MDSALDYNAUTHFILENAME = "src/test/resources/mdsalDynAuthData.json";
85     private static TestServlet servlet;
86     private static DataBroker dataBroker = loadDynamicMdsalAuthDataBroker();
87     private static Authenticator odlAuthenticator = mock(Authenticator.class);
88     private static IdMService odlIdentityService = mock(IdMService.class);
89     private static PasswordCredentialAuth passwordCredentialAuth;
90     private static TokenCreator tokenCreator;
91 //    private static final HttpServletRequest authreq = new HeadersOnlyHttpServletRequest(
92 //            Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
93
94     @BeforeClass
95     public static void init() throws IllegalArgumentException, Exception {
96
97         try {
98             Config config = createConfigFile();
99             tokenCreator = TokenCreator.getInstance(config);
100             servlet = new TestServlet();
101         } catch (IOException | InvalidConfigurationException e) {
102             fail(e.getMessage());
103         }
104         servlet.setDataBroker(dataBroker);
105         passwordCredentialAuth = mock(PasswordCredentialAuth.class);
106
107         servlet.setPasswordCredentialAuth(passwordCredentialAuth);
108     }
109
110     private static DataBroker loadDynamicMdsalAuthDataBroker() {
111         DataBroker dataBroker = mock(DataBroker.class);
112         ReadTransaction rotx = mock(ReadTransaction.class);
113         InstanceIdentifier<Policies> iif = InstanceIdentifier.create(HttpAuthorization.class).child(Policies.class);
114         try {
115             when(rotx.read(LogicalDatastoreType.CONFIGURATION, iif))
116                     .thenReturn(loadDataBrokerFile(MDSALDYNAUTHFILENAME, Policies.class));
117         } catch (IOException e) {
118             fail("problem init databroker read" + e.getMessage());
119         }
120         when(dataBroker.newReadOnlyTransaction()).thenReturn(rotx);
121         return dataBroker;
122     }
123
124     private static <T> FluentFuture<Optional<T>> loadDataBrokerFile(String fn, Class<T> clazz) throws IOException {
125         return FluentFutures.immediateFluentFuture(Optional.ofNullable(readJson(new File(fn), clazz)));
126     }
127
128     private static ShiroConfiguration loadShiroConfig(String filename)
129             throws JsonParseException, JsonMappingException, IOException {
130         OdlXmlMapper mapper = new OdlXmlMapper();
131         return mapper.readValue(new File(filename), ShiroConfigurationBuilder.class).build();
132     }
133
134     private static Config createConfigFile() throws IOException, InvalidConfigurationException {
135         return Config.getInstance(TESTCONFIGFILE);
136
137     }
138
139     @Test
140     public void testValidLoginRedirect() {
141
142         HttpServletRequest req = mock(HttpServletRequest.class);
143         when(req.getRequestURI()).thenReturn("/oauth/login/keycloak");
144         HttpServletResponse resp = mock(HttpServletResponse.class);
145         try {
146             servlet.doGet(req, resp);
147         } catch (ServletException | IOException e) {
148             fail(e.getMessage());
149         }
150         verify(resp).setStatus(302);
151         verify(resp).setHeader("Location",
152                 "http://10.20.11.160:8080/auth/realms/onap/protocol/openid-connect/auth?client_id=odlux.app&response"
153                         + "_type=code&scope=openid&redirect_uri=http%3A%2F%2Fnasp.diasf.de%2Foauth%2Fredirect%2Fkeycloak");
154     }
155
156     @Test
157     public void testInValidLoginRedirect() {
158
159         HttpServletRequest req = mock(HttpServletRequest.class);
160         when(req.getRequestURI()).thenReturn("/oauth/login/unknownproviderid");
161         HttpServletResponse resp = mock(HttpServletResponse.class);
162         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
163         try {
164             when(resp.getOutputStream()).thenReturn(printOut);
165             servlet.doGet(req, resp);
166         } catch (ServletException | IOException e) {
167             fail(e.getMessage());
168         }
169         verify(resp).setStatus(404);
170     }
171
172     @Test
173     public void testValidLogin() {
174
175         HttpServletRequest req = mock(HttpServletRequest.class);
176         when(req.getRequestURI()).thenReturn("/oauth/login");
177         when(req.getParameter("username")).thenReturn("admin");
178         when(req.getParameter("password")).thenReturn("admin");
179         Claim claim = new Claim() {
180             @Override
181             public String clientId() {
182                 return "admin";
183             }
184
185             @Override
186             public String userId() {
187                 return "admin";
188             }
189
190             @Override
191             public String user() {
192                 return null;
193             }
194
195             @Override
196             public String domain() {
197                 return "sdn";
198             }
199
200             @Override
201             public Set<String> roles() {
202                 return Set.of("admin");
203             }
204         };
205         when(passwordCredentialAuth.authenticate(any(PasswordCredentials.class))).thenReturn(claim);
206         HttpServletResponse resp = mock(HttpServletResponse.class);
207         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
208         try {
209             when(resp.getOutputStream()).thenReturn(printOut);
210             servlet.doPost(req, resp);
211         } catch (ServletException | IOException e) {
212             fail(e.getMessage());
213         }
214         verify(resp).setStatus(200);
215     }
216
217     @Test
218     public void testGetProviders() {
219
220         HttpServletRequest req = mock(HttpServletRequest.class);
221         when(req.getRequestURI()).thenReturn("/oauth/providers");
222         HttpServletResponse resp = mock(HttpServletResponse.class);
223         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
224         try {
225             when(resp.getOutputStream()).thenReturn(printOut);
226             servlet.doGet(req, resp);
227         } catch (ServletException | IOException e) {
228             fail(e.getMessage());
229         }
230         verify(resp).setStatus(200);
231         String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
232         System.out.println(responseBody);
233         JSONArray a = new JSONArray(responseBody);
234         assertEquals(1, a.length());
235         assertEquals("keycloak", a.getJSONObject(0).getString("id"));
236         assertEquals("OSNL Keycloak Provider", a.getJSONObject(0).getString("title"));
237         assertEquals("/oauth/login/keycloak", a.getJSONObject(0).getString("loginUrl"));
238
239     }
240
241     @Test
242 /*
243     @Ignore
244 */
245     public void testPoliciesAnon() {
246
247         HttpServletRequest req = mock(HttpServletRequest.class);
248         when(req.getRequestURI()).thenReturn("/oauth/policies");
249         HttpServletResponse resp = mock(HttpServletResponse.class);
250         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
251         try {
252             when(resp.getOutputStream()).thenReturn(printOut);
253             servlet.doGet(req, resp);
254         } catch (ServletException | IOException e) {
255             fail(e.getMessage());
256         }
257         verify(resp).setStatus(200);
258         String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
259         System.out.println(responseBody);
260         OdlPolicy[] anonPolicies = null;
261         try {
262             anonPolicies = readJson(responseBody, OdlPolicy[].class);
263         } catch (JsonProcessingException e) {
264             fail("unable to read anon policies response");
265         }
266         assertEquals(9, anonPolicies.length);
267         OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
268         assertNotNull(pApidoc);
269         assertAllEquals(false, pApidoc);
270         OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
271         assertNotNull(pOauth);
272         assertAllEquals(true, pOauth);
273         OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
274         assertNotNull(pRestconf);
275         assertAllEquals(false, pRestconf);
276     }
277
278     @Test
279     public void testPoliciesBasicAuth() {
280
281         HttpServletRequest req = mock(HttpServletRequest.class);
282         when(req.getRequestURI()).thenReturn("/oauth/policies");
283         when(req.getHeader("Authorization")).thenReturn(BaseHTTPClient.getAuthorizationHeaderValue("admin", "admin"));
284         when(odlIdentityService.listRoles("admin@sdn", "sdn")).thenReturn(Arrays.asList("admin"));
285         HttpServletResponse resp = mock(HttpServletResponse.class);
286         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
287         try {
288             when(resp.getOutputStream()).thenReturn(printOut);
289             servlet.doGet(req, resp);
290         } catch (ServletException | IOException e) {
291             fail(e.getMessage());
292         }
293         verify(resp).setStatus(200);
294         String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
295         System.out.println(responseBody);
296         OdlPolicy[] anonPolicies = null;
297         try {
298             anonPolicies = readJson(responseBody, OdlPolicy[].class);
299         } catch (JsonProcessingException e) {
300             fail("unable to read anon policies response");
301         }
302         assertEquals(9, anonPolicies.length);
303         OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
304         assertNotNull(pApidoc);
305         assertAllEquals(false, pApidoc);
306         OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
307         assertNotNull(pOauth);
308         assertAllEquals(true, pOauth);
309         OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
310         assertNotNull(pRestconf);
311         assertAllEquals(false, pRestconf);
312     }
313
314     @Test
315     public void testPoliciesBearer() {
316         HttpServletRequest req = mock(HttpServletRequest.class);
317         when(req.getRequestURI()).thenReturn("/oauth/policies");
318         String token = createToken("admin", Arrays.asList("admin", "provision")).getToken();
319         when(req.getHeader("Authorization")).thenReturn(String.format("Bearer %s", token));
320         HttpServletResponse resp = mock(HttpServletResponse.class);
321         ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
322         try {
323             when(resp.getOutputStream()).thenReturn(printOut);
324             servlet.doGet(req, resp);
325         } catch (ServletException | IOException e) {
326             fail(e.getMessage());
327         }
328         verify(resp).setStatus(200);
329         String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
330         System.out.println(responseBody);
331         OdlPolicy[] anonPolicies = null;
332         try {
333             anonPolicies = readJson(responseBody, OdlPolicy[].class);
334         } catch (JsonProcessingException e) {
335             fail("unable to read anon policies response");
336         }
337         assertEquals(9, anonPolicies.length);
338         OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
339         assertNotNull(pApidoc);
340         assertAllEquals(false, pApidoc);
341         OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
342         assertNotNull(pOauth);
343         assertAllEquals(true, pOauth);
344         OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
345         assertNotNull(pRestconf);
346         assertAllEquals(true, pRestconf);
347     }
348
349     private static BearerToken createToken(String username, List<String> roles) {
350         UserTokenPayload data = new UserTokenPayload();
351         data.setPreferredUsername(username);
352         data.setFamilyName("");
353         data.setGivenName(username);
354         data.setExp(tokenCreator.getDefaultExp());
355         data.setRoles(roles);
356         return tokenCreator.createNewJWT(data);
357     }
358
359     private static void assertAllEquals(boolean b, OdlPolicy p) {
360         assertEquals(b, p.getMethods().isGet());
361         assertEquals(b, p.getMethods().isPost());
362         assertEquals(b, p.getMethods().isPut());
363         assertEquals(b, p.getMethods().isDelete());
364         assertEquals(b, p.getMethods().isPatch());
365     }
366
367     private static OdlPolicy find(OdlPolicy[] policies, String path) {
368         for (OdlPolicy p : policies) {
369             if (path.equals(p.getPath())) {
370                 return p;
371             }
372         }
373         return null;
374     }
375
376     private static <T> T readJson(String data, Class<T> clazz) throws JsonMappingException, JsonProcessingException {
377         CustomObjectMapper mapper = new CustomObjectMapper();
378         return mapper.readValue(data, clazz);
379     }
380
381     private static <T> T readJson(File file, Class<T> clazz) throws IOException {
382         OdlJsonMapper mapper = new OdlJsonMapper();
383         return mapper.readValue(file, clazz);
384     }
385
386     private static class TestServlet extends AuthHttpServlet {
387
388         private static final long serialVersionUID = 1L;
389
390         public TestServlet() throws IllegalArgumentException, Exception {
391             super(TESTSHIROCONFIGFILE);
392         }
393
394         @Override
395         public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
396             super.doGet(req, resp);
397         }
398
399         @Override
400         public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
401             super.doPost(req, resp);
402         }
403     }
404 }