KEYCLOAK-2726: Invalidate token upon failure
When a token managed by TokenManager is known to be invalid, it should no longer be used. This commit adds a response listener to the only filter using TokenManager, which causes, upon authentication failure, to invalidate the token that was used.
This commit is contained in:
parent
dfc4cf36a2
commit
ad7a6c4854
2 changed files with 38 additions and 2 deletions
|
@ -21,14 +21,18 @@ import org.keycloak.admin.client.token.TokenManager;
|
||||||
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
import javax.ws.rs.client.ClientRequestContext;
|
||||||
import javax.ws.rs.client.ClientRequestFilter;
|
import javax.ws.rs.client.ClientRequestFilter;
|
||||||
|
import javax.ws.rs.client.ClientResponseContext;
|
||||||
|
import javax.ws.rs.client.ClientResponseFilter;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author rodrigo.sasaki@icarros.com.br
|
* @author rodrigo.sasaki@icarros.com.br
|
||||||
*/
|
*/
|
||||||
public class BearerAuthFilter implements ClientRequestFilter {
|
public class BearerAuthFilter implements ClientRequestFilter, ClientResponseFilter {
|
||||||
|
|
||||||
|
public static final String AUTH_HEADER_PREFIX = "Bearer ";
|
||||||
private final String tokenString;
|
private final String tokenString;
|
||||||
private final TokenManager tokenManager;
|
private final TokenManager tokenManager;
|
||||||
|
|
||||||
|
@ -45,9 +49,27 @@ public class BearerAuthFilter implements ClientRequestFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||||
String authHeader = "Bearer " + (tokenManager != null ? tokenManager.getAccessTokenString() : tokenString);
|
String authHeader = AUTH_HEADER_PREFIX + (tokenManager != null ? tokenManager.getAccessTokenString() : tokenString);
|
||||||
|
|
||||||
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
|
||||||
|
if (responseContext.getStatus() == 401 && tokenManager != null) {
|
||||||
|
List<Object> authHeaders = requestContext.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (authHeaders == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Object authHeader : authHeaders) {
|
||||||
|
if (authHeader instanceof String) {
|
||||||
|
String headerValue = (String) authHeader;
|
||||||
|
if (headerValue.startsWith(AUTH_HEADER_PREFIX)) {
|
||||||
|
String token = headerValue.substring( AUTH_HEADER_PREFIX.length() );
|
||||||
|
tokenManager.invalidate( token );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,4 +118,18 @@ public class TokenManager {
|
||||||
return (Time.currentTime() + minTokenValidity) >= expirationTime;
|
return (Time.currentTime() + minTokenValidity) >= expirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates the current token, but only when it is equal to the token passed as an argument.
|
||||||
|
*
|
||||||
|
* @param token the token to invalidate (cannot be null).
|
||||||
|
*/
|
||||||
|
public void invalidate(String token) {
|
||||||
|
if (currentToken == null) {
|
||||||
|
return; // There's nothing to invalidate.
|
||||||
|
}
|
||||||
|
if (token.equals(currentToken.getToken())) {
|
||||||
|
// When used next, this cause a refresh attempt, that in turn will cause a grant attempt if refreshing fails.
|
||||||
|
expirationTime = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue