|
|
|
@ -1,6 +1,25 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright 2023 Red Hat, Inc. and/or its affiliates
|
|
|
|
|
* and other contributors as indicated by the @author tags.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package org.keycloak.testsuite.oidc;
|
|
|
|
|
|
|
|
|
|
import jakarta.ws.rs.NotFoundException;
|
|
|
|
|
import org.jboss.logging.Logger;
|
|
|
|
|
import org.junit.Assert;
|
|
|
|
|
import org.junit.Before;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
import org.keycloak.admin.client.resource.ClientScopeResource;
|
|
|
|
@ -23,15 +42,17 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
|
|
|
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
|
|
|
|
import org.keycloak.representations.idm.RealmRepresentation;
|
|
|
|
|
import org.keycloak.representations.idm.UserRepresentation;
|
|
|
|
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
|
|
|
|
import org.keycloak.services.clientpolicy.condition.AnyClientConditionFactory;
|
|
|
|
|
import org.keycloak.services.clientpolicy.executor.UseLightweightAccessTokenExecutorFactory;
|
|
|
|
|
import org.keycloak.testsuite.admin.ApiUtil;
|
|
|
|
|
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
|
|
|
|
import org.keycloak.testsuite.client.policies.AbstractClientPoliciesTest;
|
|
|
|
|
import org.keycloak.testsuite.util.ClientManager;
|
|
|
|
|
import org.keycloak.testsuite.util.ClientPoliciesUtil;
|
|
|
|
|
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
|
|
|
|
import org.keycloak.testsuite.util.OAuthClient;
|
|
|
|
|
import org.keycloak.testsuite.util.ProtocolMapperUtil;
|
|
|
|
|
import org.keycloak.util.JsonSerialization;
|
|
|
|
|
import org.wildfly.common.Assert;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
@ -62,25 +83,29 @@ import static org.keycloak.protocol.oidc.mappers.AudienceProtocolMapper.INCLUDED
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.HardcodedClaim.CLAIM_VALUE;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.PairwiseSubMapperHelper.PAIRWISE_SUB_ALGORITHM_SALT;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.NEW_ROLE_NAME;
|
|
|
|
|
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.ROLE_CONFIG;
|
|
|
|
|
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
|
|
|
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
|
|
|
|
import static org.keycloak.testsuite.util.ClientPoliciesUtil.createAnyClientConditionConfig;
|
|
|
|
|
|
|
|
|
|
@EnableFeature(value = Profile.Feature.TOKEN_EXCHANGE, skipRestart = true)
|
|
|
|
|
public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
|
|
|
|
|
public class LightWeightAccessTokenTest extends AbstractClientPoliciesTest {
|
|
|
|
|
private static final Logger logger = Logger.getLogger(LightWeightAccessTokenTest.class);
|
|
|
|
|
private static String RESOURCE_SERVER_CLIENT_ID = "resource-server";
|
|
|
|
|
private static String RESOURCE_SERVER_CLIENT_PASSWORD = "password";
|
|
|
|
|
@Before
|
|
|
|
|
public void clientConfiguration() {
|
|
|
|
|
ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true).setServiceAccountsEnabled(true);
|
|
|
|
|
ClientManager.realm(adminClient.realm("test")).clientId("resource-server").directAccessGrant(true);
|
|
|
|
|
ClientManager.realm(adminClient.realm(REALM_NAME)).clientId(TEST_CLIENT).directAccessGrant(true).setServiceAccountsEnabled(true);
|
|
|
|
|
ClientManager.realm(adminClient.realm(REALM_NAME)).clientId(RESOURCE_SERVER_CLIENT_ID).directAccessGrant(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
|
|
|
|
RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
|
|
|
|
|
UserRepresentation user = findUser(realm, "test-user@localhost");
|
|
|
|
|
UserRepresentation user = findUser(realm, TEST_USER_NAME);
|
|
|
|
|
Map<String, List<String>> attributes = new HashMap<>(){{
|
|
|
|
|
put("street", Arrays.asList("1 My Street"));
|
|
|
|
|
put("locality", Arrays.asList("Cardiff"));
|
|
|
|
@ -89,8 +114,8 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
}};
|
|
|
|
|
user.setAttributes(attributes);
|
|
|
|
|
user.setGroups(Arrays.asList("/topGroup/level2group"));
|
|
|
|
|
ClientRepresentation confApp = KeycloakModelUtils.createClient(realm, "resource-server");
|
|
|
|
|
confApp.setSecret("password");
|
|
|
|
|
ClientRepresentation confApp = KeycloakModelUtils.createClient(realm, RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
confApp.setSecret(RESOURCE_SERVER_CLIENT_PASSWORD);
|
|
|
|
|
confApp.setServiceAccountsEnabled(Boolean.TRUE);
|
|
|
|
|
testRealms.add(realm);
|
|
|
|
|
}
|
|
|
|
@ -99,7 +124,6 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
for (UserRepresentation user : testRealm.getUsers()) {
|
|
|
|
|
if (user.getUsername().equals(userName)) return user;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -109,15 +133,15 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
try {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin(TEST_CLIENT_SECRET, TEST_USER_NAME, TEST_USER_PASSWORD).tokenResponse;
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
logger.debug("tokenResponse:" + tokenResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
@ -130,15 +154,15 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
try {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin(TEST_CLIENT_SECRET, TEST_USER_NAME, TEST_USER_PASSWORD).tokenResponse;
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
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);
|
|
|
|
|
} finally {
|
|
|
|
@ -152,15 +176,15 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
try {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin(TEST_CLIENT_SECRET, TEST_USER_NAME, TEST_USER_PASSWORD).tokenResponse;
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
logger.debug("tokenResponse:" + tokenResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
@ -174,33 +198,24 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("openid address offline_access");
|
|
|
|
|
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
TokenResponseContext ctx = browserLogin("password", "test-user@localhost", "password");
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
TokenResponseContext ctx = browserLogin(TEST_CLIENT_SECRET, TEST_USER_NAME, TEST_USER_PASSWORD);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = ctx.tokenResponse;
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
System.out.println("idtoken:" + response.getIdToken());
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("idtoken:" + response.getIdToken());
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
removeSession(ctx.userSessionId);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
logger.debug("tokenResponse:" + tokenResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void removeSession(final String sessionId) {
|
|
|
|
|
testingClient.testing().removeExpired("test");
|
|
|
|
|
try {
|
|
|
|
|
testingClient.testing().removeUserSession("test", sessionId);
|
|
|
|
|
} catch (NotFoundException nfe) {
|
|
|
|
|
// Ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void clientCredentialTest() throws Exception {
|
|
|
|
|
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, false);
|
|
|
|
@ -208,15 +223,15 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("password");
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest(TEST_CLIENT_SECRET);
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), false, false);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
logger.debug("tokenResponse:" + tokenResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), false);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
@ -230,24 +245,94 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
|
|
|
|
|
oauth.clientId("test-app");
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
OAuthClient.AccessTokenResponse response = browserLogin(TEST_CLIENT_SECRET, TEST_USER_NAME, TEST_USER_PASSWORD).tokenResponse;
|
|
|
|
|
String accessToken = response.getAccessToken();
|
|
|
|
|
System.out.println("accessToken:" + accessToken);
|
|
|
|
|
logger.debug("accessToken:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
|
|
|
|
response = oauth.doTokenExchange(TEST, accessToken, null, "test-app", "password");
|
|
|
|
|
response = oauth.doTokenExchange(TEST, accessToken, null, TEST_CLIENT, TEST_CLIENT_SECRET);
|
|
|
|
|
String exchangedTokenString = response.getAccessToken();
|
|
|
|
|
System.out.println("exchangedTokenString:" + exchangedTokenString);
|
|
|
|
|
logger.debug("exchangedTokenString:" + exchangedTokenString);
|
|
|
|
|
|
|
|
|
|
oauth.clientId("resource-server");
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", exchangedTokenString);
|
|
|
|
|
System.out.println("tokenResponse:" + tokenResponse);
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String tokenResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, exchangedTokenString);
|
|
|
|
|
logger.debug("tokenResponse:" + tokenResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, true);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testPolicyLightWeightFalseTest() throws Exception {
|
|
|
|
|
setUseLightweightAccessTokenExecutor();
|
|
|
|
|
ProtocolMappersResource protocolMappers = setProtocolMappers(true, true, false, true);
|
|
|
|
|
try {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
|
|
|
|
|
OAuthClient.AuthorizationEndpointResponse authsEndpointResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
|
|
|
|
|
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(authsEndpointResponse.getCode(), TEST_CLIENT_SECRET);
|
|
|
|
|
String accessToken = tokenResponse.getAccessToken();
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
|
|
|
|
logger.debug("lightweight access token:" + accessToken);
|
|
|
|
|
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String introspectResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
|
|
|
|
|
logger.debug("tokenResponse:" + introspectResponse);
|
|
|
|
|
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
deletePolicy(POLICY_NAME);
|
|
|
|
|
oauth.doLogout(tokenResponse.getRefreshToken(), TEST_CLIENT_SECRET);
|
|
|
|
|
|
|
|
|
|
authsEndpointResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
|
|
|
|
|
tokenResponse = oauth.doAccessTokenRequest(authsEndpointResponse.getCode(), TEST_CLIENT_SECRET);
|
|
|
|
|
accessToken = tokenResponse.getAccessToken();
|
|
|
|
|
logger.debug("access token:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testPolicyLightWeightTrueTest() throws Exception {
|
|
|
|
|
setUseLightweightAccessTokenExecutor();
|
|
|
|
|
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, true, true);
|
|
|
|
|
try {
|
|
|
|
|
oauth.nonce("123456");
|
|
|
|
|
oauth.scope("address");
|
|
|
|
|
|
|
|
|
|
oauth.clientId(TEST_CLIENT);
|
|
|
|
|
|
|
|
|
|
OAuthClient.AuthorizationEndpointResponse authsEndpointResponse = oauth.doLogin(TEST_USER_NAME, TEST_USER_PASSWORD);
|
|
|
|
|
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(authsEndpointResponse.getCode(), TEST_CLIENT_SECRET);
|
|
|
|
|
String accessToken = tokenResponse.getAccessToken();
|
|
|
|
|
logger.debug("access token:" + accessToken);
|
|
|
|
|
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
|
|
|
|
|
|
|
|
|
oauth.clientId(RESOURCE_SERVER_CLIENT_ID);
|
|
|
|
|
String introspectResponse = oauth.introspectAccessTokenWithClientCredential(RESOURCE_SERVER_CLIENT_ID, RESOURCE_SERVER_CLIENT_PASSWORD, accessToken);
|
|
|
|
|
logger.debug("tokenResponse:" + introspectResponse);
|
|
|
|
|
assertTokenIntrospectionResponse(JsonSerialization.readValue(introspectResponse, AccessToken.class), true, true, false);
|
|
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
deleteProtocolMappers(protocolMappers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void removeSession(final String sessionId) {
|
|
|
|
|
testingClient.testing().removeExpired(REALM_NAME);
|
|
|
|
|
try {
|
|
|
|
|
testingClient.testing().removeUserSession(REALM_NAME, sessionId);
|
|
|
|
|
} catch (NotFoundException nfe) {
|
|
|
|
|
// Ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void assertMapperClaims(AccessToken token, boolean isAddMapperResponseFlag, boolean isAuthCodeFlow) {
|
|
|
|
|
if (isAddMapperResponseFlag) {
|
|
|
|
|
if (isAuthCodeFlow) {
|
|
|
|
@ -269,21 +354,21 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
Assert.assertNotNull(token.getPreferredUsername());
|
|
|
|
|
} else {
|
|
|
|
|
if (isAuthCodeFlow) {
|
|
|
|
|
Assert.assertTrue(token.getName() == null);
|
|
|
|
|
Assert.assertTrue(token.getGivenName() == null);
|
|
|
|
|
Assert.assertTrue(token.getFamilyName() == null);
|
|
|
|
|
Assert.assertTrue(token.getAddress() == null);
|
|
|
|
|
Assert.assertTrue(token.getEmail() == null);
|
|
|
|
|
Assert.assertTrue(token.getOtherClaims().get("user-session-note") == null);
|
|
|
|
|
Assert.assertTrue(token.getOtherClaims().get("test-claim") == null);
|
|
|
|
|
Assert.assertTrue(token.getOtherClaims().get("group-name") == null);
|
|
|
|
|
Assert.assertNull(token.getName());
|
|
|
|
|
Assert.assertNull(token.getGivenName());
|
|
|
|
|
Assert.assertNull(token.getFamilyName());
|
|
|
|
|
Assert.assertNull(token.getAddress());
|
|
|
|
|
Assert.assertNull(token.getEmail());
|
|
|
|
|
Assert.assertNull(token.getOtherClaims().get("user-session-note"));
|
|
|
|
|
Assert.assertNull(token.getOtherClaims().get("test-claim"));
|
|
|
|
|
Assert.assertNull(token.getOtherClaims().get("group-name"));
|
|
|
|
|
}
|
|
|
|
|
Assert.assertTrue(token.getAcr() == null);
|
|
|
|
|
Assert.assertTrue(token.getAllowedOrigins() == null);
|
|
|
|
|
Assert.assertTrue(token.getRealmAccess() == null);
|
|
|
|
|
Assert.assertNull(token.getAcr());
|
|
|
|
|
Assert.assertNull(token.getAllowedOrigins());
|
|
|
|
|
Assert.assertNull(token.getRealmAccess());
|
|
|
|
|
Assert.assertTrue(token.getResourceAccess().isEmpty());
|
|
|
|
|
Assert.assertTrue(token.getEmailVerified() == null);
|
|
|
|
|
Assert.assertTrue(token.getPreferredUsername() == null);
|
|
|
|
|
Assert.assertNull(token.getEmailVerified());
|
|
|
|
|
Assert.assertNull(token.getPreferredUsername());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -296,12 +381,13 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
Assert.assertNotNull(token.getSessionId());
|
|
|
|
|
Assert.assertNotNull(token.getAuth_time());
|
|
|
|
|
} else {
|
|
|
|
|
Assert.assertTrue(token.getSessionId() == null);
|
|
|
|
|
Assert.assertTrue(token.getAuth_time() == null);
|
|
|
|
|
Assert.assertNull(token.getSessionId());
|
|
|
|
|
Assert.assertNull(token.getAuth_time());
|
|
|
|
|
}
|
|
|
|
|
Assert.assertNotNull(token.getIssuedFor());
|
|
|
|
|
Assert.assertNotNull(token.getScope());
|
|
|
|
|
Assert.assertNotNull(token.getIssuer());
|
|
|
|
|
Assert.assertNotNull(token.getSubject());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void assertIntrospectClaims(AccessToken token) {
|
|
|
|
@ -314,7 +400,7 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
if (isAuthCodeFlow && !exchangeToken) {
|
|
|
|
|
Assert.assertNotNull(token.getNonce());
|
|
|
|
|
} else {
|
|
|
|
|
Assert.assertTrue(token.getNonce() == null);
|
|
|
|
|
Assert.assertNull(token.getNonce());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -336,25 +422,25 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RealmResource testRealm() {
|
|
|
|
|
return adminClient.realm("test");
|
|
|
|
|
return adminClient.realm(REALM_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setScopeProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection) {
|
|
|
|
|
setScopeProtocolMapper(ACR_SCOPE, ACR, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, FULL_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(EMAIL, EMAIL, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(EMAIL, EMAIL_VERIFIED, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, GIVEN_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, FAMILY_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, USERNAME, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(WEB_ORIGINS_SCOPE, ALLOWED_WEB_ORIGINS, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, REALM_ROLES, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, CLIENT_ROLES, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, AUDIENCE_RESOLVE, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMapper(ADDRESS, ADDRESS, isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
private void setScopeProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean isIncludeLightweightAccessToken) {
|
|
|
|
|
setScopeProtocolMapper(ACR_SCOPE, ACR, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, FULL_NAME, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(EMAIL, EMAIL, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(EMAIL, EMAIL_VERIFIED, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, GIVEN_NAME, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, FAMILY_NAME, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(PROFILE_CLAIM, USERNAME, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(WEB_ORIGINS_SCOPE, ALLOWED_WEB_ORIGINS, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, REALM_ROLES, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, CLIENT_ROLES, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(ROLES_SCOPE, AUDIENCE_RESOLVE, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
setScopeProtocolMapper(ADDRESS, ADDRESS, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setScopeProtocolMapper(String scopeName, String mapperName, boolean isIncludeAccessToken, boolean isIncludeIntrospection) {
|
|
|
|
|
private void setScopeProtocolMapper(String scopeName, String mapperName, boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean isIncludeLightweightAccessToken) {
|
|
|
|
|
ClientScopeResource scope = ApiUtil.findClientScopeByName(testRealm(), scopeName);
|
|
|
|
|
ProtocolMapperRepresentation protocolMapper = ApiUtil.findProtocolMapperByName(scope, mapperName);
|
|
|
|
|
Map<String, String> config = protocolMapper.getConfig();
|
|
|
|
@ -368,31 +454,49 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
} else {
|
|
|
|
|
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
|
|
|
|
}
|
|
|
|
|
if (isIncludeLightweightAccessToken) {
|
|
|
|
|
config.put(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN, "true");
|
|
|
|
|
} else {
|
|
|
|
|
config.put(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN, "false");
|
|
|
|
|
}
|
|
|
|
|
scope.getProtocolMappers().update(protocolMapper.getId(), protocolMapper);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ProtocolMappersResource setProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean setPairWise) {
|
|
|
|
|
setScopeProtocolMappers(isIncludeAccessToken, isIncludeIntrospection);
|
|
|
|
|
setScopeProtocolMappers(isIncludeAccessToken, isIncludeIntrospection, false);
|
|
|
|
|
List<ProtocolMapperRepresentation> protocolMapperList = new ArrayList<>();
|
|
|
|
|
setExistingProtocolMappers(protocolMapperList, isIncludeAccessToken, isIncludeIntrospection, setPairWise);
|
|
|
|
|
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
|
|
|
|
setExistingProtocolMappers(protocolMapperList, isIncludeAccessToken, isIncludeIntrospection, false, setPairWise);
|
|
|
|
|
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm(REALM_NAME), TEST_CLIENT).getProtocolMappers();
|
|
|
|
|
protocolMappers.createMapper(protocolMapperList);
|
|
|
|
|
return protocolMappers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setExistingProtocolMappers(List<ProtocolMapperRepresentation> protocolMapperList, boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean setPairWise) {
|
|
|
|
|
private ProtocolMappersResource setProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean isIncludeLightweightAccessToken, boolean setPairWise) {
|
|
|
|
|
setScopeProtocolMappers(isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken);
|
|
|
|
|
List<ProtocolMapperRepresentation> protocolMapperList = new ArrayList<>();
|
|
|
|
|
setExistingProtocolMappers(protocolMapperList, isIncludeAccessToken, isIncludeIntrospection, isIncludeLightweightAccessToken, setPairWise);
|
|
|
|
|
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm(REALM_NAME), TEST_CLIENT).getProtocolMappers();
|
|
|
|
|
protocolMappers.createMapper(protocolMapperList);
|
|
|
|
|
return protocolMappers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setExistingProtocolMappers(List<ProtocolMapperRepresentation> protocolMapperList, boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean isIncludeLightweightAccessToken, boolean setPairWise) {
|
|
|
|
|
Map<String, String> config = new HashMap<>();
|
|
|
|
|
if (isIncludeAccessToken) {
|
|
|
|
|
config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
|
|
|
|
} else {
|
|
|
|
|
config.put(INCLUDE_IN_ACCESS_TOKEN, "false");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isIncludeIntrospection) {
|
|
|
|
|
config.put(INCLUDE_IN_INTROSPECTION, "true");
|
|
|
|
|
} else {
|
|
|
|
|
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
|
|
|
|
}
|
|
|
|
|
if (isIncludeLightweightAccessToken) {
|
|
|
|
|
config.put(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN, "true");
|
|
|
|
|
} else {
|
|
|
|
|
config.put(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN, "false");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProtocolMapperRepresentation audienceProtocolMapper = createClaimMapper("audience", AudienceProtocolMapper.PROVIDER_ID, new HashMap<>(config) {{
|
|
|
|
|
put(INCLUDED_CLIENT_AUDIENCE, "account-console");
|
|
|
|
@ -469,4 +573,24 @@ public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
|
|
|
|
this.tokenResponse = tokenResponse;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setUseLightweightAccessTokenExecutor() throws Exception {
|
|
|
|
|
// register profiles
|
|
|
|
|
String json = (new ClientPoliciesUtil.ClientProfilesBuilder()).addProfile(
|
|
|
|
|
(new ClientPoliciesUtil.ClientProfileBuilder()).createProfile(PROFILE_NAME, "Use Lightweight Access Token")
|
|
|
|
|
.addExecutor(UseLightweightAccessTokenExecutorFactory.PROVIDER_ID, null)
|
|
|
|
|
.toRepresentation()
|
|
|
|
|
).toString();
|
|
|
|
|
updateProfiles(json);
|
|
|
|
|
|
|
|
|
|
// register policies
|
|
|
|
|
json = (new ClientPoliciesUtil.ClientPoliciesBuilder()).addPolicy(
|
|
|
|
|
(new ClientPoliciesUtil.ClientPolicyBuilder()).createPolicy(POLICY_NAME, "Use Lightweight Access Token Policy", Boolean.TRUE)
|
|
|
|
|
.addCondition(AnyClientConditionFactory.PROVIDER_ID,
|
|
|
|
|
createAnyClientConditionConfig())
|
|
|
|
|
.addProfile(PROFILE_NAME)
|
|
|
|
|
.toRepresentation()
|
|
|
|
|
).toString();
|
|
|
|
|
updatePolicies(json);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|