Verify if token is revoked when validating bearer tokens (#16394)
Closes #16388
This commit is contained in:
parent
3d62dc4254
commit
9945135861
4 changed files with 47 additions and 6 deletions
|
@ -1332,7 +1332,7 @@ public class TokenManager {
|
|||
/**
|
||||
* Check if access token was revoked with OAuth revocation endpoint
|
||||
*/
|
||||
public static class TokenRevocationCheck implements TokenVerifier.Predicate<AccessToken> {
|
||||
public static class TokenRevocationCheck implements TokenVerifier.Predicate<JsonWebToken> {
|
||||
|
||||
private final KeycloakSession session;
|
||||
|
||||
|
@ -1341,7 +1341,7 @@ public class TokenManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean test(AccessToken token) {
|
||||
public boolean test(JsonWebToken token) {
|
||||
SingleUseObjectProvider singleUseStore = session.getProvider(SingleUseObjectProvider.class);
|
||||
return !singleUseStore.contains(token.getId() + SingleUseObjectProvider.REVOKED_KEY);
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ import org.keycloak.crypto.SignatureVerifierContext;
|
|||
import org.keycloak.jose.jws.JWSBuilder;
|
||||
import org.keycloak.models.ClientInitialAccessModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.TokenManager;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.TokenManager.TokenRevocationCheck;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.clientregistration.policy.RegistrationAuth;
|
||||
|
@ -94,7 +94,7 @@ public class ClientRegistrationTokenUtils {
|
|||
JsonWebToken jwt;
|
||||
try {
|
||||
TokenVerifier<JsonWebToken> verifier = TokenVerifier.create(token, JsonWebToken.class)
|
||||
.withChecks(new TokenVerifier.RealmUrlCheck(getIssuer(session, realm)), TokenVerifier.IS_ACTIVE);
|
||||
.withChecks(new TokenVerifier.RealmUrlCheck(getIssuer(session, realm)), TokenVerifier.IS_ACTIVE, new TokenRevocationCheck(session));
|
||||
|
||||
SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
|
||||
verifier.verifierContext(verifierContext);
|
||||
|
|
|
@ -128,9 +128,13 @@ public abstract class AbstractClientRegistrationTest extends AbstractKeycloakTes
|
|||
reg.auth(Auth.token(getToken("no-access", "password")));
|
||||
}
|
||||
|
||||
private String getToken(String username, String password) {
|
||||
protected String getToken(String username, String password) {
|
||||
return getToken(Constants.ADMIN_CLI_CLIENT_ID, null, username, password);
|
||||
}
|
||||
|
||||
protected String getToken(String clientId, String clientSecret, String username, String password) {
|
||||
try {
|
||||
return oauth.doGrantAccessTokenRequest(REALM_NAME, username, password, null, Constants.ADMIN_CLI_CLIENT_ID, null).getAccessToken();
|
||||
return oauth.doGrantAccessTokenRequest(REALM_NAME, username, password, null, clientId, clientSecret).getAccessToken();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.keycloak.client.registration.Auth;
|
|||
import org.keycloak.client.registration.ClientRegistration;
|
||||
import org.keycloak.client.registration.ClientRegistrationException;
|
||||
import org.keycloak.client.registration.HttpErrorException;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||
|
@ -46,6 +47,7 @@ import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
|
|||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -176,6 +178,41 @@ public class ClientRegistrationTest extends AbstractClientRegistrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerClientUsingRevokedToken() throws Exception {
|
||||
reg.auth(Auth.token(getToken("manage-clients", "password")));
|
||||
|
||||
ClientRepresentation myclient = new ClientRepresentation();
|
||||
|
||||
myclient.setClientId("myclient");
|
||||
myclient.setServiceAccountsEnabled(true);
|
||||
myclient.setSecret("password");
|
||||
myclient.setDirectAccessGrantsEnabled(true);
|
||||
|
||||
reg.create(myclient);
|
||||
|
||||
oauth.clientId("myclient");
|
||||
String bearerToken = getToken("myclient", "password", "manage-clients", "password");
|
||||
try (CloseableHttpResponse response = oauth.doTokenRevoke(bearerToken, "access_token", "password")) {
|
||||
assertEquals(Response.Status.OK.getStatusCode(), response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
try {
|
||||
reg.auth(Auth.token(bearerToken));
|
||||
|
||||
ClientRepresentation clientRep = buildClient();
|
||||
clientRep.setServiceAccountsEnabled(true);
|
||||
|
||||
registerClient(clientRep);
|
||||
} catch (ClientRegistrationException cre) {
|
||||
HttpErrorException cause = (HttpErrorException) cre.getCause();
|
||||
assertEquals(401, cause.getStatusLine().getStatusCode());
|
||||
OAuth2ErrorRepresentation error = cause.toErrorRepresentation();
|
||||
assertEquals(Errors.INVALID_TOKEN, error.getError());
|
||||
assertEquals("Failed decode token", error.getErrorDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerClientWithNonAsciiChars() throws ClientRegistrationException {
|
||||
authCreateClients();
|
||||
|
|
Loading…
Reference in a new issue