Skip to content

Commit 7b5e518

Browse files
authored
KNOX-3317: Fixed NPE when no token-metadata-headers are declared for ICEBERG-REST (#1225)
1 parent fb70788 commit 7b5e518

2 files changed

Lines changed: 158 additions & 4 deletions

File tree

gateway-service-restcatalog/src/main/java/org/apache/knox/gateway/service/restcatalog/TokenMetadataHeaderHandler.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ private Set<String> getMetadataHeaderConfig(final FilterConfig filterConfig) {
8888
// Add the default metadata element to be included in the outbound request headers
8989
metadataForHeaders.add("userName");
9090

91-
// Parse the configured token metadata elements which should be included as outbound request headers
91+
// Parse the configured token metadata elements, if any, which should be included as outbound request headers
9292
String tokenMetadataHeadersConfig = filterConfig.getInitParameter(TOKEN_METADATA_PARAM);
93-
String[] tokenMetadataHeaderNames = tokenMetadataHeadersConfig.split(",");
94-
for (String metadataName : tokenMetadataHeaderNames) {
95-
metadataForHeaders.add(metadataName.trim());
93+
if (tokenMetadataHeadersConfig != null) {
94+
String[] tokenMetadataHeaderNames = tokenMetadataHeadersConfig.split(",");
95+
for (String metadataName : tokenMetadataHeaderNames) {
96+
metadataForHeaders.add(metadataName.trim());
97+
}
9698
}
9799
return metadataForHeaders;
98100
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.knox.gateway.service.restcatalog;
19+
20+
import org.apache.http.client.methods.HttpRequestBase;
21+
import org.apache.knox.gateway.security.CommonTokenConstants;
22+
import org.apache.knox.gateway.services.GatewayServices;
23+
import org.apache.knox.gateway.services.ServiceType;
24+
import org.apache.knox.gateway.services.security.token.TokenMetadata;
25+
import org.apache.knox.gateway.services.security.token.TokenStateService;
26+
import org.easymock.EasyMock;
27+
import org.eclipse.jetty.http.HttpMethod;
28+
import org.junit.Test;
29+
30+
import javax.servlet.FilterConfig;
31+
import javax.servlet.ServletContext;
32+
import javax.servlet.http.HttpServletRequest;
33+
import java.util.Base64;
34+
import java.util.HashMap;
35+
import java.util.Map;
36+
37+
import static java.nio.charset.StandardCharsets.UTF_8;
38+
import static org.junit.Assert.assertEquals;
39+
import static org.junit.Assert.assertNotNull;
40+
import static org.junit.Assert.assertNull;
41+
42+
public class TokenMetadataHeaderHandlerTest {
43+
44+
@Test
45+
public void testNullTokenMetadataHeadersConfig() throws Exception {
46+
FilterConfig filterConfig = createFilterConfig(null, null, null, null);
47+
// This should not throw NPE
48+
TokenMetadataHeaderHandler handler = new TokenMetadataHeaderHandler(filterConfig);
49+
assertNotNull(handler);
50+
}
51+
52+
@Test
53+
public void testEmptyTokenMetadataHeadersConfig() throws Exception {
54+
FilterConfig filterConfig = createFilterConfig("", null, null, null);
55+
TokenMetadataHeaderHandler handler = new TokenMetadataHeaderHandler(filterConfig);
56+
assertNotNull(handler);
57+
}
58+
59+
@Test
60+
public void testApplyHeaders() throws Exception {
61+
final String clientId = "test-client-id";
62+
Map<String, String> metadataMap = new HashMap<>();
63+
metadataMap.put("userName", "test-user");
64+
metadataMap.put("custom-meta", "custom-value");
65+
metadataMap.put("another-meta", "another-value");
66+
67+
FilterConfig filterConfig = createFilterConfig("custom-meta, another-meta", null, clientId, metadataMap);
68+
TokenMetadataHeaderHandler handler = new TokenMetadataHeaderHandler(filterConfig);
69+
70+
HttpServletRequest inboundRequest = createInboundRequest(clientId);
71+
TestHttpUriRequest outboundRequest = new TestHttpUriRequest();
72+
handler.applyHeadersToRequest(inboundRequest, outboundRequest);
73+
74+
assertEquals("test-user", outboundRequest.getFirstHeader("X-Knox-Meta-userName").getValue());
75+
assertEquals("custom-value", outboundRequest.getFirstHeader("X-Knox-Meta-custom-meta").getValue());
76+
assertEquals("another-value", outboundRequest.getFirstHeader("X-Knox-Meta-another-meta").getValue());
77+
}
78+
79+
@Test
80+
public void testApplyHeadersCustomPrefix() throws Exception {
81+
final String clientId = "test-client-id";
82+
Map<String, String> metadataMap = new HashMap<>();
83+
metadataMap.put("userName", "test-user");
84+
85+
FilterConfig filterConfig = createFilterConfig(null, "Custom-Prefix-", clientId, metadataMap);
86+
TokenMetadataHeaderHandler handler = new TokenMetadataHeaderHandler(filterConfig);
87+
88+
HttpServletRequest inboundRequest = createInboundRequest(clientId);
89+
TestHttpUriRequest outboundRequest = new TestHttpUriRequest();
90+
handler.applyHeadersToRequest(inboundRequest, outboundRequest);
91+
92+
assertEquals("test-user", outboundRequest.getFirstHeader("Custom-Prefix-userName").getValue());
93+
}
94+
95+
@Test
96+
public void testApplyHeadersMissingMetadata() throws Exception {
97+
final String clientId = "test-client-id";
98+
Map<String, String> metadataMap = new HashMap<>(); // Empty metadata
99+
100+
FilterConfig filterConfig = createFilterConfig("custom-meta", null, clientId, metadataMap);
101+
TokenMetadataHeaderHandler handler = new TokenMetadataHeaderHandler(filterConfig);
102+
103+
HttpServletRequest inboundRequest = createInboundRequest(clientId);
104+
TestHttpUriRequest outboundRequest = new TestHttpUriRequest();
105+
handler.applyHeadersToRequest(inboundRequest, outboundRequest);
106+
107+
assertNull("userName header should be null if metadata is missing", outboundRequest.getFirstHeader("X-Knox-Meta-userName"));
108+
assertNull("custom-meta header should be null if metadata is missing", outboundRequest.getFirstHeader("X-Knox-Meta-custom-meta"));
109+
}
110+
111+
private FilterConfig createFilterConfig(String tokenMetadataHeaders, String headerPrefix, String clientId, Map<String, String> metadataMap) throws Exception {
112+
FilterConfig filterConfig = EasyMock.createNiceMock(FilterConfig.class);
113+
ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class);
114+
GatewayServices gatewayServices = EasyMock.createNiceMock(GatewayServices.class);
115+
TokenStateService tss = EasyMock.createNiceMock(TokenStateService.class);
116+
117+
EasyMock.expect(filterConfig.getServletContext()).andReturn(servletContext).anyTimes();
118+
EasyMock.expect(servletContext.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(gatewayServices).anyTimes();
119+
EasyMock.expect(gatewayServices.getService(ServiceType.TOKEN_STATE_SERVICE)).andReturn(tss).anyTimes();
120+
EasyMock.expect(filterConfig.getInitParameter(TokenMetadataHeaderHandler.TOKEN_METADATA_PARAM)).andReturn(tokenMetadataHeaders).anyTimes();
121+
EasyMock.expect(filterConfig.getInitParameter(TokenMetadataHeaderHandler.METADATA_HEADER_PREFIX_PARAM)).andReturn(headerPrefix).anyTimes();
122+
123+
if (clientId != null && metadataMap != null) {
124+
TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
125+
EasyMock.expect(tss.getTokenMetadata(clientId)).andReturn(tokenMetadata).anyTimes();
126+
EasyMock.expect(tokenMetadata.getMetadataMap()).andReturn(metadataMap).anyTimes();
127+
EasyMock.replay(tokenMetadata);
128+
}
129+
130+
EasyMock.replay(filterConfig, servletContext, gatewayServices, tss);
131+
return filterConfig;
132+
}
133+
134+
private HttpServletRequest createInboundRequest(String clientId) {
135+
final String clientSecret = Base64.getEncoder().encodeToString(
136+
(Base64.getEncoder().encodeToString(clientId.getBytes(UTF_8)) + "::" +
137+
Base64.getEncoder().encodeToString("secret".getBytes(UTF_8))).getBytes(UTF_8));
138+
139+
HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
140+
EasyMock.expect(inboundRequest.getParameter(CommonTokenConstants.GRANT_TYPE)).andReturn(CommonTokenConstants.CLIENT_CREDENTIALS).anyTimes();
141+
EasyMock.expect(inboundRequest.getParameter(CommonTokenConstants.CLIENT_SECRET)).andReturn(clientSecret).anyTimes();
142+
EasyMock.replay(inboundRequest);
143+
return inboundRequest;
144+
}
145+
146+
private static class TestHttpUriRequest extends HttpRequestBase {
147+
@Override
148+
public String getMethod() {
149+
return HttpMethod.GET.asString();
150+
}
151+
}
152+
}

0 commit comments

Comments
 (0)