KEYCLOAK-17300 Add a method to check if the token revocation request has duplicate parameters
This commit is contained in:
parent
3d76e2b775
commit
2605eddbe7
2 changed files with 63 additions and 0 deletions
|
@ -99,6 +99,8 @@ public class TokenRevocationEndpoint {
|
|||
|
||||
formParams = request.getDecodedFormParameters();
|
||||
|
||||
checkParameterDuplicated(formParams);
|
||||
|
||||
try {
|
||||
session.clientPolicy().triggerOnEvent(new TokenRevokeContext(formParams));
|
||||
} catch (ClientPolicyException cpe) {
|
||||
|
@ -219,6 +221,14 @@ public class TokenRevocationEndpoint {
|
|||
event.user(user);
|
||||
}
|
||||
|
||||
private void checkParameterDuplicated(MultivaluedMap<String, String> formParams) {
|
||||
for (String key : formParams.keySet()) {
|
||||
if (formParams.get(key).size() != 1) {
|
||||
throw new CorsErrorResponseException(cors, Errors.INVALID_REQUEST, "duplicated parameter", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void revokeClient() {
|
||||
session.users().revokeConsentForClient(realm, user.getId(), client.getId());
|
||||
if (TokenUtil.TOKEN_TYPE_OFFLINE.equals(token.getType())) {
|
||||
|
|
|
@ -25,19 +25,30 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.apache.commons.io.output.ByteArrayOutputStream;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
|
||||
|
@ -211,6 +222,22 @@ public class TokenRevocationTest extends AbstractKeycloakTest {
|
|||
isTokenDisabled(tokenResponse, "test-app");
|
||||
}
|
||||
|
||||
// KEYCLOAK-17300
|
||||
@Test
|
||||
public void testRevokeRequestParamsMoreThanOnce() throws Exception {
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("password", "test-user@localhost",
|
||||
"password");
|
||||
|
||||
isTokenEnabled(tokenResponse, "test-app");
|
||||
|
||||
String revokeResponse = doTokenRevokeWithDuplicateParams(tokenResponse.getRefreshToken(), "refresh_token", "password");
|
||||
|
||||
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(revokeResponse, OAuth2ErrorRepresentation.class);
|
||||
assertEquals("duplicated parameter", errorRep.getErrorDescription());
|
||||
assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
|
||||
}
|
||||
|
||||
private AccessTokenResponse login(String clientId, String username, String password) {
|
||||
oauth.clientId(clientId);
|
||||
oauth.openLoginForm();
|
||||
|
@ -248,4 +275,30 @@ public class TokenRevocationTest extends AbstractKeycloakTest {
|
|||
TokenMetadataRepresentation rep = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
|
||||
assertFalse(rep.isActive());
|
||||
}
|
||||
|
||||
private String doTokenRevokeWithDuplicateParams(String token, String tokenTypeHint, String clientSecret)
|
||||
throws IOException {
|
||||
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
|
||||
HttpPost post = new HttpPost(oauth.getTokenRevocationUrl());
|
||||
|
||||
List<NameValuePair> parameters = new LinkedList<>();
|
||||
parameters.add(new BasicNameValuePair("token", token));
|
||||
parameters.add(new BasicNameValuePair("token", "foo"));
|
||||
parameters.add(new BasicNameValuePair("token_type_hint", tokenTypeHint));
|
||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, oauth.getClientId()));
|
||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_SECRET, clientSecret));
|
||||
|
||||
UrlEncodedFormEntity formEntity;
|
||||
try {
|
||||
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
post.setEntity(formEntity);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
client.execute(post).getEntity().writeTo(out);
|
||||
return new String(out.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue