Added new `KeycloakClientHelper` class to perform token request for user in one shot and without the need to provide the `clientId` parameter (#25291). Only `context`, `username` and `password` are required.

This commit is contained in:
Mauro Mugnaini 2023-07-13 13:09:33 +02:00
parent 89c5cf04bd
commit 52d70eda60
2 changed files with 89 additions and 9 deletions

View File

@ -0,0 +1,48 @@
package org.gcube.common.keycloak;
import org.gcube.common.keycloak.model.AccessToken;
import org.gcube.common.keycloak.model.RefreshToken;
import org.gcube.common.keycloak.model.TokenResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KeycloakClientHelper {
protected static Logger logger = LoggerFactory.getLogger(KeycloakClientHelper.class);
/**
* The public GW used to obtain the token, is not declared final since it can be changed if necessary at runtime
*/
private static String GATEWAY_CLIENT_ID = "d4science-internal-gateway";
/**
* Sets the new default GW <code>clientId</code> used for all the queries to the Keycloak server.
* Note: The operation will logged as WARN to be visible.
* @param gatewayClientId the new GW <code>clientId</code>
*/
public static void setDefaultGWClientID(String gatewayClientId) {
logger.warn("The default GW clientId will be changed to: {}", gatewayClientId);
GATEWAY_CLIENT_ID = gatewayClientId;
}
/**
* Gets a new {@link TokenResponse}, containing the {@link AccessToken} and the {@link RefreshToken} from the Keycloak server in the environment of the context represented by the <code>context</code> parameter.
* The <code>context</code> parameter is also used as audience for the token.
*
* @param context the context ot be used for discovery and for audience
* @param username the user's username
* @param password the user's password
* @return the token response from the Keycloak server
* @throws KeycloakClientException if an error occurs during the process
*/
public static TokenResponse getTokenForUser(String context, String username, String password) throws KeycloakClientException {
logger.debug("Getting new token for user '{}' in context '{}'", username, context);
logger.trace("Getting OIDC token for user '{}' using configured default GW clientId '{}'", username, GATEWAY_CLIENT_ID);
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(context, GATEWAY_CLIENT_ID,
"", username, password);
logger.trace("Getting UMA token in the '{}' context", context);
return KeycloakClientFactory.newInstance().queryUMAToken(context, oidcTR, context, null);
}
}

View File

@ -47,7 +47,7 @@ public class TestKeycloakClient {
@Test
public void test00TokenEndpointConstruction() throws Exception {
logger.info("*** [0.0] Start testing Keycloak token endpoint construction from base URL...");
logger.info("*** [0.0] Start testing Keycloak token endpoint construction from base URL computed from context...");
KeycloakClient client = KeycloakClientFactory.newInstance();
tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
Assert.assertNotNull(tokenURL);
@ -69,7 +69,7 @@ public class TestKeycloakClient {
@Test
public void test02IntrospectEndpointCompute() throws Exception {
logger.info("*** [0.2] Start testing Keycloak userinfo endpoint computed from provided URL...");
logger.info("*** [0.2] Start testing Keycloak userinfo endpoint computed from provided URL string...");
KeycloakClient client = KeycloakClientFactory.newInstance();
URL url = client
.computeIntrospectionEndpointURL(client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT)));
@ -83,7 +83,7 @@ public class TestKeycloakClient {
@Test
public void test12QueryOIDCToken() throws Exception {
logger.info("*** [1.2] Start testing query OIDC token from Keycloak with URL...");
logger.info("*** [1.2] Start testing query OIDC token from Keycloak with context...");
oidcTR = KeycloakClientFactory.newInstance().queryOIDCToken(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET);
@ -107,7 +107,7 @@ public class TestKeycloakClient {
@Test
public void test13QueryOIDCTokenOfUser() throws Exception {
logger.info("*** [1.3] Start testing query OIDC token from Keycloak with URL for user...");
logger.info("*** [1.3] Start testing query OIDC token from Keycloak with context for user...");
oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD);
@ -119,19 +119,39 @@ public class TestKeycloakClient {
@Test
public void test13aQueryOIDCTokenOfUserWithContext() throws Exception {
logger.info("*** [1.3] Start testing query OIDC token from Keycloak with URL for user...");
logger.info("*** [1.3a] Start testing query OIDC token for audience from Keycloak with context for user...");
oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TEST_AUDIENCE);
logger.info("*** [1.3] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.3] OIDC refresh token: {}", oidcTR.getRefreshToken());
logger.info("*** [1.3a] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.3a] OIDC refresh token: {}", oidcTR.getRefreshToken());
TestModels.checkTokenResponse(oidcTR);
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
}
@Test
public void test13bQueryOIDCTokenAndUMAOfUser() throws Exception {
logger.info("*** [1.3b] Start testing query OIDC and UMA tokens from Keycloak with context for user...");
oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD);
logger.info("*** [1.3b] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.3b] OIDC refresh token: {}", oidcTR.getRefreshToken());
TestModels.checkTokenResponse(oidcTR);
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, false);
umaTR = KeycloakClientFactory.newInstance().queryUMAToken(DEV_ROOT_CONTEXT, oidcTR, TEST_AUDIENCE, null);
logger.info("*** [1.3b] UMA access token: {}", umaTR.getAccessToken());
logger.info("*** [1.3b] UMA refresh token: {}", umaTR.getRefreshToken());
TestModels.checkTokenResponse(umaTR);
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), TEST_USER_USERNAME, true);
}
@Test
public void test24QueryUMAToken() throws Exception {
logger.info("*** [2.4] Start testing query UMA token from Keycloak with URL...");
logger.info("*** [2.4] Start testing query UMA token from Keycloak with context...");
umaTR = KeycloakClientFactory.newInstance().queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
TEST_AUDIENCE, null);
@ -144,7 +164,7 @@ public class TestKeycloakClient {
@Test
public void test24aQueryUMAToken() throws Exception {
logger.info("*** [2.4a] Start testing query UMA token from Keycloak with URL...");
logger.info("*** [2.4a] Start testing query UMA token from Keycloak with context...");
umaTR = KeycloakClientFactory.newInstance().queryUMAToken(tokenURL, CLIENT_ID, CLIENT_SECRET,
TEST_AUDIENCE, null);
@ -246,4 +266,16 @@ public class TestKeycloakClient {
Assert.assertFalse(KeycloakClientFactory.newInstance().isAccessTokenVerified(
introspectionURL, CLIENT_ID, CLIENT_SECRET, OLD_UMA_ACCESS_TOKEN));
}
@Test
public void test4GetTokenOfUser() throws Exception {
logger.info("*** [4] Start testing query token from Keycloak for user...");
TokenResponse tokenResponse = KeycloakClientHelper.getTokenForUser(DEV_ROOT_CONTEXT, TEST_USER_USERNAME, TEST_USER_PASSWORD);
logger.info("*** [4] UMA access token: {}", tokenResponse.getAccessToken());
logger.info("*** [4] UMA refresh token: {}", tokenResponse.getRefreshToken());
TestModels.checkTokenResponse(tokenResponse);
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(tokenResponse), TEST_USER_USERNAME, true);
}
}