From 6cfebc0867b2f21a401f55734aba30eb245e3c70 Mon Sep 17 00:00:00 2001 From: Neil Derraugh Date: Mon, 8 Jun 2020 10:40:10 -0400 Subject: Fix security issue in SecurityUtil - Specified mode and padding to address risky algorithm - Corrected unit test for different exception message - Moved tests to package Issue-ID: SDC-3105 Signed-off-by: Neil Derraugh Change-Id: I5773ab555a5468362c775cf99795df4eb8c52136 --- .../AuthenticationCookieUtilsTest.java | 66 ++++++++ .../openecomp/sdc/securityutil/CipherUtilTest.java | 73 +++++++++ .../openecomp/sdc/securityutil/PasswordsTest.java | 97 +++++++++++ .../sdc/securityutil/RepresentationUtilsTest.java | 56 +++++++ .../filters/SessionValidationFilterTest.java | 180 +++++++++++++++++++++ 5 files changed, 472 insertions(+) create mode 100644 openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/AuthenticationCookieUtilsTest.java create mode 100644 openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/CipherUtilTest.java create mode 100644 openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/PasswordsTest.java create mode 100644 openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/RepresentationUtilsTest.java create mode 100644 openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/filters/SessionValidationFilterTest.java (limited to 'openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp') diff --git a/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/AuthenticationCookieUtilsTest.java b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/AuthenticationCookieUtilsTest.java new file mode 100644 index 0000000000..6c1e6cb849 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/AuthenticationCookieUtilsTest.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.securityutil; + +import org.junit.Test; + +import javax.servlet.http.Cookie; + +import java.io.IOException; +import org.openecomp.sdc.securityutil.AuthenticationCookie; +import org.openecomp.sdc.securityutil.AuthenticationCookieUtils; +import org.openecomp.sdc.securityutil.CipherUtilException; +import org.openecomp.sdc.securityutil.ISessionValidationFilterConfiguration; +import org.openecomp.sdc.securityutil.filters.SampleFilter; + +import static org.junit.Assert.*; + +public class AuthenticationCookieUtilsTest { + + private SampleFilter sessionValidationFilter = new SampleFilter(); + private ISessionValidationFilterConfiguration filterCfg = sessionValidationFilter.getFilterConfiguration(); + + @Test + public void vaildateThatCookieCurrentSessionTimeIncreased() throws IOException, CipherUtilException { + // original cookie, pojo and servlet cookie + AuthenticationCookie authenticationCookieOriginal = new AuthenticationCookie("kuku"); + Cookie cookieWithOriginalTime = new Cookie(filterCfg.getCookieName(), AuthenticationCookieUtils + .getEncryptedCookie(authenticationCookieOriginal,filterCfg )); + // cookie with increased time, pojo and servlet cookie + Cookie cookieWithIncreasedTime = AuthenticationCookieUtils.updateSessionTime(cookieWithOriginalTime, filterCfg); + AuthenticationCookie authenticationCookieIncreasedTime = AuthenticationCookieUtils.getAuthenticationCookie(cookieWithIncreasedTime, filterCfg); + // validation + long currentSessionTimeOriginal = authenticationCookieOriginal.getCurrentSessionTime(); + long currentSessionTimeIncreased = authenticationCookieIncreasedTime.getCurrentSessionTime(); + assertTrue(currentSessionTimeOriginal < currentSessionTimeIncreased); + } + + @Test + public void validateSerializationEncriptionDeserializationDecryption() throws IOException, CipherUtilException { + // original cookie, pojo and servlet cookie + AuthenticationCookie authenticationCookieOriginal = new AuthenticationCookie("kuku"); + Cookie cookieWithOriginalTime = new Cookie(filterCfg.getCookieName(), AuthenticationCookieUtils.getEncryptedCookie(authenticationCookieOriginal,filterCfg )); + // cookie with increased time, pojo and servlet cookie + AuthenticationCookie decriptedAndDeserializedAuthenticationCookie = AuthenticationCookieUtils.getAuthenticationCookie(cookieWithOriginalTime,filterCfg); + assertTrue(authenticationCookieOriginal.equals(decriptedAndDeserializedAuthenticationCookie)); + } + +} diff --git a/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/CipherUtilTest.java b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/CipherUtilTest.java new file mode 100644 index 0000000000..437974de02 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/CipherUtilTest.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.securityutil; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.RandomStringUtils; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CipherUtilTest { + + private static final String KEY = "AGLDdG4D04BKm2IxIWEr8o=="; + private static final String DATA = "data"; + + @Test + public void encryptDecryptPKC() throws CipherUtilException { + String generatedKey = RandomStringUtils.randomAlphabetic(16); + String base64Key = Base64.encodeBase64String(generatedKey.getBytes()); + String encrypted = CipherUtil.encryptPKC(DATA, base64Key); + assertNotEquals(DATA, encrypted); + String decrypted = CipherUtil.decryptPKC(encrypted, base64Key); + assertEquals(decrypted, DATA); + } + + @Test + public void encryptInvalidKey() { + try { + CipherUtil.encryptPKC(DATA, "invalidKey"); + fail(); + } catch (CipherUtilException ex) { + assertTrue(ex.getMessage().contains("Invalid AES key length")); + } + } + + @Test + public void decryptInvalidKey() { + try { + CipherUtil.decryptPKC(DATA, "invalidKey"); + fail(); + } catch (CipherUtilException ex) { + assertTrue(ex.getMessage().contains("length")); + } + } + + @Test + public void decryptInvalidData() { + try { + CipherUtil.decryptPKC(DATA, KEY); + fail(); + } catch (CipherUtilException ex) { + assertTrue(ex.getMessage().contains("Input too short")); + } + } +} diff --git a/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/PasswordsTest.java b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/PasswordsTest.java new file mode 100644 index 0000000000..34a0c52604 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/PasswordsTest.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.securityutil; + +import org.junit.Test; +import org.openecomp.sdc.securityutil.Passwords; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class PasswordsTest { + + @Test + public void hashPassword() throws Exception { + String hash = Passwords.hashPassword("hello1234"); + assertTrue(Passwords.isExpectedPassword("hello1234", hash)); + + //test different salt-> result in different hash + String hash2 = Passwords.hashPassword("hello1234"); + assertFalse(hash.equals(hash2)); + + String hash3 = Passwords.hashPassword(""); + assertTrue(Passwords.isExpectedPassword("", hash3)); + + String hash4 = Passwords.hashPassword(null); + assertTrue(hash4 == null); + } + + @Test + public void isExpectedPassword() throws Exception { + //region isExpectedPassword(String password, String salt, String hash) + assertTrue(Passwords.isExpectedPassword(null, null, null)); + //valid hash + assertTrue(Passwords.isExpectedPassword("hello1234", "e0277df331f4ff8f74752ac4a8fbe03b", "6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0")); + //invalid salt + assertFalse(Passwords.isExpectedPassword("hello1234", "c0000df331f4ff8f74752ac4a00be03c", "6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0")); + assertFalse(Passwords.isExpectedPassword("hello1234", null, "6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0")); + //exacly 1 param uninitialized + assertFalse(Passwords.isExpectedPassword("hello1234", "", null)); + assertFalse(Passwords.isExpectedPassword(null, "", "hello1234")); + //no salt & no hash + assertFalse(Passwords.isExpectedPassword("hello1234", null, "hello1234")); + //endregion + + //region isExpectedPassword(String password, String expectedHash) + assertTrue(Passwords.isExpectedPassword(null, null)); + //valid hash + assertTrue(Passwords.isExpectedPassword("hello1234", "e0277df331f4ff8f74752ac4a8fbe03b:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0")); + //invalid salt + assertFalse(Passwords.isExpectedPassword("hello1234", "c0000df331f4ff8f74752ac4a00be03c:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0")); + //exacly 1 param uninitialized + assertFalse(Passwords.isExpectedPassword("hello1234", null)); + assertFalse(Passwords.isExpectedPassword(null, "hello1234")); + //no salt & no hash + assertFalse(Passwords.isExpectedPassword("hello1234", "hello1234")); + //endregion + } + + @Test + public void hashtest() { + String password = "123456"; + String hash = Passwords.hashPassword(password); + assertTrue(Passwords.isExpectedPassword(password, hash)); + password = "1sdfgsgd23456"; + hash = Passwords.hashPassword(password); + assertTrue(Passwords.isExpectedPassword(password, hash)); + password = "1sdfgsgd2345((*&%$%6"; + hash = Passwords.hashPassword(password); + assertTrue(Passwords.isExpectedPassword(password, hash)); + password = ""; + hash = Passwords.hashPassword(password); + assertTrue(Passwords.isExpectedPassword(password, hash)); + password = " "; + hash = Passwords.hashPassword(password); + assertTrue(Passwords.isExpectedPassword(password, hash)); + } + + +} diff --git a/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/RepresentationUtilsTest.java b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/RepresentationUtilsTest.java new file mode 100644 index 0000000000..f7af4a9318 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/RepresentationUtilsTest.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.securityutil; + +import org.junit.Test; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import org.openecomp.sdc.securityutil.AuthenticationCookie; +import org.openecomp.sdc.securityutil.RepresentationUtils; + +import static org.junit.Assert.assertTrue; + +public class RepresentationUtilsTest { + + private static AuthenticationCookie originalCookie = new AuthenticationCookie("kuku"); + + @Test + public void representationE2EwithRoleNull() throws IOException { + originalCookie.setRoles(null); + String jsonStr = RepresentationUtils.toRepresentation(originalCookie); + AuthenticationCookie cookieFromJson = RepresentationUtils.fromRepresentation(jsonStr, AuthenticationCookie.class); + assertTrue(originalCookie.equals(cookieFromJson)); + } + + @Test + public void representationE2EwithRoleNotNull() throws IOException { + Set roles = new HashSet(); + roles.add("Designer"); + roles.add("Admin"); + roles.add("Tester"); + originalCookie.setRoles(roles); + String jsonStr = RepresentationUtils.toRepresentation(originalCookie); + AuthenticationCookie cookieFromJson = RepresentationUtils.fromRepresentation(jsonStr, AuthenticationCookie.class); + assertTrue(originalCookie.equals(cookieFromJson)); + } +} diff --git a/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/filters/SessionValidationFilterTest.java b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/filters/SessionValidationFilterTest.java new file mode 100644 index 0000000000..cb11ef97f4 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-security-util/src/test/java/org/openecomp/sdc/securityutil/filters/SessionValidationFilterTest.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.securityutil.filters; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.openecomp.sdc.securityutil.AuthenticationCookie; +import org.openecomp.sdc.securityutil.AuthenticationCookieUtils; +import org.openecomp.sdc.securityutil.CipherUtilException; +import org.openecomp.sdc.securityutil.RepresentationUtils; +import org.openecomp.sdc.securityutil.filters.ResponceWrapper; +import org.openecomp.sdc.securityutil.filters.SampleFilter; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class SessionValidationFilterTest { + + @Mock + private HttpServletRequest request; + @Spy + private HttpServletResponse response; + @Mock + private FilterChain filterChain; + @Mock + private FilterConfig filterConfig; + @Mock + private ResponceWrapper responceWrapper; + + // implementation of SessionValidationFilter + @InjectMocks + @Spy + private SampleFilter sessionValidationFilter = new SampleFilter(); + + @Before + public void setUpClass() throws ServletException { + sessionValidationFilter.init(filterConfig); + } + + @Test + public void excludedUrlHealthcheck() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/healthCheck"); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(filterChain, times(1)).doFilter(request, response); + } + + @Test + public void excludedUrlUpload() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/upload/123"); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(filterChain, times(1)).doFilter(request, response); + } + + // case when url pattern in web.xml is forward slash (/) + @Test + public void pathInfoIsNull() throws IOException, ServletException { + when(request.getServletPath()).thenReturn("/upload/2"); + when(request.getPathInfo()).thenReturn(null); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(filterChain, times(1)).doFilter(request, response); + } + + @Test + public void noCookiesInRequest() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/resource"); + when(request.getCookies()).thenReturn(new Cookie[0]); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(response, times(1)).sendRedirect(sessionValidationFilter.getFilterConfiguration().getRedirectURL()); + } + + @Test + public void nullCookiesInRequest() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/resource"); + when(request.getCookies()).thenReturn(null); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(response, times(1)).sendRedirect(sessionValidationFilter.getFilterConfiguration().getRedirectURL()); + } + + @Test + public void noCookiesWithCorrectNameInRequest() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/resource"); + String newNameNotContainsRealName = sessionValidationFilter.getFilterConfiguration().getCookieName().substring(1); + Cookie cookie = new Cookie("fake" + newNameNotContainsRealName + "fake2", RepresentationUtils.toRepresentation(new AuthenticationCookie("kuku"))); + when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(response, times(1)).sendRedirect(sessionValidationFilter.getFilterConfiguration().getRedirectURL()); + } + + @Test + public void cookieMaxSessionTimeTimedOut() throws IOException, ServletException, CipherUtilException { + when(request.getPathInfo()).thenReturn("/resource"); + AuthenticationCookie authenticationCookie = new AuthenticationCookie("kuku"); + // set max session time to timout value + long maxSessionTimeOut = sessionValidationFilter.getFilterConfiguration().getMaxSessionTimeOut(); + long startTime = authenticationCookie.getMaxSessionTime(); + long timeout = startTime - maxSessionTimeOut - 1000l; + authenticationCookie.setMaxSessionTime(timeout); + Cookie cookie = new Cookie(sessionValidationFilter.getFilterConfiguration().getCookieName(), AuthenticationCookieUtils + .getEncryptedCookie(authenticationCookie, sessionValidationFilter.getFilterConfiguration())); + + when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(response, times(1)).sendRedirect(sessionValidationFilter.getFilterConfiguration().getRedirectURL()); + } + + @Test + public void cookieSessionIdle() throws IOException, ServletException, CipherUtilException { + when(request.getPathInfo()).thenReturn("/resource"); + AuthenticationCookie authenticationCookie = new AuthenticationCookie("kuku"); + // set session time to timout to idle + long idleSessionTimeOut = sessionValidationFilter.getFilterConfiguration().getSessionIdleTimeOut(); + long sessionStartTime = authenticationCookie.getCurrentSessionTime(); + long timeout = sessionStartTime - idleSessionTimeOut - 2000; + authenticationCookie.setCurrentSessionTime(timeout); + Cookie cookie = new Cookie(sessionValidationFilter.getFilterConfiguration().getCookieName(), AuthenticationCookieUtils.getEncryptedCookie(authenticationCookie, sessionValidationFilter.getFilterConfiguration())); + + when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(response, times(1)).sendRedirect(sessionValidationFilter.getFilterConfiguration().getRedirectURL()); + } + + @Test + public void requestThatPassFilter() throws IOException, ServletException, CipherUtilException { + when(request.getPathInfo()).thenReturn("/resource"); + + AuthenticationCookie authenticationCookie = new AuthenticationCookie("kuku"); + Cookie cookie = new Cookie(sessionValidationFilter.getFilterConfiguration().getCookieName(), AuthenticationCookieUtils.getEncryptedCookie(authenticationCookie, sessionValidationFilter.getFilterConfiguration())); + + when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(filterChain, times(1)).doFilter(request, response); + } + +// test validate contains + @Test + public void requestThatPassFilterWithCookieNameAsPartOfOtherString() throws IOException, ServletException, CipherUtilException { + when(request.getPathInfo()).thenReturn("/resource"); + + AuthenticationCookie authenticationCookie = new AuthenticationCookie("kuku"); + Cookie cookie = new Cookie("some" +sessionValidationFilter.getFilterConfiguration().getCookieName() + "Thing", AuthenticationCookieUtils.getEncryptedCookie(authenticationCookie, sessionValidationFilter.getFilterConfiguration())); + + when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + sessionValidationFilter.doFilter(request, response, filterChain); + Mockito.verify(filterChain, times(1)).doFilter(request, response); + } + +} -- cgit 1.2.3-korg