Skip to content

Commit

Permalink
KNOX-3032 - Passcode use without token state service returns 401 (#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
smolnar82 authored Apr 30, 2024
1 parent 1018a3b commit e1a7468
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public interface JWTMessages {
@Message( level = MessageLevel.WARN, text = "Unable to verify token expiration: {0}" )
void unableToVerifyExpiration(@StackTrace( level = MessageLevel.DEBUG) Exception e);

@Message( level = MessageLevel.WARN, text = "Unable to verify passcode token ({0}) due to missing or incorrect token state service configuration.")
void unableToVerifyPasscodeToken(String tokenId);

@Message( level = MessageLevel.ERROR, text = "Unable to issue token: {0}" )
void unableToIssueToken(@StackTrace( level = MessageLevel.DEBUG) Exception e);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
import org.apache.knox.gateway.util.Tokens;

public abstract class AbstractJWTFilter implements Filter {

public static final String TOKEN_STATE_SERVICE_DISABLED_ERROR = "Error in token provider config: passcode use with knox.token.exp.server-managed set to false.";

/**
* If specified, this configuration property refers to a value which the issuer of a received
* token must match. Otherwise, the default value "KNOXSSO" is used
Expand Down Expand Up @@ -433,10 +436,10 @@ protected boolean validateToken(final HttpServletRequest request,
final String passcode)
throws IOException, ServletException {

final String displayableTokenId = tokenId == null ? "N/A" : Tokens.getTokenIDDisplayText(tokenId);
if (tokenStateService != null) {
try {
if (tokenId != null) {
final String displayableTokenId = Tokens.getTokenIDDisplayText(tokenId);
if (tokenIsStillValid(tokenId)) {
final TokenMetadata tokenMetadata = tokenStateService == null ? null : tokenStateService.getTokenMetadata(tokenId);
if (isTokenEnabled(tokenMetadata)) {
Expand Down Expand Up @@ -473,6 +476,9 @@ protected boolean validateToken(final HttpServletRequest request,
log.unableToVerifyExpiration(e);
handleValidationError(request, response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
}
} else {
log.unableToVerifyPasscodeToken(displayableTokenId);
handleValidationError(request, response, HttpServletResponse.SC_UNAUTHORIZED, TOKEN_STATE_SERVICE_DISABLED_ERROR);
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@
import java.util.Date;
import java.util.Properties;

import javax.servlet.FilterConfig;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.knox.gateway.provider.federation.jwt.filter.AbstractJWTFilter;
import org.apache.knox.gateway.provider.federation.jwt.filter.JWTFederationFilter;
import org.apache.knox.gateway.provider.federation.jwt.filter.SignatureVerificationCache;
import org.apache.knox.gateway.services.security.token.TokenMetadata;
import org.apache.knox.gateway.services.security.token.TokenStateService;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

Expand Down Expand Up @@ -98,6 +104,61 @@ public void testCookieAuthSupportCustomCookieName() throws Exception {
testCookieAuthSupport(true, "customCookie");
}

@Test
public void testVerifyPasscodeTokens() throws Exception {
testVerifyPasscodeTokens(true);
}

@Test
public void testVerifyPasscodeTokensTssDisabled() throws Exception {
testVerifyPasscodeTokens(false);
}

private void testVerifyPasscodeTokens(boolean tssEnabled) throws Exception {
final String topologyName = "jwt-topology";
final String tokenId = "4e0c548b-6568-4061-a3dc-62908087650a";
final String passcode = "0138aaed-ca2a-47f1-8ed8-e0c397596f95";
final String passcodeToken = "UGFzc2NvZGU6VGtkVmQxbDZWVEJQUjBsMFRtcFZNazlETURCTlJGbDRURmRGZWxwSFRYUk9ha2sxVFVSbmQwOUVZekpPVkVKb09qcE5SRVY2VDBkR2FGcFhVWFJaTWtWNVdWTXdNRTR5V1hoTVZHaHNXa1JuZEZwVVFtcE5lbXN6VGxSck1scHFhekU9";

final TokenStateService tokenStateService = EasyMock.createNiceMock(TokenStateService.class);
EasyMock.expect(tokenStateService.getTokenExpiration(tokenId)).andReturn(Long.MAX_VALUE).anyTimes();

final TokenMetadata tokenMetadata = EasyMock.createNiceMock(TokenMetadata.class);
EasyMock.expect(tokenMetadata.isEnabled()).andReturn(true).anyTimes();
EasyMock.expect(tokenMetadata.getPasscode()).andReturn(passcodeToken).anyTimes();
EasyMock.expect(tokenStateService.getTokenMetadata(EasyMock.anyString())).andReturn(tokenMetadata).anyTimes();

final Properties filterConfigProps = getProperties();
filterConfigProps.put(TokenStateService.CONFIG_SERVER_MANAGED, Boolean.toString(tssEnabled));
filterConfigProps.put(TestFilterConfig.TOPOLOGY_NAME_PROP, topologyName);
final FilterConfig filterConfig = new TestFilterConfig(filterConfigProps, tokenStateService);
handler.init(filterConfig);

final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getRequestURL()).andReturn(new StringBuffer(SERVICE_URL)).anyTimes();
EasyMock.expect(request.getHeader("Authorization")).andReturn("Basic " + passcodeToken);

final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
if (!tssEnabled) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AbstractJWTFilter.TOKEN_STATE_SERVICE_DISABLED_ERROR);
EasyMock.expectLastCall().once();
}
EasyMock.replay(tokenStateService, tokenMetadata, request, response);

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

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

EasyMock.verify(response);
if (tssEnabled) {
Assert.assertTrue(chain.doFilterCalled);
Assert.assertNotNull(chain.subject);
} else {
Assert.assertFalse(chain.doFilterCalled);
}
}

private void testCookieAuthSupport(boolean validCookie) throws Exception {
testCookieAuthSupport(validCookie, null);
}
Expand Down

0 comments on commit e1a7468

Please sign in to comment.