Added custom base URL set via factory (not automatically working cross environments) [#27234]
Better tests for exchange-token features
This commit is contained in:
parent
35c913db02
commit
726291ca55
|
@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||
|
||||
## [v2.1.0-SNAPSHOT]
|
||||
- Added `token-exchange` support, also with `offline-token` scope, and methods to add extra headers during the OIDC token requests.
|
||||
- Added custom base URL set via factory (not automatically working cross environments) [#27234].
|
||||
|
||||
## [v2.0.0]
|
||||
- Removed the discovery functionality to be compatible with SmartGears.v4 and moved to the new library `keycloak-client-legacy-is` that will provide the backward compatibility. (#23478).
|
||||
|
|
|
@ -52,7 +52,21 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
|
||||
protected final static String AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
public static final String BASE_URL = "https://url.d4science.org/auth/realms/";
|
||||
public static final String DEFAULT_BASE_URL = "https://url.d4science.org/auth/realms/";
|
||||
|
||||
private String customBaseURL = null;
|
||||
|
||||
public void setCustomBaseURL(String customBaseURL) {
|
||||
if (customBaseURL == null || customBaseURL.endsWith("/")) {
|
||||
this.customBaseURL = customBaseURL;
|
||||
} else {
|
||||
this.customBaseURL = customBaseURL += "/";
|
||||
}
|
||||
}
|
||||
|
||||
public String getCustomBaseURL() {
|
||||
return customBaseURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getRealmBaseURL(String context) throws KeycloakClientException {
|
||||
|
@ -61,16 +75,20 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
|
||||
@Override
|
||||
public URL getRealmBaseURL(String context, String realm) throws KeycloakClientException {
|
||||
String urlString = BASE_URL + realm + "/";
|
||||
if (!context.startsWith(PROD_ROOT_SCOPE)) {
|
||||
String root = checkContext(context).split("/")[1];
|
||||
urlString = urlString.replace("url", "url." + root.replaceAll("\\.", "-"));
|
||||
String realmBaseURLString = null;
|
||||
if (getCustomBaseURL() != null) {
|
||||
realmBaseURLString = getCustomBaseURL() + realm + "/";
|
||||
} else {
|
||||
realmBaseURLString = DEFAULT_BASE_URL + realm + "/";
|
||||
if (!context.startsWith(PROD_ROOT_SCOPE)) {
|
||||
String root = checkContext(context).split("/")[1];
|
||||
realmBaseURLString = realmBaseURLString.replace("url", "url." + root.replaceAll("\\.", "-"));
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new URL(urlString);
|
||||
return new URL(realmBaseURLString);
|
||||
} catch (MalformedURLException e) {
|
||||
// That should be almost impossible
|
||||
logger.warn("Cannot create base URL from string: {}", urlString, e);
|
||||
logger.error("Cannot create base URL from string: {}", realmBaseURLString, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +210,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
String username, String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
|
||||
username, password, null, extraHeaders);
|
||||
username, password, audience, extraHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,9 +7,32 @@ public class KeycloakClientFactory {
|
|||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(KeycloakClientFactory.class);
|
||||
|
||||
protected static String CUSTOM_BASE_URL;
|
||||
|
||||
public static void setCustomBaseURL(String customBaseURL) {
|
||||
if (customBaseURL != null) {
|
||||
logger.info("Setting custom base URL static value to {}", customBaseURL);
|
||||
} else {
|
||||
logger.info("Removing custom base URL static value");
|
||||
}
|
||||
if (customBaseURL == null || customBaseURL.endsWith("/")) {
|
||||
CUSTOM_BASE_URL = customBaseURL;
|
||||
} else {
|
||||
CUSTOM_BASE_URL = customBaseURL += "/";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCustomBaseURL() {
|
||||
return CUSTOM_BASE_URL;
|
||||
}
|
||||
|
||||
public static KeycloakClient newInstance() {
|
||||
logger.debug("Instantiating a new keycloak client instance");
|
||||
return new DefaultKeycloakClient();
|
||||
DefaultKeycloakClient newInstance = new DefaultKeycloakClient();
|
||||
if (getCustomBaseURL() != null) {
|
||||
newInstance.setCustomBaseURL(CUSTOM_BASE_URL);
|
||||
}
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,8 @@ public class TestKeycloakClient {
|
|||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
// Assure to reset the factory's default base URL
|
||||
KeycloakClientFactory.setCustomBaseURL(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -105,6 +107,23 @@ public class TestKeycloakClient {
|
|||
Assert.assertEquals(devAvatarURL.toString(), avatarURL.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test04CustomEndpointTest() throws Exception {
|
||||
String customBase = "https://accounts.cloud.dev.d4science.org/auth/realms/";
|
||||
logger.info("*** [0.4] Start testing Keycloak token endpoint construction from custom base URL {}...",
|
||||
customBase);
|
||||
|
||||
KeycloakClientFactory.setCustomBaseURL(customBase);
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL customBaseURL = client.getRealmBaseURL(DEV_ROOT_CONTEXT);
|
||||
logger.info("*** [0.4] Constructed token URL is: {}", customBaseURL);
|
||||
URL devTokenURL = new URL(DEV_TOKEN_ENDPOINT);
|
||||
logger.info("*** [0.4] DEV token URL is: {}", devTokenURL);
|
||||
Assert.assertNotNull(customBaseURL);
|
||||
Assert.assertEquals(customBaseURL.getProtocol(), "https");
|
||||
Assert.assertEquals(customBase + KeycloakClient.DEFAULT_REALM + "/", customBaseURL.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test12QueryOIDCToken() throws Exception {
|
||||
logger.info("*** [1.2] Start testing query OIDC token from Keycloak with context...");
|
||||
|
@ -145,13 +164,28 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test13aQueryOIDCTokenOfUserWithContext() throws Exception {
|
||||
logger.info("*** [1.3a] Start testing query OIDC token for audience from Keycloak with context for user...");
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TEST_AUDIENCE);
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD);
|
||||
|
||||
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);
|
||||
|
||||
TokenResponse oidcRestrictedTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(
|
||||
DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD,
|
||||
TOKEN_RESTRICTION_VRE_CONTEXT);
|
||||
|
||||
logger.info("*** [1.3a] OIDC restricted access token: {}", oidcRestrictedTR.getAccessToken());
|
||||
logger.info("*** [1.3a] OIDC restricted refresh token: {}", oidcRestrictedTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(oidcTR);
|
||||
TestModels.checkTokenResponse(oidcRestrictedTR);
|
||||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
|
||||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcRestrictedTR), TEST_USER_USERNAME, true);
|
||||
assertTrue(ModelUtils.getAccessTokenFrom(oidcTR).getAudience().length > 1);
|
||||
assertTrue(ModelUtils.getAccessTokenFrom(oidcRestrictedTR).getAudience().length == 1);
|
||||
assertTrue(
|
||||
TOKEN_RESTRICTION_VRE_CONTEXT.equals(ModelUtils.getAccessTokenFrom(oidcRestrictedTR).getAudience()[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -178,28 +212,18 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test13aQueryOIDCTokenOfUserWithContextAndCustomHeader() throws Exception {
|
||||
logger.info(
|
||||
"*** [1.3c] Start testing query OIDC token for audience from Keycloak with context and custom header for user...");
|
||||
"*** [1.3c] Start testing query OIDC token for audience from Keycloak with context and custom headers for user...");
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TOKEN_RESTRICTION_VRE_CONTEXT);
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TOKEN_RESTRICTION_VRE_CONTEXT,
|
||||
Collections.singletonMap("X_A_CUSTOM_HEADER", "HEADER_VALUE"));
|
||||
|
||||
logger.info("*** [1.3c] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
logger.info("*** [1.3c] OIDC refresh token: {}", oidcTR.getRefreshToken());
|
||||
|
||||
TokenResponse oidcRestrictedTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(
|
||||
DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TOKEN_RESTRICTION_VRE_CONTEXT,
|
||||
Collections.singletonMap(KeycloakClient.D4S_CONTEXT_HEADER_NAME, TOKEN_RESTRICTION_VRE_CONTEXT));
|
||||
|
||||
logger.info("*** [1.3c] OIDC restricted access token: {}", oidcRestrictedTR.getAccessToken());
|
||||
logger.info("*** [1.3c] OIDC restricted refresh token: {}", oidcRestrictedTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(oidcTR);
|
||||
TestModels.checkTokenResponse(oidcRestrictedTR);
|
||||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
|
||||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcRestrictedTR), TEST_USER_USERNAME, true);
|
||||
assertTrue(ModelUtils.getAccessTokenFrom(oidcTR).getAudience().length > 1);
|
||||
assertTrue(ModelUtils.getAccessTokenFrom(oidcRestrictedTR).getAudience().length == 1);
|
||||
assertTrue(
|
||||
TOKEN_RESTRICTION_VRE_CONTEXT.equals(ModelUtils.getAccessTokenFrom(oidcRestrictedTR).getAudience()[0]));
|
||||
assertTrue(ModelUtils.getAccessTokenFrom(oidcTR).getAudience().length == 1);
|
||||
// It is not possible to check programmatically if the header has been added to the call, See the logs if the Header is present.
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -443,27 +467,28 @@ public class TestKeycloakClient {
|
|||
client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, exchangedTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test53ExchangeToken4Offline() throws Exception {
|
||||
logger.info("*** [5.3] Start testing token exchange for offline token from Keycloak...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse oidcTR = client.queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME,
|
||||
TEST_USER_PASSWORD);
|
||||
|
||||
logger.info("*** [5.3] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
TokenResponse exchangedTR = client.exchangeTokenForOfflineToken(DEV_ROOT_CONTEXT, oidcTR, CLIENT_ID,
|
||||
CLIENT_SECRET, CLIENT_ID);
|
||||
|
||||
logger.info("*** [5.3] Exchanged access token: {}", exchangedTR.getAccessToken());
|
||||
logger.info("*** [5.3] Exchanged refresh token: {}", exchangedTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(exchangedTR, true);
|
||||
TestModels.checkOfflineToken(exchangedTR);
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, exchangedTR.getAccessToken()));
|
||||
|
||||
}
|
||||
@Test
|
||||
public void test53ExchangeToken4Offline() throws Exception {
|
||||
logger.info("*** [5.3] Start testing token exchange for offline token from Keycloak...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse oidcTR = client.queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
|
||||
TEST_USER_USERNAME,
|
||||
TEST_USER_PASSWORD);
|
||||
|
||||
logger.info("*** [5.3] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
TokenResponse exchangedTR = client.exchangeTokenForOfflineToken(DEV_ROOT_CONTEXT, oidcTR, CLIENT_ID,
|
||||
CLIENT_SECRET, CLIENT_ID);
|
||||
|
||||
logger.info("*** [5.3] Exchanged access token: {}", exchangedTR.getAccessToken());
|
||||
logger.info("*** [5.3] Exchanged refresh token: {}", exchangedTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(exchangedTR, true);
|
||||
TestModels.checkOfflineToken(exchangedTR);
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, exchangedTR.getAccessToken()));
|
||||
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void test6GetAvatar() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue