KEYCLOAK-17259 Add a method to check if the introspection request has duplicate parameters

This commit is contained in:
Yang Xie 2021-03-02 08:52:44 +00:00 committed by Marek Posolda
parent 2796f62899
commit 78754d1127
2 changed files with 70 additions and 0 deletions

View file

@ -81,6 +81,9 @@ public class TokenIntrospectionEndpoint {
authorizeClient();
MultivaluedMap<String, String> formParams = request.getDecodedFormParameters();
checkParameterDuplicated(formParams);
String tokenTypeHint = formParams.getFirst(PARAM_TOKEN_TYPE_HINT);
if (tokenTypeHint == null) {
@ -148,6 +151,15 @@ public class TokenIntrospectionEndpoint {
}
}
private void checkParameterDuplicated(MultivaluedMap<String, String> formParams) {
for (String key : formParams.keySet()) {
if (formParams.get(key).size() != 1) {
throw throwErrorResponseException(Errors.INVALID_REQUEST, "duplicated parameter", Status.BAD_REQUEST);
}
}
}
private ErrorResponseException throwErrorResponseException(String error, String detail, Status status) {
this.event.detail("detail", detail).error(error);
return new ErrorResponseException(error, detail, status);

View file

@ -19,6 +19,14 @@ package org.keycloak.testsuite.oauth;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.TextNode;
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.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
@ -45,10 +53,14 @@ import org.keycloak.testsuite.util.KeycloakModelUtils;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
import org.keycloak.testsuite.util.TokenSignatureUtil;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
import javax.ws.rs.core.UriBuilder;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import static org.junit.Assert.assertEquals;
@ -443,4 +455,50 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
return tokenResponse;
}
// KEYCLOAK-17259
@Test
public void testIntrospectionRequestParamsMoreThanOnce() throws Exception {
oauth.doLogin("test-user@localhost", "password");
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
accessTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken(), "password");
String tokenResponse = introspectAccessTokenWithDuplicateParams("confidential-cli", "secret1", accessTokenResponse.getAccessToken());
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
assertEquals("duplicated parameter", errorRep.getErrorDescription());
assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
}
private String introspectAccessTokenWithDuplicateParams(String clientId, String clientSecret, String tokenToIntrospect) {
HttpPost post = new HttpPost(oauth.getTokenIntrospectionUrl());
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
post.setHeader("Authorization", authorization);
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair("token", tokenToIntrospect));
parameters.add(new BasicNameValuePair("token", "foo"));
parameters.add(new BasicNameValuePair("token_type_hint", "access_token"));
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
try (CloseableHttpResponse response = HttpClientBuilder.create().build().execute(post)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
return new String(out.toByteArray());
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve access token", e);
}
}
}