This is an automated email from the ASF dual-hosted git repository.
lmccay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 098e8091c KNOX-3119 - Provide appropriate defaults for CLIENTID
extension of KN… (#1016)
098e8091c is described below
commit 098e8091cf53b446b542578e568175e566691904
Author: lmccay <[email protected]>
AuthorDate: Mon Apr 7 12:43:47 2025 -0400
KNOX-3119 - Provide appropriate defaults for CLIENTID extension of KN…
(#1016)
* KNOX-3119 - Provide appropriate defaults for CLIENTID extension of
KNOXTOKEN API
---
.../knoxtoken/ClientCredentialsResource.java | 55 ++++
.../service/knoxtoken/ServletContextWrapper.java | 324 +++++++++++++++++++++
.../gateway/service/knoxtoken/TokenResource.java | 18 +-
.../knoxtoken/ServletContextWrapperTest.java | 134 +++++++++
.../knoxtoken/TokenServiceResourceTest.java | 3 +-
5 files changed, 527 insertions(+), 7 deletions(-)
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
index 42201e55a..6def33dff 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ClientCredentialsResource.java
@@ -17,17 +17,31 @@
*/
package org.apache.knox.gateway.service.knoxtoken;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.OctetSequenceKey;
+import com.nimbusds.jose.jwk.gen.OctetSequenceKeyGenerator;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.token.TokenMetadata;
import org.apache.knox.gateway.services.security.token.TokenMetadataType;
+import org.apache.knox.gateway.services.security.token.TokenStateService;
+import org.apache.knox.gateway.services.security.token.impl.TokenMAC;
import org.apache.knox.gateway.util.JsonUtils;
import javax.inject.Singleton;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.HashMap;
+import java.util.UUID;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
@@ -40,6 +54,47 @@ public class ClientCredentialsResource extends TokenResource
{
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
+ private GatewayServices services;
+
+ @Override
+ protected ServletContext wrapContextForDefaultParams(ServletContext
context) throws ServletException {
+ ServletContext wrapperContext = new ServletContextWrapper(context);
+
wrapperContext.setInitParameter(TokenStateService.CONFIG_SERVER_MANAGED,
"true");
+ wrapperContext.setInitParameter(TokenResource.TOKEN_TTL_PARAM, "-1");
+ services = (GatewayServices)
wrapperContext.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+ tokenStateService =
services.getService(ServiceType.TOKEN_STATE_SERVICE);
+ final GatewayConfig gatewayConfig = (GatewayConfig)
wrapperContext.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+ gatewayConfig.getKnoxTokenHashAlgorithm();
+ final AliasService aliasService =
services.getService(ServiceType.ALIAS_SERVICE);
+ char[] hashkey = new char[0];
+ try {
+ hashkey =
aliasService.getPasswordFromAliasForGateway(TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME);
+ } catch (AliasServiceException e) {
+ throw new ServletException(e);
+ }
+ if (hashkey == null) {
+ generateAndStoreHMACKeyAlias();
+ }
+ return wrapperContext;
+ }
+
+ private void generateAndStoreHMACKeyAlias() {
+ final int keyLength =
Integer.parseInt(JWSAlgorithm.HS256.getName().substring(2));
+ String jwkAsText = null;
+ try {
+ final OctetSequenceKey jwk = new
OctetSequenceKeyGenerator(keyLength).keyID(UUID.randomUUID().toString())
+ .algorithm(JWSAlgorithm.HS256).generate();
+ jwkAsText = jwk.getKeyValue().toJSONString().replace("\"", "");
+ getAliasService().addAliasForCluster("__gateway",
TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME, jwkAsText);
+ } catch (JOSEException | AliasServiceException e) {
+ throw new RuntimeException("Error while generating " + keyLength +
" bits JWK secret", e);
+ }
+ }
+
+ protected AliasService getAliasService() {
+ return services.getService(ServiceType.ALIAS_SERVICE);
+ }
+
@Override
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapper.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapper.java
new file mode 100644
index 000000000..e7e848424
--- /dev/null
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapper.java
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.knox.gateway.service.knoxtoken;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+class ServletContextWrapper implements ServletContext {
+ private ServletContext delegate;
+ private Map<String, String> defaultParams;
+
+ ServletContextWrapper(ServletContext delegate) {
+ this.delegate = delegate;
+ defaultParams = new HashMap<>();
+ }
+
+ @Override
+ public String getContextPath() {
+ return delegate.getContextPath();
+ }
+
+ @Override
+ public ServletContext getContext(String uripath) {
+ return delegate.getContext(uripath);
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return delegate.getMajorVersion();
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return delegate.getMinorVersion();
+ }
+
+ @Override
+ public int getEffectiveMajorVersion() {
+ return delegate.getEffectiveMajorVersion();
+ }
+
+ @Override
+ public int getEffectiveMinorVersion() {
+ return delegate.getEffectiveMinorVersion();
+ }
+
+ @Override
+ public String getMimeType(String file) {
+ return delegate.getMimeType(file);
+ }
+
+ @Override
+ public Set<String> getResourcePaths(String path) {
+ return delegate.getResourcePaths(path);
+ }
+
+ @Override
+ public URL getResource(String path) throws MalformedURLException {
+ return delegate.getResource(path);
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String path) {
+ return delegate.getResourceAsStream(path);
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return delegate.getRequestDispatcher(path);
+ }
+
+ @Override
+ public RequestDispatcher getNamedDispatcher(String name) {
+ return delegate.getNamedDispatcher(name);
+ }
+
+ @Override
+ public Servlet getServlet(String name) throws ServletException {
+ return delegate.getServlet(name);
+ }
+
+ @Override
+ public Enumeration<Servlet> getServlets() {
+ return delegate.getServlets();
+ }
+
+ @Override
+ public Enumeration<String> getServletNames() {
+ return delegate.getServletNames();
+ }
+
+ @Override
+ public void log(String msg) {
+ delegate.log(msg);
+ }
+
+ @Override
+ public void log(Exception exception, String msg) {
+ delegate.log(exception, msg);
+ }
+
+ @Override
+ public void log(String message, Throwable throwable) {
+ delegate.log(message, throwable);
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return delegate.getRealPath(path);
+ }
+
+ @Override
+ public String getServerInfo() {
+ return delegate.getServerInfo();
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ String value = delegate.getInitParameter(name);
+ if (value == null) {
+ value = defaultParams.get(name);
+ }
+ return value;
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ // Add all keys from the overriddenParams map
+ Set<String> combinedNames = new HashSet<>(defaultParams.keySet());
+
+ // Add all parameter names from the delegate context
+ Enumeration<String> delegateNames = delegate.getInitParameterNames();
+ while (delegateNames.hasMoreElements()) {
+ combinedNames.add(delegateNames.nextElement());
+ }
+
+ // Return an Enumeration of the combined set
+ return Collections.enumeration(combinedNames);
+ }
+
+ @Override
+ public boolean setInitParameter(String name, String value) {
+ defaultParams.put(name, value);
+ return defaultParams.get(name).equals(value);
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return delegate.getAttribute(name);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return delegate.getAttributeNames();
+ }
+
+ @Override
+ public void setAttribute(String name, Object object) {
+ delegate.setAttribute(name, object);
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ delegate.removeAttribute(name);
+ }
+
+ @Override
+ public String getServletContextName() {
+ return delegate.getServletContextName();
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String servletName, String
className) {
+ return delegate.addServlet(servletName, className);
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String servletName, Servlet
servlet) {
+ return delegate.addServlet(servletName, servlet);
+ }
+
+ @Override
+ public ServletRegistration.Dynamic addServlet(String servletName, Class<?
extends Servlet> servletClass) {
+ return delegate.addServlet(servletName, servletClass);
+ }
+
+ @Override
+ public <T extends Servlet> T createServlet(Class<T> clazz) throws
ServletException {
+ return delegate.createServlet(clazz);
+ }
+
+ @Override
+ public ServletRegistration getServletRegistration(String servletName) {
+ return delegate.getServletRegistration(servletName);
+ }
+
+ @Override
+ public Map<String, ? extends ServletRegistration>
getServletRegistrations() {
+ return delegate.getServletRegistrations();
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(String filterName, String
className) {
+ return delegate.addFilter(filterName, className);
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(String filterName, Filter
filter) {
+ return delegate.addFilter(filterName, filter);
+ }
+
+ @Override
+ public FilterRegistration.Dynamic addFilter(String filterName, Class<?
extends Filter> filterClass) {
+ return delegate.addFilter(filterName, filterClass);
+ }
+
+ @Override
+ public <T extends Filter> T createFilter(Class<T> clazz) throws
ServletException {
+ return delegate.createFilter(clazz);
+ }
+
+ @Override
+ public FilterRegistration getFilterRegistration(String filterName) {
+ return delegate.getFilterRegistration(filterName);
+ }
+
+ @Override
+ public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+ return delegate.getFilterRegistrations();
+ }
+
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ return delegate.getSessionCookieConfig();
+ }
+
+ @Override
+ public void setSessionTrackingModes(Set<SessionTrackingMode>
sessionTrackingModes) {
+ delegate.setSessionTrackingModes(sessionTrackingModes);
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ return delegate.getDefaultSessionTrackingModes();
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ return delegate.getEffectiveSessionTrackingModes();
+ }
+
+ @Override
+ public void addListener(String className) {
+ delegate.addListener(className);
+ }
+
+ @Override
+ public <T extends EventListener> void addListener(T t) {
+ delegate.addListener(t);
+ }
+
+ @Override
+ public void addListener(Class<? extends EventListener> listenerClass) {
+ delegate.addListener(listenerClass);
+ }
+
+ @Override
+ public <T extends EventListener> T createListener(Class<T> clazz) throws
ServletException {
+ return delegate.createListener(clazz);
+ }
+
+ @Override
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ return delegate.getJspConfigDescriptor();
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return delegate.getClassLoader();
+ }
+
+ @Override
+ public void declareRoles(String... roleNames) {
+ delegate.declareRoles(roleNames);
+ }
+
+ @Override
+ public String getVirtualServerName() {
+ return delegate.getVirtualServerName();
+ }
+}
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
index acc32ef23..e0904b8a4 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
@@ -46,6 +46,7 @@ import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.security.auth.Subject;
import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -118,7 +119,7 @@ public class TokenResource {
private static final String ENDPOINT_PUBLIC_CERT = "endpoint_public_cert";
protected static final String BEARER = "Bearer";
private static final String TOKEN_PARAM_PREFIX = "knox.token.";
- private static final String TOKEN_TTL_PARAM = TOKEN_PARAM_PREFIX + "ttl";
+ protected static final String TOKEN_TTL_PARAM = TOKEN_PARAM_PREFIX + "ttl";
private static final String TOKEN_TYPE_PARAM = TOKEN_PARAM_PREFIX + "type";
private static final String TOKEN_AUDIENCES_PARAM = TOKEN_PARAM_PREFIX +
"audiences";
public static final String TOKEN_INCLUDE_GROUPS_IN_JWT_ALLOWED =
TOKEN_PARAM_PREFIX + "include.groups.allowed";
@@ -219,8 +220,13 @@ public class TokenResource {
}
}
+ protected ServletContext wrapContextForDefaultParams(ServletContext context)
throws ServletException {
+ return context;
+ }
+
@PostConstruct
- public void init() throws AliasServiceException, ServiceLifecycleException,
KeyLengthException {
+ public void init() throws AliasServiceException, ServiceLifecycleException,
KeyLengthException, ServletException {
+ context = wrapContextForDefaultParams(this.context);
String audiences = context.getInitParameter(TOKEN_AUDIENCES_PARAM);
if (audiences != null) {
@@ -283,7 +289,7 @@ public class TokenResource {
}
// If server-managed token expiration is configured, set the token state
service
- if (isServerManagedTokenStateEnabled()) {
+ if (isServerManagedTokenStateEnabled(context)) {
String topologyName = getTopologyName();
log.serverManagedTokenStateEnabled(topologyName);
@@ -358,9 +364,9 @@ public class TokenResource {
}
private void setTokenStateServiceStatusMap() {
- if (isServerManagedTokenStateEnabled()) {
+ if (isServerManagedTokenStateEnabled(context)) {
tokenStateServiceStatusMap.put(TSS_STATUS_IS_MANAGEMENT_ENABLED, "true");
- final GatewayConfig config = (GatewayConfig)
request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+ final GatewayConfig config = (GatewayConfig)
context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
final String configuredTokenStateServiceImpl =
config.getServiceParameter(ServiceType.TOKEN_STATE_SERVICE.getShortName(),
"impl");
final String configuredTokenServiceName =
StringUtils.isBlank(configuredTokenStateServiceImpl) ? ""
:
configuredTokenStateServiceImpl.substring(configuredTokenStateServiceImpl.lastIndexOf('.')
+ 1);
@@ -417,7 +423,7 @@ public class TokenResource {
.contains(JWSAlgorithm.parse(algName));
}
- private boolean isServerManagedTokenStateEnabled() {
+ private boolean isServerManagedTokenStateEnabled(ServletContext context) {
boolean isServerManaged;
// First, check for explicit service-level configuration
diff --git
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapperTest.java
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapperTest.java
new file mode 100644
index 000000000..bf296d348
--- /dev/null
+++
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/ServletContextWrapperTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.knox.gateway.service.knoxtoken;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.ServletContext;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ServletContextWrapperTest {
+
+ private ServletContext mockDelegate;
+ private ServletContextWrapper wrapper;
+
+ @Before
+ public void setUp() {
+ mockDelegate = EasyMock.createMock(ServletContext.class);
+ wrapper = new ServletContextWrapper(mockDelegate);
+ }
+
+ @Test
+ public void testGetInitParameterDefaultParam() {
+ wrapper.setInitParameter("defaultParam", "defaultValue");
+ assertEquals("defaultValue", wrapper.getInitParameter("defaultParam"));
+ }
+
+ @Test
+ public void testGetInitParameterDelegateParam() {
+
EasyMock.expect(mockDelegate.getInitParameter("delegateParam")).andReturn("delegateValue");
+ EasyMock.replay(mockDelegate);
+
+ assertEquals("delegateValue",
wrapper.getInitParameter("delegateParam"));
+ EasyMock.verify(mockDelegate);
+ }
+
+ @Test
+ public void testGetInitParameterOverrideDefaultParam() {
+ wrapper.setInitParameter("defaultParam", "defaultValue");
+
EasyMock.expect(mockDelegate.getInitParameter("delegateParam")).andReturn("delegateValue");
+ EasyMock.replay(mockDelegate);
+
+ assertEquals("delegateValue",
wrapper.getInitParameter("delegateParam"));
+ EasyMock.verify(mockDelegate);
+ }
+
+ @Test
+ public void testGetInitParameterNames() {
+ wrapper.setInitParameter("defaultParam", "defaultValue");
+ EasyMock.expect(mockDelegate.getInitParameterNames()).andReturn(new
Enumeration<String>() {
+ private final String[] elements = {"delegateParam"};
+ private int index;
+
+ @Override
+ public boolean hasMoreElements() {
+ return index < elements.length;
+ }
+
+ @Override
+ public String nextElement() {
+ return elements[index++];
+ }
+ });
+ EasyMock.replay(mockDelegate);
+
+ Enumeration<String> paramNames = wrapper.getInitParameterNames();
+ Map<String, Boolean> paramMap = new HashMap<>();
+ while (paramNames.hasMoreElements()) {
+ paramMap.put(paramNames.nextElement(), true);
+ }
+
+ assertTrue(paramMap.containsKey("defaultParam"));
+ assertTrue(paramMap.containsKey("delegateParam"));
+ EasyMock.verify(mockDelegate);
+ }
+
+ @Test
+ public void testGetInitParameterNamesWithDupes() {
+ wrapper.setInitParameter("testParam", "testValue");
+ EasyMock.expect(mockDelegate.getInitParameterNames()).andReturn(new
Enumeration<String>() {
+ private final String[] elements = {"delegateParam", "testParam"};
+ private int index;
+
+ @Override
+ public boolean hasMoreElements() {
+ return index < elements.length;
+ }
+
+ @Override
+ public String nextElement() {
+ return elements[index++];
+ }
+ });
+ EasyMock.replay(mockDelegate);
+
+ Enumeration<String> paramNames = wrapper.getInitParameterNames();
+ Map<String, Boolean> paramMap = new HashMap<>();
+ while (paramNames.hasMoreElements()) {
+ paramMap.put(paramNames.nextElement(), true);
+ }
+
+ assertTrue(paramMap.containsKey("testParam"));
+ assertTrue(paramMap.containsKey("delegateParam"));
+ assertEquals(2, paramMap.size());
+ EasyMock.verify(mockDelegate);
+ }
+
+ @Test
+ public void testSetInitParameter() {
+ assertTrue(wrapper.setInitParameter("newParam", "newValue"));
+ assertEquals("newValue", wrapper.getInitParameter("newParam"));
+ }
+}
\ No newline at end of file
diff --git
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
index 6142f3fc2..ef35b082f 100644
---
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
+++
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
@@ -65,6 +65,7 @@ import java.util.concurrent.Future;
import java.util.function.Predicate;
import javax.security.auth.Subject;
import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
@@ -1606,7 +1607,7 @@ public class TokenServiceResourceTest {
return new AbstractMap.SimpleEntry<>(tss, response);
}
- private String getAccessToken(TokenResource tokenResource) throws
KeyLengthException, AliasServiceException, ServiceLifecycleException {
+ private String getAccessToken(TokenResource tokenResource) throws
KeyLengthException, AliasServiceException, ServiceLifecycleException,
ServletException {
tokenResource.request = request;
tokenResource.context = context;
tokenResource.init();