Move token introspection to AbstractOAuthClient (#37859)

Closes #37858

Signed-off-by: stianst <stianst@gmail.com>
This commit is contained in:
Stian Thorgersen
2025-03-06 11:56:59 +01:00
committed by GitHub
parent 497a1141a7
commit d089e23aef
26 changed files with 185 additions and 237 deletions

View File

@@ -15,9 +15,12 @@ import org.keycloak.testframework.realm.UserConfig;
import org.keycloak.testframework.realm.UserConfigBuilder;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
import org.keycloak.testsuite.util.oauth.IntrospectionResponse;
import org.keycloak.testsuite.util.oauth.TokenRevocationResponse;
import org.keycloak.testsuite.util.oauth.UserInfoResponse;
import java.io.IOException;
@KeycloakIntegrationTest
public class OAuthClientTest {
@@ -82,6 +85,15 @@ public class OAuthClientTest {
Assertions.assertNotNull(oidcConfiguration);
}
@Test
public void testIntrospection() throws IOException {
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());
IntrospectionResponse introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
Assertions.assertTrue(introspectionResponse.isSuccess());
Assertions.assertTrue(introspectionResponse.asTokenMetadata().isActive());
}
@Test
public void testRevocation() {
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());

View File

@@ -3,10 +3,12 @@ package org.keycloak.testsuite.util.oauth;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.http.Header;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.keycloak.OAuth2Constants;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@@ -79,6 +81,10 @@ public abstract class AbstractHttpResponse {
return JsonSerialization.readValue(response.getEntity().getContent(), clazz);
}
protected String asString() throws IOException {
return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
protected abstract void parseContent() throws IOException;
private void parseError() throws IOException {

View File

@@ -132,6 +132,22 @@ public abstract class AbstractOAuthClient<T> {
return userInfoRequest(accessToken).send();
}
public IntrospectionRequest introspectionRequest(String tokenToIntrospect) {
return new IntrospectionRequest(tokenToIntrospect, this);
}
public IntrospectionResponse doIntrospectionRequest(String tokenToIntrospect, String tokenType) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint(tokenType).send();
}
public IntrospectionResponse doIntrospectionAccessTokenRequest(String tokenToIntrospect) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint("access_token").send();
}
public IntrospectionResponse doIntrospectionRefreshTokenRequest(String tokenToIntrospect) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint("refresh_token").send();
}
public TokenRevocationRequest tokenRevocationRequest(String token) {
return new TokenRevocationRequest(token, this);
}

View File

@@ -1,19 +1,17 @@
package org.keycloak.testsuite.util.oauth;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.keycloak.utils.MediaType;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class IntrospectionRequest extends AbstractHttpPostRequest<IntrospectionRequest, String> {
public class IntrospectionRequest extends AbstractHttpPostRequest<IntrospectionRequest, IntrospectionResponse> {
private final String token;
private String tokenTypeHint;
private boolean jwtResponse = false;
IntrospectionRequest(String token, OAuthClient client) {
IntrospectionRequest(String token, AbstractOAuthClient<?> client) {
super(client);
this.token = token;
}
@@ -39,8 +37,8 @@ public class IntrospectionRequest extends AbstractHttpPostRequest<IntrospectionR
}
@Override
protected String toResponse(CloseableHttpResponse response) throws IOException {
return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
protected IntrospectionResponse toResponse(CloseableHttpResponse response) throws IOException {
return new IntrospectionResponse(response);
}
@Override

View File

@@ -0,0 +1,35 @@
package org.keycloak.testsuite.util.oauth;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
public class IntrospectionResponse extends AbstractHttpResponse {
private String raw;
IntrospectionResponse(CloseableHttpResponse response) throws IOException {
super(response);
}
@Override
protected void parseContent() throws IOException {
raw = asString();
}
public String getRaw() {
return raw;
}
public JsonNode asJsonNode() throws IOException {
return JsonSerialization.readValue(raw, JsonNode.class);
}
public TokenMetadataRepresentation asTokenMetadata() throws IOException {
return JsonSerialization.readValue(raw, TokenMetadataRepresentation.class);
}
}

View File

@@ -27,15 +27,12 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.OAuth2Constants;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.models.Constants;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.grants.ciba.channel.AuthenticationChannelResponse;
import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
import org.keycloak.representations.ClaimsRepresentation;
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.DroneUtils;
import org.keycloak.testsuite.util.WaitUtils;
@@ -148,22 +145,6 @@ public class OAuthClient extends AbstractOAuthClient<OAuthClient> {
loginPage.login(username, password);
}
public IntrospectionRequest introspectionRequest(String tokenToIntrospect) {
return new IntrospectionRequest(tokenToIntrospect, this);
}
public String doIntrospectionRequest(String tokenToIntrospect, String tokenType) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint(tokenType).send();
}
public String doIntrospectionAccessTokenRequest(String tokenToIntrospect) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint("access_token").send();
}
public String doIntrospectionRefreshTokenRequest(String tokenToIntrospect) {
return introspectionRequest(tokenToIntrospect).tokenTypeHint("refresh_token").send();
}
public TokenExchangeRequest tokenExchangeRequest(String subjectToken) {
return new TokenExchangeRequest(subjectToken, this);
}

View File

@@ -583,7 +583,7 @@ public class UmaGrantTypeTest extends AbstractResourceServerTest {
assertNotNull(introspectionResponse.getPermissions());
oauth.realm("authz-test").client("resource-server-test", "secret");
String introspectHttpResponse = oauth.doIntrospectionRequest(rpt, "requesting_party_token");
String introspectHttpResponse = oauth.doIntrospectionRequest(rpt, "requesting_party_token").getRaw();
Map jsonNode = JsonSerialization.readValue(introspectHttpResponse, Map.class);

View File

@@ -564,9 +564,7 @@ public final class KcOidcBrokerTransientSessionsTest extends AbstractAdvancedBro
assertThat(userInfoResponse.getUserInfo().getEmail(), is(bc.getUserEmail()));
// Check that tokenIntrospection can be invoked
var introspectionResponse = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken()).asJsonNode();
org.junit.Assert.assertEquals(true, jsonNode.get("active").asBoolean());
org.junit.Assert.assertEquals(bc.getUserEmail(), jsonNode.get("email").asText());
}

View File

@@ -504,13 +504,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
AccessTokenResponse tokenRes = doBackchannelAuthenticationTokenRequest(username, response.getAuthReqId());
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, true);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// revoke by refresh token
EventRepresentation logoutEvent = doTokenRevokeByRefreshToken(tokenRes.getRefreshToken(), tokenRes.getSessionState(), userId, true);
@@ -606,13 +606,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
tokenRes = doBackchannelAuthenticationTokenRequest(username, response.getAuthReqId());
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, false);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// revoke by refresh token
EventRepresentation logoutEvent = doTokenRevokeByRefreshToken(tokenRes.getRefreshToken(), tokenRes.getSessionState(), userId, false);
@@ -670,13 +670,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
tokenRes = doBackchannelAuthenticationTokenRequest(username, response.getAuthReqId());
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, false);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// revoke by refresh token
EventRepresentation logoutEvent = doTokenRevokeByRefreshToken(tokenRes.getRefreshToken(), tokenRes.getSessionState(), userId, false);
@@ -907,13 +907,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
assertTrue(authTime <= currentTime + 5);
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, false);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// logout by refresh token
EventRepresentation logoutEvent = doLogoutByRefreshToken(tokenRes.getRefreshToken(), sessionId, userId, false);
@@ -2556,13 +2556,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
AccessTokenResponse tokenRes = doBackchannelAuthenticationTokenRequest(username, response.getAuthReqId());
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, false);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// logout by refresh token
EventRepresentation logoutEvent = doLogoutByRefreshToken(tokenRes.getRefreshToken(), sessionId, userId, false);
@@ -2785,36 +2785,22 @@ public class CIBATest extends AbstractClientPoliciesTest {
assertThat(idToken.getAudience()[0], is(equalTo(idToken.getIssuedFor())));
}
private String doIntrospectAccessTokenWithClientCredential(AccessTokenResponse tokenRes, String username) throws IOException {
private void doIntrospectAccessTokenWithClientCredential(AccessTokenResponse tokenRes, String username) throws IOException {
AccessToken accessToken = oauth.verifyToken(tokenRes.getAccessToken());
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(tokenRes.getAccessToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
assertThat(jsonNode.get("active").asBoolean(), is(equalTo(true)));
assertThat(jsonNode.get("username").asText(), is(equalTo(username)));
assertThat(jsonNode.get("client_id").asText(), is(equalTo(TEST_CLIENT_NAME)));
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(tokenRes.getAccessToken()).asTokenMetadata();
assertThat(rep.isActive(), is(equalTo(true)));
assertThat(rep.getClientId(), is(equalTo(TEST_CLIENT_NAME)));
assertThat(rep.getIssuedFor(), is(equalTo(TEST_CLIENT_NAME)));
events.expect(EventType.INTROSPECT_TOKEN).user((String) null).session(accessToken.getSessionId()).clearDetails().assertEvent();
tokenResponse = oauth.doIntrospectionAccessTokenRequest(tokenRes.getRefreshToken());
jsonNode = objectMapper.readTree(tokenResponse);
assertThat(jsonNode.get("active").asBoolean(), is(equalTo(true)));
assertThat(jsonNode.get("client_id").asText(), is(equalTo(TEST_CLIENT_NAME)));
rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
rep = oauth.doIntrospectionAccessTokenRequest(tokenRes.getRefreshToken()).asTokenMetadata();
assertThat(rep.isActive(), is(equalTo(true)));
assertThat(rep.getClientId(), is(equalTo(TEST_CLIENT_NAME)));
assertThat(rep.getIssuedFor(), is(equalTo(TEST_CLIENT_NAME)));
assertThat(rep.getAudience()[0], is(equalTo(rep.getIssuer())));
events.expect(EventType.INTROSPECT_TOKEN).user((String) null).session(accessToken.getSessionId()).clearDetails().assertEvent();
tokenResponse = oauth.doIntrospectionAccessTokenRequest(tokenRes.getIdToken());
jsonNode = objectMapper.readTree(tokenResponse);
assertThat(jsonNode.get("active").asBoolean(), is(equalTo(true)));
assertThat(jsonNode.get("client_id").asText(), is(equalTo(TEST_CLIENT_NAME)));
rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
rep = oauth.doIntrospectionAccessTokenRequest(tokenRes.getIdToken()).asTokenMetadata();
assertThat(rep.isActive(), is(equalTo(true)));
assertThat(rep.getUserName(), is(equalTo(username)));
assertThat(rep.getClientId(), is(equalTo(TEST_CLIENT_NAME)));
@@ -2822,8 +2808,6 @@ public class CIBATest extends AbstractClientPoliciesTest {
assertThat(rep.getPreferredUsername(), is(equalTo(username)));
assertThat(rep.getAudience()[0], is(equalTo(rep.getIssuedFor())));
events.expect(EventType.INTROSPECT_TOKEN).user((String) null).session(accessToken.getSessionId()).clearDetails().assertEvent();
return tokenResponse;
}
private AccessTokenResponse doRefreshTokenRequest(String oldRefreshToken, String username, String sessionId, boolean isOfflineAccess) {
@@ -2951,13 +2935,13 @@ public class CIBATest extends AbstractClientPoliciesTest {
assertTrue(authTime <= currentTime + 5);
// token introspection
String tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// token refresh
tokenRes = doRefreshTokenRequest(tokenRes.getRefreshToken(), username, sessionId, isOfflineAccess);
// token introspection after token refresh
tokenResponse = doIntrospectAccessTokenWithClientCredential(tokenRes, username);
doIntrospectAccessTokenWithClientCredential(tokenRes, username);
// logout by refresh token
EventRepresentation logoutEvent = doLogoutByRefreshToken(tokenRes.getRefreshToken(), sessionId, userId, isOfflineAccess);

View File

@@ -248,9 +248,6 @@ public class OAuth2_1PublicClientTest extends AbstractFAPITest {
dpopProofEcEncoded = generateSignedDPoPProof(UUID.randomUUID().toString(), HttpMethod.POST, oauth.getEndpoints().getRevocation(), (long) Time.currentTime(), Algorithm.ES256, jwsEcHeader, ecKeyPair.getPrivate());
oauth.dpopProof(dpopProofEcEncoded);
assertTrue(oauth.doTokenRevoke(response.getAccessToken(), "access_token").isSuccess());
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(response.getAccessToken());
TokenMetadataRepresentation tokenMetadataRepresentation = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
assertFalse(tokenMetadataRepresentation.isActive());
oauth.idTokenHint(response.getIdToken()).openLogout();
}

View File

@@ -418,10 +418,7 @@ public class OIDCPairwiseClientRegistrationTest extends AbstractClientRegistrati
// Login to pairwise client
AccessTokenResponse accessTokenResponse = login(pairwiseClient, "test-user@localhost", "password");
String introspectionResponse = oauth.client(pairwiseClient.getClientId(), pairwiseClient.getClientSecret()).doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.client(pairwiseClient.getClientId(), pairwiseClient.getClientSecret()).doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asJsonNode();
Assert.assertEquals(true, jsonNode.get("active").asBoolean());
Assert.assertEquals("test-user@localhost", jsonNode.get("email").asText());
}

View File

@@ -179,6 +179,7 @@ import org.keycloak.testsuite.util.SignatureSignerUtil;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
import org.keycloak.testsuite.util.ServerURLs;
import org.keycloak.testsuite.util.oauth.IntrospectionResponse;
import org.keycloak.testsuite.util.oauth.LogoutResponse;
import org.keycloak.util.JsonSerialization;
@@ -650,15 +651,11 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
// OAuth2 protocol operation
protected void doIntrospectAccessToken(AccessTokenResponse tokenRes, String username, String clientId, String sessionId, String clientSecret) throws IOException {
String tokenResponse = oauth.client(clientId, clientSecret).doIntrospectionAccessTokenRequest(tokenRes.getAccessToken());
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
assertEquals(true, jsonNode.get("active").asBoolean());
assertEquals(username, jsonNode.get("username").asText());
assertEquals(clientId, jsonNode.get("client_id").asText());
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.client(clientId, clientSecret).doIntrospectionAccessTokenRequest(tokenRes.getAccessToken()).asTokenMetadata();
assertEquals(true, rep.isActive());
assertEquals(clientId, rep.getClientId());
assertEquals(clientId, rep.getIssuedFor());
assertEquals(username, rep.getUserName());
events.expect(EventType.INTROSPECT_TOKEN).client(clientId).session(sessionId).user((String)null).clearDetails().assertEvent();
}
@@ -1332,7 +1329,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
assertEquals(200, accessTokenResponseRefreshed.getStatusCode());
// Check token introspection.
String tokenResponse;
IntrospectionResponse tokenResponse;
try (CloseableHttpClient client = MutualTLSUtils.newCloseableHttpClientWithDefaultKeyStoreAndTrustStore()) {
oauth.client(TEST_CLIENT, TEST_CLIENT_SECRET).httpClient().set(client);
tokenResponse = oauth.doIntrospectionRequest(accessTokenResponse.getAccessToken(), "access_token");
@@ -1342,7 +1339,7 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
oauth.httpClient().reset();
}
Assert.assertNotNull(tokenResponse);
TokenMetadataRepresentation tokenMetadataRepresentation = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation tokenMetadataRepresentation = tokenResponse.asTokenMetadata();
Assert.assertTrue(tokenMetadataRepresentation.isActive());
// Check token revoke.

View File

@@ -335,9 +335,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
private void assertTokenIntrospection(String token, boolean expectActive) {
try {
String tokenResponse = oauth.client("confidential-cli", "secret1").doIntrospectionAccessTokenRequest(token);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
JsonNode jsonNode = oauth.client("confidential-cli", "secret1").doIntrospectionAccessTokenRequest(token).asJsonNode();
assertEquals(expectActive, jsonNode.get("active").asBoolean());
oauth.client("test-app", "password");
} catch (IOException e) {

View File

@@ -451,9 +451,7 @@ public class AccessTokenTest extends AbstractKeycloakTest {
UserInfoClientUtil.testSuccessfulUserInfoResponse(userInfoResponse, "test-user@localhost", "test-user@localhost");
// Check that tokenIntrospection can be invoked
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.doIntrospectionAccessTokenRequest(accessToken).asJsonNode();
Assert.assertEquals(true, jsonNode.get("active").asBoolean());
Assert.assertEquals("test-user@localhost", jsonNode.get("email").asText());
@@ -477,9 +475,7 @@ public class AccessTokenTest extends AbstractKeycloakTest {
userInfoResponse.close();
// Check that tokenIntrospection can't be invoked with invalidated accessToken
introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
objectMapper = new ObjectMapper();
jsonNode = objectMapper.readTree(introspectionResponse);
jsonNode = oauth.doIntrospectionAccessTokenRequest(accessToken).asJsonNode();
Assert.assertEquals(false, jsonNode.get("active").asBoolean());
Assert.assertNull(jsonNode.get("email"));

View File

@@ -65,6 +65,7 @@ import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientPolicyBuilder;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientProfileBuilder;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientProfilesBuilder;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.oauth.IntrospectionResponse;
import org.keycloak.testsuite.util.oauth.UserInfoResponse;
import org.keycloak.testsuite.util.ServerURLs;
import org.keycloak.util.JWKSUtils;
@@ -211,17 +212,14 @@ public class DPoPTest extends AbstractTestRealmKeycloakTest {
// For confidential client, DPoP is not bind to refresh token (See "section 5 DPoP Access Token Request" of DPoP specification)
assertNull(refreshToken.getConfirmation());
String tokenResponse = oauth.doIntrospectionRequest(response.getAccessToken(), "access_token");
Assert.assertNotNull(tokenResponse);
TokenMetadataRepresentation tokenMetadataRepresentation = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation tokenMetadataRepresentation = oauth.doIntrospectionRequest(response.getAccessToken(), "access_token").asTokenMetadata();
Assert.assertTrue(tokenMetadataRepresentation.isActive());
assertEquals(jktRsa, tokenMetadataRepresentation.getConfirmation().getKeyThumbprint());
assertEquals(TokenUtil.TOKEN_TYPE_DPOP, tokenMetadataRepresentation.getOtherClaims().get(OAuth2Constants.TOKEN_TYPE));
oauth.doTokenRevoke(response.getAccessToken(), "access_token", TEST_CONFIDENTIAL_CLIENT_SECRET);
tokenResponse = oauth.doIntrospectionRequest(response.getAccessToken(), "access_token");
Assert.assertNotNull(tokenResponse);
tokenMetadataRepresentation = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
tokenMetadataRepresentation = oauth.doIntrospectionRequest(response.getAccessToken(), "access_token").asTokenMetadata();
Assert.assertFalse(tokenMetadataRepresentation.isActive());
// token refresh
@@ -644,9 +642,9 @@ public class DPoPTest extends AbstractTestRealmKeycloakTest {
dpopProofEcEncoded = generateSignedDPoPProof(UUID.randomUUID().toString(), HttpMethod.POST, oauth.getEndpoints().getRevocation(), (long) Time.currentTime(), Algorithm.ES256, jwsEcHeader, ecKeyPair.getPrivate());
oauth.dpopProof(dpopProofEcEncoded);
assertTrue(oauth.doTokenRevoke(encodedAccessToken, "access_token").isSuccess());
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(encodedAccessToken);
TokenMetadataRepresentation tokenMetadataRepresentation = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
assertFalse(tokenMetadataRepresentation.isActive());
IntrospectionResponse introspectionResponse = oauth.doIntrospectionAccessTokenRequest(encodedAccessToken);
assertFalse(introspectionResponse.isSuccess());
assertEquals("Client not allowed.", introspectionResponse.getErrorDescription());
updatePolicies("{}");
updateProfiles("{}");

View File

@@ -1368,9 +1368,7 @@ public class OfflineTokenTest extends AbstractKeycloakTest {
assertThat(tokenResponse.getRefreshExpiresIn(), allOf(greaterThanOrEqualTo(29), lessThanOrEqualTo(30)));
assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken()).asJsonNode();
Assert.assertEquals(true, jsonNode.get("active").asBoolean());
Assert.assertEquals("test-user@localhost", jsonNode.get("email").asText());
assertThat(jsonNode.get("exp").asInt() - getCurrentTime(),

View File

@@ -938,8 +938,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
Assert.assertFalse(hasClientSessionForTestApp());
// Introspection with the accessToken from the first authentication. This should fail
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(response1.getAccessToken());
JsonNode jsonNode = JsonSerialization.mapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.doIntrospectionAccessTokenRequest(response1.getAccessToken()).asJsonNode();
Assert.assertFalse(jsonNode.get("active").asBoolean());
events.clear();
@@ -960,8 +959,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
Assert.assertTrue(hasClientSessionForTestApp());
// Introspection again with the accessToken from the very first authentication. This should fail as the access token was obtained for the old client session before SSO re-authentication
introspectionResponse = oauth.doIntrospectionAccessTokenRequest(response1.getAccessToken());
jsonNode = JsonSerialization.mapper.readTree(introspectionResponse);
jsonNode = oauth.doIntrospectionAccessTokenRequest(response1.getAccessToken()).asJsonNode();
Assert.assertFalse(jsonNode.get("active").asBoolean());
// Try userInfo with the same old access token. Should fail as well

View File

@@ -444,9 +444,7 @@ public class ServiceAccountTest extends AbstractKeycloakTest {
}
private boolean getIntrospectionResponse(String tokenString) throws IOException {
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(tokenString);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
JsonNode jsonNode = oauth.doIntrospectionAccessTokenRequest(tokenString).asJsonNode();
return jsonNode.get("active").asBoolean();
}

View File

@@ -57,6 +57,7 @@ import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.KeycloakModelUtils;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.TokenSignatureUtil;
import org.keycloak.testsuite.util.oauth.IntrospectionResponse;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.TokenUtil;
@@ -151,9 +152,8 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
String code = oauth.parseLoginResponse().getCode();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
IntrospectionResponse introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
JsonNode jsonNode = introspectionResponse.asJsonNode();
assertTrue(jsonNode.get("active").asBoolean());
assertEquals("test-user@localhost", jsonNode.get("username").asText());
@@ -166,7 +166,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
assertTrue(jsonNode.has("iss"));
assertTrue(jsonNode.has("jti"));
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = introspectionResponse.asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -193,11 +193,10 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
String code = oauth.parseLoginResponse().getCode();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("confidential-cli", "bad_credential");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
IntrospectionResponse tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
Assert.assertEquals("Authentication failed.", errorRep.getErrorDescription());
Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
Assert.assertEquals("Authentication failed.", tokenResponse.getErrorDescription());
Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, tokenResponse.getError());
}
@Test
@@ -208,11 +207,8 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
String sessionId = loginEvent.getSessionId();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionRefreshTokenRequest(accessTokenResponse.getRefreshToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
JsonNode jsonNode = oauth.doIntrospectionRefreshTokenRequest(accessTokenResponse.getRefreshToken()).asJsonNode();
assertTrue(jsonNode.get("active").asBoolean());
assertEquals(sessionId, jsonNode.get("sid").asText());
assertEquals("test-app", jsonNode.get("client_id").asText());
assertTrue(jsonNode.has("exp"));
@@ -223,18 +219,6 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
assertTrue(jsonNode.has("iss"));
assertTrue(jsonNode.has("jti"));
assertTrue(jsonNode.has("typ"));
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
assertTrue(rep.isActive());
assertEquals("test-app", rep.getClientId());
assertEquals(jsonNode.get("sid").asText(), rep.getSessionState());
assertEquals(Long.valueOf(jsonNode.get("exp").asLong()), rep.getExp());
assertEquals(Long.valueOf(jsonNode.get("iat").asLong()), rep.getIat());
assertEquals(Optional.ofNullable(jsonNode.get("nbf")).map(JsonNode::asLong).orElse(null), rep.getNbf());
assertEquals(jsonNode.get("iss").asText(), rep.getIssuer());
assertEquals(jsonNode.get("jti").asText(), rep.getId());
assertEquals(jsonNode.get("typ").asText(), "Refresh");
}
@Test
@@ -258,15 +242,10 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
oauth.client("confidential-cli", "secret1");
String introspectResponse = oauth.doIntrospectionRefreshTokenRequest(tokenResponse2.getRefreshToken());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(introspectResponse);
JsonNode jsonNode = oauth.doIntrospectionRefreshTokenRequest(tokenResponse2.getRefreshToken()).asJsonNode();
assertTrue(jsonNode.get("active").asBoolean());
introspectResponse = oauth.doIntrospectionRefreshTokenRequest(refreshToken1);
jsonNode = objectMapper.readTree(introspectResponse);
jsonNode = oauth.doIntrospectionRefreshTokenRequest(refreshToken1).asJsonNode();
assertFalse(jsonNode.get("active").asBoolean());
}
@@ -277,11 +256,10 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
String code = oauth.parseLoginResponse().getCode();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("public-cli");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
IntrospectionResponse tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
Assert.assertEquals("Client not allowed.", errorRep.getErrorDescription());
Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
Assert.assertEquals("Client not allowed.", tokenResponse.getErrorDescription());
Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, tokenResponse.getError());
}
@Test
@@ -289,13 +267,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
oauth.doLogin("test-user@localhost", "password");
String inactiveAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGSjg2R2NGM2pUYk5MT2NvNE52WmtVQ0lVbWZZQ3FvcXRPUWVNZmJoTmxFIn0.eyJqdGkiOiI5NjgxZTRlOC01NzhlLTQ3M2ItOTIwNC0yZWE5OTdhYzMwMTgiLCJleHAiOjE0NzYxMDY4NDksIm5iZiI6MCwiaWF0IjoxNDc2MTA2NTQ5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvdGVzdCIsImF1ZCI6InRlc3QtYXBwIiwic3ViIjoiZWYyYzk0NjAtZDRkYy00OTk5LWJlYmUtZWVmYWVkNmJmMGU3IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdC1hcHAiLCJhdXRoX3RpbWUiOjE0NzYxMDY1NDksInNlc3Npb25fc3RhdGUiOiI1OGY4M2MzMi03MDhkLTQzNjktODhhNC05YjI5OGRjMDY5NzgiLCJhY3IiOiIxIiwiY2xpZW50X3Nlc3Npb24iOiI2NTYyOTVkZC1kZWNkLTQyZDAtYWJmYy0zZGJjZjJlMDE3NzIiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo4MTgwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1c2VyIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsidGVzdC1hcHAiOnsicm9sZXMiOlsiY3VzdG9tZXItdXNlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJUb20gQnJhZHkiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0LXVzZXJAbG9jYWxob3N0IiwiZ2l2ZW5fbmFtZSI6IlRvbSIsImZhbWlseV9uYW1lIjoiQnJhZHkiLCJlbWFpbCI6InRlc3QtdXNlckBsb2NhbGhvc3QifQ.LYU7opqZsc9e-ZmdsIhcecjHL3kQkpP13VpwO4MHMqEVNeJsZI1WOkTM5HGVAihcPfQazhaYvcik0gFTF_6ZcKzDqanjx80TGhSIrV5FoCeUrbp7w_66VKDH7ImPc8T2kICQGHh2d521WFBnvXNifw7P6AR1rGg4qrUljHdf_KU";
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(inactiveAccessToken);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
assertFalse(jsonNode.get("active").asBoolean());
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(inactiveAccessToken).asTokenMetadata();
assertFalse(rep.isActive());
assertNull(rep.getUserName());
@@ -308,13 +280,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
oauth.doLogin("test-user@localhost", "password");
String inactiveAccessToken = "unsupported";
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(inactiveAccessToken);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
assertFalse(jsonNode.get("active").asBoolean());
TokenMetadataRepresentation rep = objectMapper.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(inactiveAccessToken).asTokenMetadata();
assertFalse(rep.isActive());
assertNull(rep.getUserName());
@@ -329,8 +295,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
EventRepresentation loginEvent = events.expectLogin().assertEvent();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -353,8 +318,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
EventRepresentation loginEvent = events.expectLogin().client("no-scope").assertEvent();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("no-scope", "password");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -373,12 +337,11 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
EventRepresentation loginEvent = events.expectLogin().assertEvent();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
String tokenResponse = oauth.introspectionRequest(accessTokenResponse.getAccessToken())
TokenMetadataRepresentation rep = oauth.introspectionRequest(accessTokenResponse.getAccessToken())
.tokenTypeHint("access_token")
.client("confidential-cli", "secret1")
.jwtResponse()
.send();
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
.send().asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -412,9 +375,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
assertEquals(jwaAlgorithm, new JWSInput(accessTokenResponse.getAccessToken()).getHeader().getAlgorithm().name());
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -437,8 +398,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
oauth.doLogout(accessTokenResponse.getRefreshToken(), "password");
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertFalse(rep.isActive());
assertNull(rep.getUserName());
@@ -459,8 +419,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
// "Online" session still exists, but is invalid
accessTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -472,8 +431,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
oauth.client("test-app", "password");
accessTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
oauth.client("confidential-cli", "secret1");
tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -490,8 +448,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
setTimeOffset(1200);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionRefreshTokenRequest(accessTokenResponse.getRefreshToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionRefreshTokenRequest(accessTokenResponse.getRefreshToken()).asTokenMetadata();
assertTrue(rep.isActive());
assertEquals("test-user@localhost", rep.getUserName());
@@ -520,8 +477,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
adminClient.realm(oauth.getRealm()).users().get(loginEvent.getUserId()).update(userRep);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertFalse(rep.isActive());
assertNull(rep.getUserName());
@@ -541,8 +497,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
setTimeOffset(adminClient.realm(oauth.getRealm()).toRepresentation().getAccessTokenLifespan() + 1);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken()).asTokenMetadata();
assertFalse(rep.isActive());
assertNull(rep.getUserName());
@@ -555,17 +510,15 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
* Test covers the same scenario from different endpoints like TokenEndpoint and LogoutEndpoint.
*/
@Test
public void testIntrospectWithSamlClient() throws Exception {
public void testIntrospectWithSamlClient() {
oauth.doLogin("test-user@localhost", "password");
String code = oauth.parseLoginResponse().getCode();
events.expectLogin().assertEvent();
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code);
oauth.client("saml-client", "secret2");
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
IntrospectionResponse introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenResponse.getAccessToken());
assertEquals(Errors.INVALID_CLIENT, rep.getOtherClaims().get("error"));
assertNull(rep.getSubject());
assertEquals(Errors.INVALID_CLIENT, introspectionResponse.getError());
}
private AccessTokenResponse loginAndForceNewLoginPage() {
@@ -651,17 +604,14 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
accessTokenResponse = oauth.doRefreshTokenRequest(oldRefreshToken);
String newRefreshToken = accessTokenResponse.getRefreshToken();
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionRefreshTokenRequest(newRefreshToken);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(tokenResponse);
JsonNode jsonNode = oauth.doIntrospectionRefreshTokenRequest(newRefreshToken).asJsonNode();
assertTrue(jsonNode.get("active").asBoolean());
oauth.client("test-app", "password");
accessTokenResponse = oauth.doRefreshTokenRequest(newRefreshToken);
oauth.client("confidential-cli", "secret1");
tokenResponse = oauth.doIntrospectionRefreshTokenRequest(oldRefreshToken);
jsonNode = objectMapper.readTree(tokenResponse);
jsonNode = oauth.doIntrospectionRefreshTokenRequest(oldRefreshToken).asJsonNode();
assertFalse(jsonNode.get("active").asBoolean());
} finally {
realm.setRevokeRefreshToken(false);
@@ -703,8 +653,6 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
accessTokenResponse = oauth.doRefreshTokenRequest(stringRefreshToken);
oauth.client("confidential-cli", "secret1");
String tokenResponse = oauth.doIntrospectionRefreshTokenRequest(stringRefreshToken);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readTree(tokenResponse);
return oauth.doIntrospectionRefreshTokenRequest(stringRefreshToken).asJsonNode();
}
}

View File

@@ -17,25 +17,23 @@
package org.keycloak.testsuite.oauth;
import static org.junit.Assert.*;
import static org.keycloak.testsuite.admin.AbstractAdminTest.*;
import java.io.IOException;
import java.util.List;
import jakarta.ws.rs.core.Response.Status;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.hamcrest.MatcherAssert;
import org.junit.Test;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.oidc.TokenMetadataRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.Matchers;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.oauth.TokenRevocationResponse;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
/**
* @author <a href="mailto:yoshiyuki.tabata.jy@hitachi.com">Yoshiyuki Tabata</a>
@@ -49,7 +47,7 @@ public class TokenRevocationCorsTest extends AbstractKeycloakTest {
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
realm.getClients().add(ClientBuilder.create().redirectUris(VALID_CORS_URL + "/realms/master/app")
.addWebOrigin(VALID_CORS_URL).clientId("test-app2").publicClient().directAccessGrants().build());
.addWebOrigin(VALID_CORS_URL).clientId("test-app2").secret("password").directAccessGrants().build());
testRealms.add(realm);
}
@@ -98,8 +96,7 @@ public class TokenRevocationCorsTest extends AbstractKeycloakTest {
}
private void isTokenDisabled(AccessTokenResponse tokenResponse) throws IOException {
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken()).asTokenMetadata();
assertFalse(rep.isActive());
AccessTokenResponse tokenRefreshResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken());

View File

@@ -344,8 +344,7 @@ public class TokenRevocationTest extends AbstractKeycloakTest {
private void isTokenEnabled(AccessTokenResponse tokenResponse, String clientId) throws IOException {
oauth.client(clientId, "password");
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken());
TokenMetadataRepresentation rep = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(tokenResponse.getAccessToken()).asTokenMetadata();
assertTrue(rep.isActive());
AccessTokenResponse tokenRefreshResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken());
@@ -363,8 +362,7 @@ public class TokenRevocationTest extends AbstractKeycloakTest {
private void isAccessTokenDisabled(String accessTokenString, String clientId) throws IOException {
// Test introspection endpoint not possible
oauth.client(clientId, "password");
String introspectionResponse = oauth.doIntrospectionAccessTokenRequest(accessTokenString);
TokenMetadataRepresentation rep = JsonSerialization.readValue(introspectionResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.doIntrospectionAccessTokenRequest(accessTokenString).asTokenMetadata();
assertFalse(rep.isActive());
// Test userInfo endpoint not possible

View File

@@ -663,16 +663,15 @@ public class HoKTest extends AbstractTestRealmKeycloakTest {
// Do token introspection
// mimic Resource Server
String tokenResponse;
TokenMetadataRepresentation rep;
try (CloseableHttpClient client = MutualTLSUtils.newCloseableHttpClientWithoutKeyStoreAndTrustStore()) {
oauth.client("confidential-cli", "secret1").httpClient().set(client);
tokenResponse = oauth.doIntrospectionRequest(accessTokenResponse.getAccessToken(), "access_token");
rep = oauth.doIntrospectionRequest(accessTokenResponse.getAccessToken(), "access_token").asTokenMetadata();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} finally {
oauth.httpClient().reset();
}
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
JWSInput jws = new JWSInput(accessTokenResponse.getAccessToken());
AccessToken at = jws.readJsonContent(AccessToken.class);
jws = new JWSInput(accessTokenResponse.getRefreshToken());

View File

@@ -256,7 +256,7 @@ public abstract class AbstractSubjectImpersonationTokenExchangeTest extends Abst
org.junit.Assert.assertEquals(200, response.getStatus());
AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
String exchangedTokenString = accessTokenResponse.getToken();
JsonNode json = JsonSerialization.readValue(oauth.doIntrospectionAccessTokenRequest(exchangedTokenString), com.fasterxml.jackson.databind.JsonNode.class);
JsonNode json = oauth.doIntrospectionAccessTokenRequest(exchangedTokenString).asJsonNode();
assertTrue(json.get("active").asBoolean());
assertEquals("impersonated-user", json.get("preferred_username").asText());
assertEquals("user", json.get("act").get("sub").asText());
@@ -276,7 +276,7 @@ public abstract class AbstractSubjectImpersonationTokenExchangeTest extends Abst
org.junit.Assert.assertEquals(200, response.getStatus());
AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
String exchangedTokenString = accessTokenResponse.getToken();
JsonNode json = JsonSerialization.readValue(oauth.doIntrospectionAccessTokenRequest(exchangedTokenString), com.fasterxml.jackson.databind.JsonNode.class);
JsonNode json = oauth.doIntrospectionAccessTokenRequest(exchangedTokenString).asJsonNode();
assertTrue(json.get("active").asBoolean());
assertEquals("impersonated-user", json.get("preferred_username").asText());
assertEquals("user", json.get("act").get("sub").asText());

View File

@@ -1016,15 +1016,13 @@ public class StandardTokenExchangeV2Test extends AbstractClientPoliciesTest {
}
private void assertIntrospectSuccess(String token, String clientId, String clientSecret, String userId) throws IOException {
String tokenResponse = oauth.client(clientId, clientSecret).introspectionRequest(token).tokenTypeHint("access_token").send();
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.client(clientId, clientSecret).introspectionRequest(token).tokenTypeHint("access_token").send().asTokenMetadata();
assertTrue(rep.isActive());
assertEquals(userId, rep.getSubject());
}
private void assertIntrospectError(String token, String clientId, String clientSecret) throws IOException {
String tokenResponse = oauth.client(clientId, clientSecret).introspectionRequest(token).tokenTypeHint("access_token").send();
TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
TokenMetadataRepresentation rep = oauth.client(clientId, clientSecret).introspectionRequest(token).tokenTypeHint("access_token").send().asTokenMetadata();
assertFalse(rep.isActive());
}

View File

@@ -158,7 +158,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, false, false);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
} finally {
@@ -179,7 +179,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, true, false);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
// Most of the claims should not be included in introspectionResponse as introspectionMapper was disabled
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, false, false);
@@ -201,7 +201,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, true, false);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
} finally {
@@ -223,7 +223,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.introspectionRequest(accessToken).tokenTypeHint("access_token").jwtResponse().send();
String tokenResponse = oauth.introspectionRequest(accessToken).tokenTypeHint("access_token").jwtResponse().send().getRaw();
logger.debug("tokenResponse:" + tokenResponse);
AccessToken introspectionResult = JsonSerialization.readValue(tokenResponse, AccessToken.class);
assertTokenIntrospectionResponse(introspectionResult, true, true, false);
@@ -251,7 +251,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
removeSession(ctx.userSessionId);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
} finally {
@@ -273,7 +273,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), false, false, false);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), false, true, false);
} finally {
@@ -299,7 +299,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
logger.debug("exchangedTokenString:" + exchangedTokenString);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(exchangedTokenString);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(exchangedTokenString).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
} finally {
@@ -324,7 +324,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
logger.debug("lightweight access token:" + accessToken);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
logger.debug("tokenResponse:" + introspectResponse);
@@ -365,7 +365,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
Assert.assertEquals(ctx.getGrantType(), OAuth2Constants.AUTHORIZATION_CODE);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + introspectResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
@@ -391,7 +391,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
logger.debug("lightweight access token:" + accessToken);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
logger.debug("tokenResponse:" + introspectResponse);
@@ -426,7 +426,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, true, true);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + introspectResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
@@ -452,7 +452,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, false,true);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + introspectResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, true);
@@ -468,7 +468,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), true, true, true);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
introspectResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + introspectResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, true);
@@ -492,7 +492,7 @@ public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
assertAccessToken(oauth.verifyToken(accessToken), false, false,false);
oauth.client(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken);
String tokenResponse = oauth.doIntrospectionAccessTokenRequest(accessToken).getRaw();
logger.debug("tokenResponse:" + tokenResponse);
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), false, true, false);
} finally {

View File

@@ -49,6 +49,8 @@ import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
import org.keycloak.util.TokenUtil;
import java.io.IOException;
/**
*
* @author rmartinc
@@ -63,12 +65,12 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
}
@Test
public void testNonceWithoutMapper() throws JsonProcessingException {
public void testNonceWithoutMapper() throws IOException {
testNonce(false, false);
}
@Test
public void testNonceWithMapper() throws JsonProcessingException {
public void testNonceWithMapper() throws IOException {
ClientResource testApp = ApiUtil.findClientByClientId(testRealm(), "test-app");
String mapperId = createNonceMapper(testApp);
try {
@@ -79,7 +81,7 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
}
@Test
public void testOfflineSessionNonceWithMapper() throws JsonProcessingException {
public void testOfflineSessionNonceWithMapper() throws IOException {
ClientResource testApp = ApiUtil.findClientByClientId(testRealm(), "test-app");
String mapperId = createNonceMapper(testApp);
try {
@@ -128,13 +130,12 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
}
}
private void testIntrospection(String accessToken, String expectedNonce, boolean expected) throws JsonProcessingException {
String tokenResponse = oauth.client("test-app", "password").doIntrospectionAccessTokenRequest(accessToken);
JsonNode nonce = new ObjectMapper().readTree(tokenResponse).get(OIDCLoginProtocol.NONCE_PARAM);
private void testIntrospection(String accessToken, String expectedNonce, boolean expected) throws IOException {
JsonNode nonce = oauth.client("test-app", "password").doIntrospectionAccessTokenRequest(accessToken).asJsonNode().get(OIDCLoginProtocol.NONCE_PARAM);
checkNonce(expectedNonce, nonce != null? nonce.asText() : null, expected);
}
private void testNonceImplicit(boolean mapper) throws JsonProcessingException {
private void testNonceImplicit(boolean mapper) throws IOException {
String nonce = KeycloakModelUtils.generateId();
oauth.nonce(nonce);
oauth.responseMode(OIDCResponseMode.JWT.value());
@@ -155,7 +156,7 @@ public class NonceBackwardsCompatibleMapperTest extends AbstractTestRealmKeycloa
testIntrospection(idTokenString, nonce, true);
}
private void testNonce(boolean mapper, boolean offlineSession) throws JsonProcessingException {
private void testNonce(boolean mapper, boolean offlineSession) throws IOException {
String nonce = KeycloakModelUtils.generateId();
oauth.nonce(nonce);
if (offlineSession) {