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.InvalidConfigurationException;
53 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
54 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
55 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
56 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.HeadersOnlyHttpServletRequest;
57 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
58 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlJsonMapper;
59 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlXmlMapper;
60 import org.opendaylight.aaa.api.IdMService;
61 import org.apache.shiro.authc.BearerToken;
62 import org.opendaylight.mdsal.binding.api.DataBroker;
63 import org.opendaylight.mdsal.binding.api.ReadTransaction;
64 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfigurationBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.Policies;
69 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 public class TestAuthHttpServlet {
75 private static final String TESTCONFIGFILE = TestConfig.TEST_CONFIG_FILENAME;
76 private static final String TESTSHIROCONFIGFILE = "src/test/resources/aaa-app-config.test.xml";
77 private static final String MDSALDYNAUTHFILENAME = "src/test/resources/mdsalDynAuthData.json";
78 private static TestServlet servlet;
79 private static DataBroker dataBroker = loadDynamicMdsalAuthDataBroker();
80 private static Authenticator odlAuthenticator = mock(Authenticator.class);
81 private static IdMService odlIdentityService = mock(IdMService.class);
82 private static ShiroConfiguration shiroConfiguration = null;
83 private static TokenCreator tokenCreator;
84 // private static final HttpServletRequest authreq = new HeadersOnlyHttpServletRequest(
85 // Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
88 public static void init() throws IllegalArgumentException, Exception {
91 Config config = createConfigFile();
92 tokenCreator = TokenCreator.getInstance(config);
93 servlet = new TestServlet();
94 shiroConfiguration = loadShiroConfig(TESTSHIROCONFIGFILE);
95 } catch (IOException | InvalidConfigurationException e) {
98 servlet.setDataBroker(dataBroker);
99 servlet.setOdlAuthenticator(odlAuthenticator);
100 servlet.setOdlIdentityService(odlIdentityService);
101 servlet.setShiroConfiguration(shiroConfiguration);
104 private static DataBroker loadDynamicMdsalAuthDataBroker() {
105 DataBroker dataBroker = mock(DataBroker.class);
106 ReadTransaction rotx = mock(ReadTransaction.class);
107 InstanceIdentifier<Policies> iif = InstanceIdentifier.create(HttpAuthorization.class).child(Policies.class);
109 when(rotx.read(LogicalDatastoreType.CONFIGURATION, iif))
110 .thenReturn(loadDataBrokerFile(MDSALDYNAUTHFILENAME, Policies.class));
111 } catch (IOException e) {
112 fail("problem init databroker read" + e.getMessage());
114 when(dataBroker.newReadOnlyTransaction()).thenReturn(rotx);
118 private static <T> FluentFuture<Optional<T>> loadDataBrokerFile(String fn, Class<T> clazz) throws IOException {
119 return FluentFutures.immediateFluentFuture(Optional.ofNullable(readJson(new File(fn), clazz)));
122 private static ShiroConfiguration loadShiroConfig(String filename)
123 throws JsonParseException, JsonMappingException, IOException {
124 OdlXmlMapper mapper = new OdlXmlMapper();
125 return mapper.readValue(new File(filename), ShiroConfigurationBuilder.class).build();
128 private static Config createConfigFile() throws IOException, InvalidConfigurationException {
129 return Config.getInstance(TESTCONFIGFILE);
134 public void testValidLoginRedirect() {
136 HttpServletRequest req = mock(HttpServletRequest.class);
137 when(req.getRequestURI()).thenReturn("/oauth/login/keycloak");
138 HttpServletResponse resp = mock(HttpServletResponse.class);
140 servlet.doGet(req, resp);
141 } catch (ServletException | IOException e) {
142 fail(e.getMessage());
144 verify(resp).setStatus(302);
145 verify(resp).setHeader("Location",
146 "http://10.20.11.160:8080/auth/realms/onap/protocol/openid-connect/auth?client_id=odlux.app&response"
147 + "_type=code&scope=openid&redirect_uri=http%3A%2F%2Fnasp.diasf.de%2Foauth%2Fredirect%2Fkeycloak");
151 public void testInValidLoginRedirect() {
153 HttpServletRequest req = mock(HttpServletRequest.class);
154 when(req.getRequestURI()).thenReturn("/oauth/login/unknownproviderid");
155 HttpServletResponse resp = mock(HttpServletResponse.class);
156 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
158 when(resp.getOutputStream()).thenReturn(printOut);
159 servlet.doGet(req, resp);
160 } catch (ServletException | IOException e) {
161 fail(e.getMessage());
163 verify(resp).setStatus(404);
167 public void testValidLogin() {
169 HttpServletRequest req = mock(HttpServletRequest.class);
170 when(req.getRequestURI()).thenReturn("/oauth/login");
171 when(req.getParameter("username")).thenReturn("admin");
172 when(req.getParameter("password")).thenReturn("admin");
173 when(odlAuthenticator.authenticate(any(HeadersOnlyHttpServletRequest.class))).thenReturn(true);
174 HttpServletResponse resp = mock(HttpServletResponse.class);
175 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
177 when(resp.getOutputStream()).thenReturn(printOut);
178 servlet.doPost(req, resp);
179 } catch (ServletException | IOException e) {
180 fail(e.getMessage());
182 verify(resp).setStatus(200);
186 public void testGetProviders() {
188 HttpServletRequest req = mock(HttpServletRequest.class);
189 when(req.getRequestURI()).thenReturn("/oauth/providers");
190 HttpServletResponse resp = mock(HttpServletResponse.class);
191 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
193 when(resp.getOutputStream()).thenReturn(printOut);
194 servlet.doGet(req, resp);
195 } catch (ServletException | IOException e) {
196 fail(e.getMessage());
198 verify(resp).setStatus(200);
199 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
200 System.out.println(responseBody);
201 JSONArray a = new JSONArray(responseBody);
202 assertEquals(1, a.length());
203 assertEquals("keycloak", a.getJSONObject(0).getString("id"));
204 assertEquals("OSNL Keycloak Provider", a.getJSONObject(0).getString("title"));
205 assertEquals("/oauth/login/keycloak", a.getJSONObject(0).getString("loginUrl"));
210 public void testPoliciesAnon() {
212 HttpServletRequest req = mock(HttpServletRequest.class);
213 when(req.getRequestURI()).thenReturn("/oauth/policies");
214 HttpServletResponse resp = mock(HttpServletResponse.class);
215 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
217 when(resp.getOutputStream()).thenReturn(printOut);
218 servlet.doGet(req, resp);
219 } catch (ServletException | IOException e) {
220 fail(e.getMessage());
222 verify(resp).setStatus(200);
223 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
224 System.out.println(responseBody);
225 OdlPolicy[] anonPolicies = null;
227 anonPolicies = readJson(responseBody, OdlPolicy[].class);
228 } catch (JsonProcessingException e) {
229 fail("unable to read anon policies response");
231 assertEquals(9, anonPolicies.length);
232 OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
233 assertNotNull(pApidoc);
234 assertAllEquals(false, pApidoc);
235 OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
236 assertNotNull(pOauth);
237 assertAllEquals(true, pOauth);
238 OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
239 assertNotNull(pRestconf);
240 assertAllEquals(false, pRestconf);
244 public void testPoliciesBasicAuth() {
246 HttpServletRequest req = mock(HttpServletRequest.class);
247 when(req.getRequestURI()).thenReturn("/oauth/policies");
248 when(req.getHeader("Authorization")).thenReturn(BaseHTTPClient.getAuthorizationHeaderValue("admin", "admin"));
249 when(odlIdentityService.listRoles("admin@sdn", "sdn")).thenReturn(Arrays.asList("admin"));
250 HttpServletResponse resp = mock(HttpServletResponse.class);
251 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
253 when(resp.getOutputStream()).thenReturn(printOut);
254 servlet.doGet(req, resp);
255 } catch (ServletException | IOException e) {
256 fail(e.getMessage());
258 verify(resp).setStatus(200);
259 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
260 System.out.println(responseBody);
261 OdlPolicy[] anonPolicies = null;
263 anonPolicies = readJson(responseBody, OdlPolicy[].class);
264 } catch (JsonProcessingException e) {
265 fail("unable to read anon policies response");
267 assertEquals(9, anonPolicies.length);
268 OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
269 assertNotNull(pApidoc);
270 assertAllEquals(true, pApidoc);
271 OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
272 assertNotNull(pOauth);
273 assertAllEquals(true, pOauth);
274 OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
275 assertNotNull(pRestconf);
276 assertAllEquals(true, pRestconf);
280 public void testPoliciesBearer() {
281 HttpServletRequest req = mock(HttpServletRequest.class);
282 when(req.getRequestURI()).thenReturn("/oauth/policies");
283 String token = createToken("admin", Arrays.asList("admin", "provision")).getToken();
284 when(req.getHeader("Authorization")).thenReturn(String.format("Bearer %s", token));
285 HttpServletResponse resp = mock(HttpServletResponse.class);
286 ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
288 when(resp.getOutputStream()).thenReturn(printOut);
289 servlet.doGet(req, resp);
290 } catch (ServletException | IOException e) {
291 fail(e.getMessage());
293 verify(resp).setStatus(200);
294 String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
295 System.out.println(responseBody);
296 OdlPolicy[] anonPolicies = null;
298 anonPolicies = readJson(responseBody, OdlPolicy[].class);
299 } catch (JsonProcessingException e) {
300 fail("unable to read anon policies response");
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(true, pRestconf);
314 private static BearerToken createToken(String username, List<String> roles) {
315 UserTokenPayload data = new UserTokenPayload();
316 data.setPreferredUsername(username);
317 data.setFamilyName("");
318 data.setGivenName(username);
319 data.setExp(tokenCreator.getDefaultExp());
320 data.setRoles(roles);
321 return tokenCreator.createNewJWT(data);
324 private static void assertAllEquals(boolean b, OdlPolicy p) {
325 assertEquals(b, p.getMethods().isGet());
326 assertEquals(b, p.getMethods().isPost());
327 assertEquals(b, p.getMethods().isPut());
328 assertEquals(b, p.getMethods().isDelete());
329 assertEquals(b, p.getMethods().isPatch());
332 private static OdlPolicy find(OdlPolicy[] policies, String path) {
333 for (OdlPolicy p : policies) {
334 if (path.equals(p.getPath())) {
341 private static <T> T readJson(String data, Class<T> clazz) throws JsonMappingException, JsonProcessingException {
342 CustomObjectMapper mapper = new CustomObjectMapper();
343 return mapper.readValue(data, clazz);
346 private static <T> T readJson(File file, Class<T> clazz) throws IOException {
347 OdlJsonMapper mapper = new OdlJsonMapper();
348 return mapper.readValue(file, clazz);
351 private static class TestServlet extends AuthHttpServlet {
353 private static final long serialVersionUID = 1L;
355 public TestServlet() throws IllegalArgumentException, Exception {
360 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
361 super.doGet(req, resp);
365 public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
366 super.doPost(req, resp);