Skip to content

Commit 5d2b153

Browse files
authored
KNOX-3261 - Refactored JWTProvider and OAuthFlows tests to avoid code duplication (#1156)
1 parent 71a72e5 commit 5d2b153

File tree

2 files changed

+68
-134
lines changed

2 files changed

+68
-134
lines changed

gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -355,30 +355,22 @@ private Pair<TokenType, String> getTokenFromRequestBody(ServletRequest request)
355355
return Pair.of(TokenType.Passcode, clientSecret);
356356
} else if (REFRESH_TOKEN.equals(grantType)) {
357357
// refresh_token flow: the refresh_token parameter contains the actual token
358-
final String refreshToken = request.getParameter(REFRESH_TOKEN_PARAM);
359-
if (refreshToken != null) {
360-
// determine if it's a JWT or passcode token
361-
if (isJWT(refreshToken)) {
362-
return Pair.of(TokenType.JWT, refreshToken);
363-
} else {
364-
return Pair.of(TokenType.Passcode, refreshToken);
365-
}
366-
}
358+
return getRefreshOrSubjectToken(request, REFRESH_TOKEN_PARAM);
367359
} else if (TOKEN_EXCHANGE.equals(grantType)) {
368360
// token_exchange flow: the subject_token parameter contains the token to be exchanged
369-
final String subjectToken = request.getParameter(SUBJECT_TOKEN);
370-
if (subjectToken != null) {
371-
// determine if it's a JWT or passcode token
372-
if (isJWT(subjectToken)) {
373-
return Pair.of(TokenType.JWT, subjectToken);
374-
} else {
375-
return Pair.of(TokenType.Passcode, subjectToken);
376-
}
377-
}
361+
return getRefreshOrSubjectToken(request, SUBJECT_TOKEN);
378362
}
379363
return null;
380364
}
381365

366+
private Pair<TokenType, String> getRefreshOrSubjectToken(final ServletRequest request, final String requestParamName) {
367+
final String refreshOrSubjectToken = request.getParameter(requestParamName);
368+
if (refreshOrSubjectToken != null) {
369+
return isJWT(refreshOrSubjectToken) ? Pair.of(TokenType.JWT, refreshOrSubjectToken) : Pair.of(TokenType.Passcode, refreshOrSubjectToken);
370+
}
371+
return null;
372+
}
373+
382374
private Pair<TokenType, String> parseFromHTTPBasicCredentials(final String header, final ServletRequest request) {
383375
Pair<TokenType, String> parsed = null;
384376
final String base64Credentials = header.substring(BASIC.length()).trim();

gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/OAuthFlowsFederationFilterTest.java

Lines changed: 58 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.knox.gateway.provider.federation.jwt.filter.SignatureVerificationCache;
2424
import org.apache.knox.gateway.services.security.token.TokenMetadata;
2525
import org.apache.knox.gateway.services.security.token.TokenStateService;
26+
import org.apache.knox.gateway.services.security.token.UnknownTokenException;
2627
import org.easymock.EasyMock;
2728
import org.junit.Assert;
2829
import org.junit.Test;
@@ -105,34 +106,14 @@ public void testVerifyClientCredentialsFlow() throws Exception {
105106
final String topologyName = "jwt-topology";
106107
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650a";
107108
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f95";
108-
String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJoOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazE=";
109+
final String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJoOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazE=";
109110

110-
final TokenStateService tokenStateService = EasyMock.createNiceMock(TokenStateService.class);
111-
EasyMock.expect(tokenStateService.getTokenExpiration(tokenId)).andReturn(Long.MAX_VALUE).anyTimes();
112-
113-
final TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
114-
EasyMock.expect(tokenMetadata.isEnabled()).andReturn(true).anyTimes();
115-
EasyMock.expect(tokenMetadata.getPasscode()).andReturn(passcodeToken).anyTimes();
116-
EasyMock.expect(tokenStateService.getTokenMetadata(EasyMock.anyString())).andReturn(tokenMetadata).anyTimes();
117-
118-
final Properties filterConfigProps = getProperties();
119-
filterConfigProps.put(TokenStateService.CONFIG_SERVER_MANAGED, Boolean.toString(true));
120-
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, topologyName);
121-
final FilterConfig filterConfig = new TestFilterConfig(filterConfigProps, tokenStateService);
122-
handler.init(filterConfig);
123-
124-
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
125-
EasyMock.expect(request.getRequestURL()).andReturn(new StringBuffer(SERVICE_URL)).anyTimes();
126-
127-
// LJM TODO: this will be needed later for client credentials as Basic auth header
128-
//EasyMock.expect(request.getHeader("Authorization")).andReturn(authTokenType + passcodeToken);
129-
ensureClientCredentials(request, passcodeToken);
130-
EasyMock.expect(request.getParameter("client_id")).andReturn(tokenId).anyTimes();
111+
final Pair<TokenStateService, TokenMetadata> tokenServices = createMockTokenStateService(tokenId, passcodeToken);
112+
final FilterConfig filterConfig = initFilter(tokenServices.getLeft());
131113

114+
final HttpServletRequest request = createMockRequestForClientCredentials(tokenId);
132115
final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
133-
// response.setStatus(HttpServletResponse.SC_OK);
134-
// EasyMock.expectLastCall().once();
135-
EasyMock.replay(tokenStateService, tokenMetadata, request, response);
116+
EasyMock.replay(tokenServices.getLeft(), tokenServices.getRight(), request, response);
136117

137118
SignatureVerificationCache.getInstance(topologyName, filterConfig).recordSignatureVerification(passcode);
138119

@@ -149,35 +130,18 @@ public void testFailedVerifyClientCredentialsFlow() throws Exception {
149130
final String topologyName = "jwt-topology";
150131
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650a";
151132
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f95";
152-
String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJoOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazE=";
153-
154-
final TokenStateService tokenStateService = EasyMock.createNiceMock(TokenStateService.class);
155-
EasyMock.expect(tokenStateService.getTokenExpiration(tokenId)).andReturn(Long.MAX_VALUE).anyTimes();
156-
157-
final TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
158-
EasyMock.expect(tokenMetadata.isEnabled()).andReturn(true).anyTimes();
159-
EasyMock.expect(tokenMetadata.getPasscode()).andReturn(passcodeToken).anyTimes();
160-
EasyMock.expect(tokenStateService.getTokenMetadata(EasyMock.anyString())).andReturn(tokenMetadata).anyTimes();
161-
162-
final Properties filterConfigProps = getProperties();
163-
filterConfigProps.put(TokenStateService.CONFIG_SERVER_MANAGED, Boolean.toString(true));
164-
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, topologyName);
165-
final FilterConfig filterConfig = new TestFilterConfig(filterConfigProps, tokenStateService);
166-
handler.init(filterConfig);
133+
final String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJoOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazE=";
167134

168-
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
169-
EasyMock.expect(request.getRequestURL()).andReturn(new StringBuffer(SERVICE_URL)).anyTimes();
135+
final Pair<TokenStateService, TokenMetadata> tokenServices = createMockTokenStateService(tokenId, passcodeToken);
136+
final FilterConfig filterConfig = initFilter(tokenServices.getLeft());
170137

171-
// LJM TODO: this will be needed later for client credentials as Basic auth header
172-
//EasyMock.expect(request.getHeader("Authorization")).andReturn(authTokenType + passcodeToken);
173-
ensureClientCredentials(request, passcodeToken);
174-
EasyMock.expect(request.getParameter("client_id")).andReturn(tokenId + "invalidating_string").anyTimes();
138+
final HttpServletRequest request = createMockRequestForClientCredentials(tokenId + "invalidating_string");
175139

176140
final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
177141
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
178142
JWTFederationFilter.MISMATCHING_CLIENT_ID_AND_CLIENT_SECRET);
179143
EasyMock.expectLastCall().once();
180-
EasyMock.replay(tokenStateService, tokenMetadata, request, response);
144+
EasyMock.replay(tokenServices.getLeft(), tokenServices.getRight(), request, response);
181145

182146
SignatureVerificationCache.getInstance(topologyName, filterConfig).recordSignatureVerification(passcode);
183147

@@ -247,118 +211,96 @@ public void testUnableToParseJWT() throws Exception {
247211
@Test
248212
public void testGetWireTokenUsingRefreshTokenFlow() throws Exception {
249213
final String refreshToken = "WTJ4cFpXNTBMV2xrTFRFeU16UTE6OlkyeHBaVzUwTFhObFkzSmxkQzB4TWpNME5RPT0=";
250-
251-
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
252-
EasyMock.expect(request.getHeader("Authorization")).andReturn(null).anyTimes();
253-
EasyMock.expect(request.getQueryString()).andReturn(null).anyTimes();
254-
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(JWTFederationFilter.REFRESH_TOKEN).anyTimes();
255-
EasyMock.expect(request.getParameter(JWTFederationFilter.REFRESH_TOKEN_PARAM)).andReturn(refreshToken).anyTimes();
256-
EasyMock.replay(request);
257-
258-
handler.init(new TestFilterConfig(getProperties()));
259-
final Pair<TokenType, String> wireToken = ((TestJWTFederationFilter) handler).getWireToken(request);
260-
261-
EasyMock.verify(request);
262-
263-
assertNotNull(wireToken);
264-
assertEquals(TokenType.Passcode, wireToken.getLeft());
265-
assertEquals(refreshToken, wireToken.getRight());
214+
testGetWireTokenWithGrant(JWTFederationFilter.REFRESH_TOKEN, JWTFederationFilter.REFRESH_TOKEN_PARAM, refreshToken);
266215
}
267216

268217
@Test
269218
public void testGetWireTokenUsingTokenExchangeFlow() throws Exception {
270219
final String subjectToken = "WTJ4cFpXNTBMV2xrTFRFeU16UTE2OlkyeHBaVzUwTFhObFkzSmxkQzB4TWpNME5RPT0=";
271-
272-
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
273-
EasyMock.expect(request.getHeader("Authorization")).andReturn(null).anyTimes();
274-
EasyMock.expect(request.getQueryString()).andReturn(null).anyTimes();
275-
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(JWTFederationFilter.TOKEN_EXCHANGE).anyTimes();
276-
EasyMock.expect(request.getParameter(JWTFederationFilter.SUBJECT_TOKEN)).andReturn(subjectToken).anyTimes();
277-
EasyMock.replay(request);
278-
279-
handler.init(new TestFilterConfig(getProperties()));
280-
final Pair<TokenType, String> wireToken = ((TestJWTFederationFilter) handler).getWireToken(request);
281-
282-
EasyMock.verify(request);
283-
284-
assertNotNull(wireToken);
285-
assertEquals(TokenType.Passcode, wireToken.getLeft());
286-
assertEquals(subjectToken, wireToken.getRight());
220+
testGetWireTokenWithGrant(JWTFederationFilter.TOKEN_EXCHANGE, JWTFederationFilter.SUBJECT_TOKEN, subjectToken);
287221
}
288222

289223
@Test
290224
public void testVerifyRefreshTokenFlow() throws Exception {
291-
final String topologyName = "jwt-topology";
292225
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650b";
293226
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f96";
294-
String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJpOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazI=";
227+
final String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJpOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazI=";
228+
testVerifyTokenWithGrant(tokenId, passcode, passcodeToken, JWTFederationFilter.REFRESH_TOKEN, JWTFederationFilter.REFRESH_TOKEN_PARAM);
229+
}
230+
231+
@Test
232+
public void testVerifyTokenExchangeFlow() throws Exception {
233+
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650c";
234+
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f97";
235+
final String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJqOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazM=";
236+
testVerifyTokenWithGrant(tokenId, passcode, passcodeToken, JWTFederationFilter.TOKEN_EXCHANGE, JWTFederationFilter.SUBJECT_TOKEN);
237+
}
295238

239+
private Pair<TokenStateService, TokenMetadata> createMockTokenStateService(String tokenId, String passcodeToken) throws UnknownTokenException {
296240
final TokenStateService tokenStateService = EasyMock.createNiceMock(TokenStateService.class);
297241
EasyMock.expect(tokenStateService.getTokenExpiration(tokenId)).andReturn(Long.MAX_VALUE).anyTimes();
298242

299243
final TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
300244
EasyMock.expect(tokenMetadata.isEnabled()).andReturn(true).anyTimes();
301245
EasyMock.expect(tokenMetadata.getPasscode()).andReturn(passcodeToken).anyTimes();
302246
EasyMock.expect(tokenStateService.getTokenMetadata(EasyMock.anyString())).andReturn(tokenMetadata).anyTimes();
247+
return Pair.of(tokenStateService, tokenMetadata);
248+
}
303249

250+
private FilterConfig initFilter(TokenStateService tokenStateService) throws Exception {
304251
final Properties filterConfigProps = getProperties();
305252
filterConfigProps.put(TokenStateService.CONFIG_SERVER_MANAGED, Boolean.toString(true));
306-
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, topologyName);
253+
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, "jwt-topology");
307254
final FilterConfig filterConfig = new TestFilterConfig(filterConfigProps, tokenStateService);
308255
handler.init(filterConfig);
256+
return filterConfig;
257+
}
309258

259+
private HttpServletRequest createMockRequestForClientCredentials(String clientId) {
310260
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
261+
final String clientCredentials = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJoOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazE=";
311262
EasyMock.expect(request.getRequestURL()).andReturn(new StringBuffer(SERVICE_URL)).anyTimes();
312-
EasyMock.expect(request.getHeader("Authorization")).andReturn(null).anyTimes();
313-
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(JWTFederationFilter.REFRESH_TOKEN).anyTimes();
314-
EasyMock.expect(request.getParameter(JWTFederationFilter.REFRESH_TOKEN_PARAM)).andReturn(passcodeToken).anyTimes();
315-
EasyMock.expect(request.getQueryString()).andReturn(null).anyTimes();
263+
ensureClientCredentials(request, clientCredentials);
264+
EasyMock.expect(request.getParameter("client_id")).andReturn(clientId).anyTimes();
265+
return request;
266+
}
316267

317-
final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
318-
EasyMock.replay(tokenStateService, tokenMetadata, request, response);
268+
private void testGetWireTokenWithGrant(String grantType, String tokenParam, String tokenValue) throws Exception {
269+
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
270+
EasyMock.expect(request.getHeader("Authorization")).andReturn(null).anyTimes();
271+
EasyMock.expect(request.getQueryString()).andReturn(null).anyTimes();
272+
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(grantType).anyTimes();
273+
EasyMock.expect(request.getParameter(tokenParam)).andReturn(tokenValue).anyTimes();
274+
EasyMock.replay(request);
319275

320-
SignatureVerificationCache.getInstance(topologyName, filterConfig).recordSignatureVerification(passcode);
276+
handler.init(new TestFilterConfig(getProperties()));
277+
final Pair<TokenType, String> wireToken = ((TestJWTFederationFilter) handler).getWireToken(request);
321278

322-
final TestFilterChain chain = new TestFilterChain();
323-
handler.doFilter(request, response, chain);
279+
EasyMock.verify(request);
324280

325-
EasyMock.verify(response);
326-
Assert.assertTrue(chain.doFilterCalled);
327-
Assert.assertNotNull(chain.subject);
281+
assertNotNull(wireToken);
282+
assertEquals(TokenType.Passcode, wireToken.getLeft());
283+
assertEquals(tokenValue, wireToken.getRight());
328284
}
329285

330-
@Test
331-
public void testVerifyTokenExchangeFlow() throws Exception {
332-
final String topologyName = "jwt-topology";
333-
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650c";
334-
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f97";
335-
String passcodeToken = "TkdVd1l6VTBPR0l0TmpVMk9DMDBNRFl4TFdFelpHTXROakk1TURnd09EYzJOVEJqOjpNREV6T0dGaFpXUXRZMkV5WVMwME4yWXhMVGhsWkRndFpUQmpNemszTlRrMlpqazM=";
336-
337-
final TokenStateService tokenStateService = EasyMock.createNiceMock(TokenStateService.class);
338-
EasyMock.expect(tokenStateService.getTokenExpiration(tokenId)).andReturn(Long.MAX_VALUE).anyTimes();
339-
340-
final TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
341-
EasyMock.expect(tokenMetadata.isEnabled()).andReturn(true).anyTimes();
342-
EasyMock.expect(tokenMetadata.getPasscode()).andReturn(passcodeToken).anyTimes();
343-
EasyMock.expect(tokenStateService.getTokenMetadata(EasyMock.anyString())).andReturn(tokenMetadata).anyTimes();
286+
private void testVerifyTokenWithGrant(String tokenId, String passcode, String passcodeToken, String grantType, String tokenParam) throws Exception {
287+
final Pair<TokenStateService, TokenMetadata> tokenServices = createMockTokenStateService(tokenId, passcodeToken);
288+
final TokenStateService tokenStateService = tokenServices.getLeft();
289+
final TokenMetadata tokenMetadata = tokenServices.getRight();
344290

345-
final Properties filterConfigProps = getProperties();
346-
filterConfigProps.put(TokenStateService.CONFIG_SERVER_MANAGED, Boolean.toString(true));
347-
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, topologyName);
348-
final FilterConfig filterConfig = new TestFilterConfig(filterConfigProps, tokenStateService);
349-
handler.init(filterConfig);
291+
final FilterConfig filterConfig = initFilter(tokenStateService);
350292

351293
final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
352294
EasyMock.expect(request.getRequestURL()).andReturn(new StringBuffer(SERVICE_URL)).anyTimes();
353295
EasyMock.expect(request.getHeader("Authorization")).andReturn(null).anyTimes();
354-
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(JWTFederationFilter.TOKEN_EXCHANGE).anyTimes();
355-
EasyMock.expect(request.getParameter(JWTFederationFilter.SUBJECT_TOKEN)).andReturn(passcodeToken).anyTimes();
296+
EasyMock.expect(request.getParameter(JWTFederationFilter.GRANT_TYPE)).andReturn(grantType).anyTimes();
297+
EasyMock.expect(request.getParameter(tokenParam)).andReturn(passcodeToken).anyTimes();
356298
EasyMock.expect(request.getQueryString()).andReturn(null).anyTimes();
357299

358300
final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
359301
EasyMock.replay(tokenStateService, tokenMetadata, request, response);
360302

361-
SignatureVerificationCache.getInstance(topologyName, filterConfig).recordSignatureVerification(passcode);
303+
SignatureVerificationCache.getInstance("jwt-topology", filterConfig).recordSignatureVerification(passcode);
362304

363305
final TestFilterChain chain = new TestFilterChain();
364306
handler.doFilter(request, response, chain);

0 commit comments

Comments
 (0)