KEYCLOAK-17259 Add a method to check if the introspection request has duplicate parameters
This commit is contained in:
parent
2796f62899
commit
78754d1127
2 changed files with 70 additions and 0 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue