2 * ============LICENSE_START=======================================================
3 * ONAP : ccsdk features
4 * ================================================================================
5 * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.test;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.fail;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31 import com.fasterxml.jackson.core.JsonParseException;
32 import com.fasterxml.jackson.core.JsonProcessingException;
33 import com.fasterxml.jackson.databind.JsonMappingException;
34 import com.google.common.util.concurrent.FluentFuture;
36 import java.io.IOException;
37 import java.nio.charset.StandardCharsets;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Optional;
41 import javax.servlet.ServletException;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.servlet.http.HttpServletResponse;
44 import org.jolokia.osgi.security.Authenticator;
45 import org.json.JSONArray;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
49 import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToByteArrayOutputStream;
50 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
51 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.CustomObjectMapper;
52 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
53 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
54 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
55 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.HeadersOnlyHttpServletRequest;
56 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
57 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlJsonMapper;
58 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlXmlMapper;
59 import org.opendaylight.aaa.api.IdMService;
60 import org.opendaylight.aaa.shiro.filters.backport.BearerToken;
61 import org.opendaylight.mdsal.binding.api.DataBroker;
62 import org.opendaylight.mdsal.binding.api.ReadTransaction;
63 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfigurationBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.Policies;
68 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 public class TestAuthHttpServlet {
74 private static final String TESTCONFIGFILE = TestConfig.TEST_CONFIG_FILENAME;
75 private static final String TESTSHIROCONFIGFILE = "src/test/resources/aaa-app-config.test.xml";
76 private static final String MDSALDYNAUTHFILENAME = "src/test/resources/mdsalDynAuthData.json";
77 private static TestServlet servlet;
78 private static DataBroker dataBroker = loadDynamicMdsalAuthDataBroker();
79 private static Authenticator odlAuthenticator = mock(Authenticator.class);
80 private static IdMService odlIdentityService = mock(IdMService.class);
81 private static ShiroConfiguration shiroConfiguration = null;
82 private static TokenCreator tokenCreator;
83 // private static final HttpServletRequest authreq = new HeadersOnlyHttpServletRequest(
84 // Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
87 public static void init() {
90 Config config = createConfigFile();
91 tokenCreator = TokenCreator.getInstance(config);
92 servlet = new TestServlet();
93 shiroConfiguration = loadShiroConfig(TESTSHIROCONFIGFILE);
94 } catch (IOException e) {
97 servlet.setDataBroker(dataBroker);
98 servlet.setOdlAuthenticator(odlAuthenticator);
99 servlet.setOdlIdentityService(odlIdentityService);
100 servlet.setShiroConfiguration(shiroConfiguration);
103 private static DataBroker loadDynamicMdsalAuthDataBroker() {
104 DataBroker dataBroker = mock(DataBroker.class);
105 ReadTransaction rotx = mock(ReadTransaction.class);
106 InstanceIdentifier<Policies> iif = InstanceIdentifier.create(HttpAuthorization.class).child(Policies.class);
108 when(rotx.read(LogicalDatastoreType.CONFIGURATION, iif))
109 .thenReturn(loadDataBrokerFile(MDSALDYNAUTHFILENAME, Policies.class));
110 } catch (IOException e) {
111 fail("problem init databroker read" + e.getMessage());
113 when(dataBroker.newReadOnlyTransaction()).thenReturn(rotx);
117 private static <T> FluentFuture<Optional<T>> loadDataBrokerFile(String fn, Class<T> clazz) throws IOException {
118 return FluentFutures.immediateFluentFuture(Optional.ofNullable(readJson(new File(fn), clazz)));
121 private static ShiroConfiguration loadShiroConfig(String filename)
122 throws JsonParseException, JsonMappingException, IOException {
123 OdlXmlMapper mapper = new OdlXmlMapper();
124 return mapper.readValue(new File(filename), ShiroConfigurationBuilder.class).build();
127 private static Config createConfigFile() throws IOException {
128 return Config.getInstance(TESTCONFIGFILE);
133 public void testValidLoginRedirect() {
135 HttpServletRequest req = mock(HttpServletRequest.class);
136 when(req.getRequestURI()).thenReturn("/oauth/login/keycloak");
137 HttpServletResponse resp = mock(HttpServletResponse.class);
139 servlet.doGet(req, resp);
140 } catch (ServletException | IOException e) {
141 fail(e.getMessage());
143 verify(resp).setStatus(302);
144 verify(resp).setHeader("Location",
145 "http://10.20.11.160:8080/auth/realms/onap/protocol/openid-connect/auth?client_id=odlux.app&response"
146 + "_type=code&scope=openid&redirect_uri=http%3A%2F%2Fnasp.diasf.de%2Foauth%2Fredirect%2Fkeycloak");
150 public void testInValidLoginRedirect() {
152 HttpServletRequest req = mock(HttpServletRequest.class);
153 when(req.getRequestURI()).thenReturn("/oauth/login/unknownproviderid");
154 HttpServletResponse resp = mock(HttpServletResponse.class);
155 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
157 when(resp.getOutputStream()).thenReturn(printOut);
158 servlet.doGet(req, resp);
159 } catch (ServletException | IOException e) {
160 fail(e.getMessage());
162 verify(resp).setStatus(404);
166 public void testValidLogin() {
168 HttpServletRequest req = mock(HttpServletRequest.class);
169 when(req.getRequestURI()).thenReturn("/oauth/login");
170 when(req.getParameter("username")).thenReturn("admin");
171 when(req.getParameter("password")).thenReturn("admin");
172 when(odlAuthenticator.authenticate(any(HeadersOnlyHttpServletRequest.class))).thenReturn(true);
173 HttpServletResponse resp = mock(HttpServletResponse.class);
174 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
176 when(resp.getOutputStream()).thenReturn(printOut);
177 servlet.doPost(req, resp);
178 } catch (ServletException | IOException e) {
179 fail(e.getMessage());
181 verify(resp).setStatus(200);
185 public void testGetProviders() {
187 HttpServletRequest req = mock(HttpServletRequest.class);
188 when(req.getRequestURI()).thenReturn("/oauth/providers");
189 HttpServletResponse resp = mock(HttpServletResponse.class);
190 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
192 when(resp.getOutputStream()).thenReturn(printOut);
193 servlet.doGet(req, resp);
194 } catch (ServletException | IOException e) {
195 fail(e.getMessage());
197 verify(resp).setStatus(200);
198 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
199 System.out.println(responseBody);
200 JSONArray a = new JSONArray(responseBody);
201 assertEquals(1, a.length());
202 assertEquals("keycloak", a.getJSONObject(0).getString("id"));
203 assertEquals("OSNL Keycloak Provider", a.getJSONObject(0).getString("title"));
204 assertEquals("/oauth/login/keycloak", a.getJSONObject(0).getString("loginUrl"));
209 public void testPoliciesAnon() {
211 HttpServletRequest req = mock(HttpServletRequest.class);
212 when(req.getRequestURI()).thenReturn("/oauth/policies");
213 HttpServletResponse resp = mock(HttpServletResponse.class);
214 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
216 when(resp.getOutputStream()).thenReturn(printOut);
217 servlet.doGet(req, resp);
218 } catch (ServletException | IOException e) {
219 fail(e.getMessage());
221 verify(resp).setStatus(200);
222 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
223 System.out.println(responseBody);
224 OdlPolicy[] anonPolicies = null;
226 anonPolicies = readJson(responseBody, OdlPolicy[].class);
227 } catch (JsonProcessingException e) {
228 fail("unable to read anon policies response");
230 assertEquals(9, anonPolicies.length);
231 OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
232 assertNotNull(pApidoc);
233 assertAllEquals(false, pApidoc);
234 OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
235 assertNotNull(pOauth);
236 assertAllEquals(true, pOauth);
237 OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
238 assertNotNull(pRestconf);
239 assertAllEquals(false, pRestconf);
243 public void testPoliciesBasicAuth() {
245 HttpServletRequest req = mock(HttpServletRequest.class);
246 when(req.getRequestURI()).thenReturn("/oauth/policies");
247 when(req.getHeader("Authorization")).thenReturn(BaseHTTPClient.getAuthorizationHeaderValue("admin", "admin"));
248 when(odlIdentityService.listRoles("admin@sdn", "sdn")).thenReturn(Arrays.asList("admin"));
249 HttpServletResponse resp = mock(HttpServletResponse.class);
250 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
252 when(resp.getOutputStream()).thenReturn(printOut);
253 servlet.doGet(req, resp);
254 } catch (ServletException | IOException e) {
255 fail(e.getMessage());
257 verify(resp).setStatus(200);
258 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
259 System.out.println(responseBody);
260 OdlPolicy[] anonPolicies = null;
262 anonPolicies = readJson(responseBody, OdlPolicy[].class);
263 } catch (JsonProcessingException e) {
264 fail("unable to read anon policies response");
266 assertEquals(9, anonPolicies.length);
267 OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
268 assertNotNull(pApidoc);
269 assertAllEquals(true, 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(true, pRestconf);
279 public void testPoliciesBearer() {
280 HttpServletRequest req = mock(HttpServletRequest.class);
281 when(req.getRequestURI()).thenReturn("/oauth/policies");
282 String token = createToken("admin", Arrays.asList("admin", "provision")).getToken();
283 when(req.getHeader("Authorization")).thenReturn(String.format("Bearer %s", token));
284 HttpServletResponse resp = mock(HttpServletResponse.class);
285 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
287 when(resp.getOutputStream()).thenReturn(printOut);
288 servlet.doGet(req, resp);
289 } catch (ServletException | IOException e) {
290 fail(e.getMessage());
292 verify(resp).setStatus(200);
293 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
294 System.out.println(responseBody);
295 OdlPolicy[] anonPolicies = null;
297 anonPolicies = readJson(responseBody, OdlPolicy[].class);
298 } catch (JsonProcessingException e) {
299 fail("unable to read anon policies response");
301 assertEquals(9, anonPolicies.length);
302 OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
303 assertNotNull(pApidoc);
304 assertAllEquals(false, pApidoc);
305 OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
306 assertNotNull(pOauth);
307 assertAllEquals(true, pOauth);
308 OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
309 assertNotNull(pRestconf);
310 assertAllEquals(true, pRestconf);
313 private static BearerToken createToken(String username, List<String> roles) {
314 UserTokenPayload data = new UserTokenPayload();
315 data.setPreferredUsername(username);
316 data.setFamilyName("");
317 data.setGivenName(username);
318 data.setExp(tokenCreator.getDefaultExp());
319 data.setRoles(roles);
320 return tokenCreator.createNewJWT(data);
323 private static void assertAllEquals(boolean b, OdlPolicy p) {
324 assertEquals(b, p.getMethods().isGet());
325 assertEquals(b, p.getMethods().isPost());
326 assertEquals(b, p.getMethods().isPut());
327 assertEquals(b, p.getMethods().isDelete());
328 assertEquals(b, p.getMethods().isPatch());
331 private static OdlPolicy find(OdlPolicy[] policies, String path) {
332 for (OdlPolicy p : policies) {
333 if (path.equals(p.getPath())) {
340 private static <T> T readJson(String data, Class<T> clazz) throws JsonMappingException, JsonProcessingException {
341 CustomObjectMapper mapper = new CustomObjectMapper();
342 return mapper.readValue(data, clazz);
345 private static <T> T readJson(File file, Class<T> clazz) throws IOException {
346 OdlJsonMapper mapper = new OdlJsonMapper();
347 return mapper.readValue(file, clazz);
350 private static class TestServlet extends AuthHttpServlet {
352 private static final long serialVersionUID = 1L;
354 public TestServlet() throws IOException {
359 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
360 super.doGet(req, resp);
364 public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
365 super.doPost(req, resp);