From f9b6949353264c68e1e45cd3b417ae36de058b1e Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 3 Apr 2020 11:04:10 +0300 Subject: [PATCH] Prevent ArrayIndexOutOfBoundsException in HeaderRequestTokenExtractor --- .../token/HeaderRequestTokenExtractor.java | 14 +++- .../HeaderRequestTokenExtractorTest.java | 71 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 multiuser/api/che-multiuser-api-authentication-commons/src/test/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractorTest.java diff --git a/multiuser/api/che-multiuser-api-authentication-commons/src/main/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractor.java b/multiuser/api/che-multiuser-api-authentication-commons/src/main/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractor.java index 036e6573c4..10c2626f1d 100644 --- a/multiuser/api/che-multiuser-api-authentication-commons/src/main/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractor.java +++ b/multiuser/api/che-multiuser-api-authentication-commons/src/main/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractor.java @@ -12,17 +12,25 @@ package org.eclipse.che.multiuser.api.authentication.commons.token; import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.BadRequestException; import javax.ws.rs.core.HttpHeaders; /** Extract sso token from request headers. */ public class HeaderRequestTokenExtractor implements RequestTokenExtractor { + @Override public String getToken(HttpServletRequest req) { if (req.getHeader(HttpHeaders.AUTHORIZATION) == null) { return null; } - return req.getHeader(HttpHeaders.AUTHORIZATION).toLowerCase().startsWith("bearer") - ? req.getHeader(HttpHeaders.AUTHORIZATION).split(" ")[1] - : req.getHeader(HttpHeaders.AUTHORIZATION); + if (req.getHeader(HttpHeaders.AUTHORIZATION).toLowerCase().startsWith("bearer")) { + String[] parts = req.getHeader(HttpHeaders.AUTHORIZATION).split(" "); + if (parts.length != 2) { + throw new BadRequestException("Invalid authorization header format."); + } + return parts[1]; + } else { + return req.getHeader(HttpHeaders.AUTHORIZATION); + } } } diff --git a/multiuser/api/che-multiuser-api-authentication-commons/src/test/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractorTest.java b/multiuser/api/che-multiuser-api-authentication-commons/src/test/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractorTest.java new file mode 100644 index 0000000000..9ec5bf9aad --- /dev/null +++ b/multiuser/api/che-multiuser-api-authentication-commons/src/test/java/org/eclipse/che/multiuser/api/authentication/commons/token/HeaderRequestTokenExtractorTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.multiuser.api.authentication.commons.token; + +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.BadRequestException; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +@Listeners(MockitoTestNGListener.class) +public class HeaderRequestTokenExtractorTest { + + private HeaderRequestTokenExtractor tokenExtractor = new HeaderRequestTokenExtractor(); + + @Mock HttpServletRequest servletRequest; + + @Test(dataProvider = "validHeadersProvider") + public void shouldExtractTokensFromValidHeaders(String headerValue, String expectedToken) { + + when(servletRequest.getHeader(eq(AUTHORIZATION))).thenReturn(headerValue); + + // when + String token = tokenExtractor.getToken(servletRequest); + + // then + assertEquals(token, expectedToken); + } + + @Test( + dataProvider = "invalidHeadersProvider", + expectedExceptions = BadRequestException.class, + expectedExceptionsMessageRegExp = "Invalid authorization header format.") + public void shouldThrowExceptionOnInvalidToken(String headerValue) { + + when(servletRequest.getHeader(eq(AUTHORIZATION))).thenReturn(headerValue); + + // when + tokenExtractor.getToken(servletRequest); + } + + @DataProvider + private Object[][] validHeadersProvider() { + return new Object[][] { + {"token123", "token123"}, + {"bearer token123", "token123"}, + {"Bearer token123", "token123"}, + }; + } + + @DataProvider + private Object[][] invalidHeadersProvider() { + return new Object[][] {{"bearertoken123"}, {"bearer token123"}, {"bearer token 123"}}; + } +}