Added `token-exchange` support, also with `offline-token` scope, and methods to add extra headers during the OIDC token requests.
This commit is contained in:
parent
86c3887e76
commit
35c913db02
|
@ -2,6 +2,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||
|
||||
# Changelog for "keycloak-client"
|
||||
|
||||
## [v2.1.0-SNAPSHOT]
|
||||
- Added `token-exchange` support, also with `offline-token` scope, and methods to add extra headers during the OIDC token requests.
|
||||
|
||||
## [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).
|
||||
- Fixed typo in `AccessToken` class for `setAccessToken(..)` method (#23654)
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -13,7 +13,7 @@
|
|||
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>keycloak-client</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.1.0-SNAPSHOT</version>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
package org.gcube.common.keycloak;
|
||||
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.ACCESS_TOKEN_TOKEN_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.AUDIENCE_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.CLIENT_CREDENTIALS_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.CLIENT_ID_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.CLIENT_SECRET_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.GRANT_TYPE_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.OFFLINE_ACCESS_SCOPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.PASSWORD_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.PASSWORD_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.PERMISSION_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.REFRESH_TOKEN_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.REFRESH_TOKEN_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.REFRESH_TOKEN_TOKEN_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.REQUESTED_TOKEN_TYPE_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.SCOPE_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.SUBJECT_TOKEN_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.SUBJECT_TOKEN_TYPE_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.TOKEN_EXCHANGE_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.TOKEN_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.UMA_TOKEN_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.PASSWORD_GRANT_TYPE;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.USERNAME_PARAMETER;
|
||||
import static org.gcube.common.keycloak.model.OIDCConstants.PASSWORD_PARAMETER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
@ -20,6 +28,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
@ -42,7 +51,6 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
protected static Logger logger = LoggerFactory.getLogger(KeycloakClient.class);
|
||||
|
||||
protected final static String AUTHORIZATION_HEADER = "Authorization";
|
||||
protected final static String D4S_CONTEXT_HEADER_NAME = "X-D4Science-Context";
|
||||
|
||||
public static final String BASE_URL = "https://url.d4science.org/auth/realms/";
|
||||
|
||||
|
@ -55,7 +63,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
public URL getRealmBaseURL(String context, String realm) throws KeycloakClientException {
|
||||
String urlString = BASE_URL + realm + "/";
|
||||
if (!context.startsWith(PROD_ROOT_SCOPE)) {
|
||||
String root = context.split("/")[1];
|
||||
String root = checkContext(context).split("/")[1];
|
||||
urlString = urlString.replace("url", "url." + root.replaceAll("\\.", "-"));
|
||||
}
|
||||
try {
|
||||
|
@ -67,6 +75,18 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
}
|
||||
}
|
||||
|
||||
private static String checkContext(String context) {
|
||||
if (!context.startsWith("/")) {
|
||||
try {
|
||||
logger.trace("Context was provided in URL encoded form, decoding it");
|
||||
return URLDecoder.decode(context, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.error("Cannot URL decode 'context'", e);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getTokenEndpointURL(URL realmBaseURL) throws KeycloakClientException {
|
||||
logger.debug("Constructing token endpoint URL starting from base URL: {}", realmBaseURL);
|
||||
|
@ -80,7 +100,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
logger.debug("Constructed token URL is: {}", tokenURL);
|
||||
return tokenURL;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new KeycloakClientException("Cannot constructs toke URL from base URL: " + realmBaseURL, e);
|
||||
throw new KeycloakClientException("Cannot constructs token URL from base URL: " + realmBaseURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +119,24 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
logger.debug("Constructed introspection URL is: {}", tokenURL);
|
||||
return tokenURL;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new KeycloakClientException("Cannot constructs toke URL from base URL: " + realmBaseURL, e);
|
||||
throw new KeycloakClientException("Cannot constructs introspection URL from base URL: " + realmBaseURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getAvatarEndpointURL(URL realmBaseURL) throws KeycloakClientException {
|
||||
logger.debug("Constructing token endpoint URL starting from base URL: {}", realmBaseURL);
|
||||
try {
|
||||
URL tokenURL = null;
|
||||
if (realmBaseURL.getPath().endsWith("/")) {
|
||||
tokenURL = new URL(realmBaseURL, AVATAR_URI_PATH);
|
||||
} else {
|
||||
tokenURL = new URL(realmBaseURL.toString() + "/" + AVATAR_URI_PATH);
|
||||
}
|
||||
logger.debug("Constructed avatar URL is: {}", tokenURL);
|
||||
return tokenURL;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new KeycloakClientException("Cannot constructs avatar URL from base URL: " + realmBaseURL, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,15 +177,22 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
public TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
|
||||
String password) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(context, clientId, clientSecret, username, password, null);
|
||||
return queryOIDCTokenOfUserWithContext(context, clientId, clientSecret, username, password, (String) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
|
||||
String username, String password, String audience) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(context, clientId, clientSecret, username, password, audience, (Map<String, String>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
|
||||
String username, String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
|
||||
username, password, null);
|
||||
username, password, null, extraHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -166,7 +210,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
audience);
|
||||
}
|
||||
|
||||
protected String constructBasicAuthenticationHeader(String clientId, String clientSecret) {
|
||||
protected static String constructBasicAuthenticationHeader(String clientId, String clientSecret) {
|
||||
return "Basic " + Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes());
|
||||
}
|
||||
|
||||
|
@ -178,6 +222,14 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
password, audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String authorization, String username,
|
||||
String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(getTokenEndpointURL(getRealmBaseURL(context)), authorization, username,
|
||||
password, audience, extraHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCToken(String context, String authorization) throws KeycloakClientException {
|
||||
return queryOIDCTokenWithContext(context, authorization, null);
|
||||
|
@ -193,14 +245,28 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret,
|
||||
String username, String password, String audience) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(tokenURL, clientId, clientSecret, username, password, audience, (Map<String, String>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret,
|
||||
String username, String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(tokenURL, constructBasicAuthenticationHeader(clientId, clientSecret),
|
||||
username, password, audience);
|
||||
username, password, audience, extraHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username,
|
||||
String password, String audience) throws KeycloakClientException {
|
||||
|
||||
return queryOIDCTokenOfUserWithContext(tokenURL, authorization, username, password, audience, (Map<String, String>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username,
|
||||
String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException {
|
||||
|
||||
Map<String, List<String>> params = new HashMap<>();
|
||||
params.put(GRANT_TYPE_PARAMETER, Arrays.asList(PASSWORD_GRANT_TYPE));
|
||||
params.put(USERNAME_PARAMETER, Arrays.asList(username));
|
||||
|
@ -209,6 +275,10 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
Map<String, String> headers = new HashMap<>();
|
||||
logger.debug("Adding authorization header as: {}", authorization);
|
||||
headers.put(AUTHORIZATION_HEADER, authorization);
|
||||
if (extraHeaders != null) {
|
||||
logger.debug("Adding provided extra headers: {}", extraHeaders);
|
||||
headers.putAll(extraHeaders);
|
||||
}
|
||||
|
||||
if (audience != null) {
|
||||
logger.debug("Adding d4s context header as: {}", audience);
|
||||
|
@ -257,7 +327,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
return queryUMAToken(tokenURL, constructBeareAuthenticationHeader(oidcTokenResponse), audience, permissions);
|
||||
}
|
||||
|
||||
protected String constructBeareAuthenticationHeader(TokenResponse oidcTokenResponse) {
|
||||
protected static String constructBeareAuthenticationHeader(TokenResponse oidcTokenResponse) {
|
||||
return "Bearer " + oidcTokenResponse.getAccessToken();
|
||||
}
|
||||
|
||||
|
@ -331,9 +401,6 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
throw new KeycloakClientException("Token URL must be not null");
|
||||
}
|
||||
|
||||
if (!headers.containsKey(AUTHORIZATION_HEADER) || "".equals(headers.get(AUTHORIZATION_HEADER))) {
|
||||
throw new KeycloakClientException("Authorization must be not null nor empty");
|
||||
}
|
||||
// Constructing request object
|
||||
GXHTTPStringRequest request;
|
||||
try {
|
||||
|
@ -341,7 +408,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
.flatMap(p -> p.getValue().stream().map(v -> p.getKey() + "=" + v))
|
||||
.reduce((p1, p2) -> p1 + "&" + p2).orElse("");
|
||||
|
||||
logger.trace("Query string is {}", queryString);
|
||||
logger.trace("Query string is: {}", queryString);
|
||||
|
||||
request = GXHTTPStringRequest.newRequest(tokenURL.toString())
|
||||
.header("Content-Type", "application/x-www-form-urlencoded").withBody(queryString);
|
||||
|
@ -359,6 +426,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
GXInboundResponse response;
|
||||
try {
|
||||
response = request.post();
|
||||
// TODO: Fill a bug ticket for the gxJRS lib for JSON responses in case of not 2XX code (e.g. 403 error with JSON details in this case).
|
||||
} catch (Exception e) {
|
||||
throw new KeycloakClientException("Cannot send request correctly", e);
|
||||
}
|
||||
|
@ -428,8 +496,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
|
||||
@Override
|
||||
public TokenResponse refreshToken(String context, String clientId, String clientSecret,
|
||||
String refreshTokenJWTString)
|
||||
throws KeycloakClientException {
|
||||
String refreshTokenJWTString) throws KeycloakClientException {
|
||||
|
||||
return refreshToken(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
|
||||
refreshTokenJWTString);
|
||||
|
@ -496,6 +563,98 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForAccessToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeTokenForAccessToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
|
||||
clientSecret, audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForAccessToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
|
||||
ACCESS_TOKEN_TOKEN_TYPE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForRefreshToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeTokenForRefreshToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
|
||||
clientSecret, audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForRefreshToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
|
||||
REFRESH_TOKEN_TOKEN_TYPE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForOfflineToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeTokenForOfflineToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
|
||||
clientSecret, audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeTokenForOfflineToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException {
|
||||
|
||||
return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
|
||||
REFRESH_TOKEN_TOKEN_TYPE, OFFLINE_ACCESS_SCOPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse exchangeToken(URL tokenURL, String oidcAccessToken, String clientId, String clientSecret,
|
||||
String audience, String requestedTokenType, String scope) throws KeycloakClientException {
|
||||
|
||||
if (audience == null || "".equals(audience)) {
|
||||
throw new KeycloakClientException("Audience must be not null nor empty");
|
||||
}
|
||||
|
||||
logger.debug("Exchanging token from Keycloak server with URL: {}", tokenURL);
|
||||
|
||||
Map<String, List<String>> params = new HashMap<>();
|
||||
params.put(SUBJECT_TOKEN_PARAMETER, Arrays.asList(oidcAccessToken));
|
||||
params.put(CLIENT_ID_PARAMETER, Arrays.asList(clientId));
|
||||
params.put(CLIENT_SECRET_PARAMETER, Arrays.asList(clientSecret));
|
||||
params.put(GRANT_TYPE_PARAMETER, Arrays.asList(TOKEN_EXCHANGE_GRANT_TYPE));
|
||||
params.put(SUBJECT_TOKEN_TYPE_PARAMETER, Arrays.asList(ACCESS_TOKEN_TOKEN_TYPE));
|
||||
params.put(REQUESTED_TOKEN_TYPE_PARAMETER, Arrays.asList(requestedTokenType));
|
||||
if (scope != null) {
|
||||
params.put(SCOPE_PARAMETER, Arrays.asList(scope));
|
||||
}
|
||||
|
||||
try {
|
||||
String audienceToSend = URLEncoder.encode(checkAudience(audience), "UTF-8");
|
||||
params.put(AUDIENCE_PARAMETER, Arrays.asList(audienceToSend));
|
||||
logger.trace("audience is {}", audienceToSend);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.error("Can't URL encode audience: {}", audience, e);
|
||||
}
|
||||
|
||||
return performRequest(tokenURL, Collections.emptyMap(), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries from the OIDC server an exchanged token by using provided access token, for the given audience (context),
|
||||
* in URLEncoded form or not, and optionally a list of permissions.
|
||||
*
|
||||
* @param tokenUrl the token endpoint {@link URL} of the OIDC server
|
||||
* @param authorization the auth token (the access token URLEncoded by the "Bearer " string)
|
||||
* @param audience the audience (context) where to request the issuing of the ticket (URLEncoded)
|
||||
* @param permissions a list of permissions, can be <code>null</code>
|
||||
* @return the issued token
|
||||
* @throws OpenIdConnectRESTHelperException if an error occurs (also an unauthorized call), inspect the exception for details
|
||||
*/
|
||||
|
||||
@Override
|
||||
public TokenIntrospectionResponse introspectAccessToken(String context, String clientId, String clientSecret,
|
||||
String accessTokenJWTString) throws KeycloakClientException {
|
||||
|
@ -590,4 +749,46 @@ public class DefaultKeycloakClient implements KeycloakClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAvatarData(String context, TokenResponse tokenResponse) throws KeycloakClientException {
|
||||
return getAvatarData(getAvatarEndpointURL(getRealmBaseURL(context)), tokenResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getAvatarData(URL avatarURL, TokenResponse tokenResponse) throws KeycloakClientException {
|
||||
logger.debug("Getting user's avatar from URL: {}", avatarURL);
|
||||
try {
|
||||
GXHTTPStringRequest request;
|
||||
try {
|
||||
request = GXHTTPStringRequest.newRequest(avatarURL.toString());
|
||||
|
||||
safeSetAsExternalCallForOldAPI(request);
|
||||
|
||||
String authorization = constructBeareAuthenticationHeader(tokenResponse);
|
||||
logger.debug("Adding authorization header as: {}", authorization);
|
||||
request = request.header("Authorization", authorization);
|
||||
request = request.header("Accept", "image/png, image/gif");
|
||||
} catch (Exception e) {
|
||||
throw new KeycloakClientException("Cannot construct the request object correctly", e);
|
||||
}
|
||||
|
||||
GXInboundResponse response;
|
||||
try {
|
||||
response = request.get();
|
||||
} catch (Exception e) {
|
||||
throw new KeycloakClientException("Cannot send request correctly", e);
|
||||
}
|
||||
if (response.isSuccessResponse()) {
|
||||
return response.getStreamedContent();
|
||||
} else {
|
||||
throw KeycloakClientException.create("Unable to get avatar image data", response.getHTTPCode(),
|
||||
response.getHeaderFields()
|
||||
.getOrDefault("content-type", Collections.singletonList("unknown/unknown")).get(0),
|
||||
response.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new KeycloakClientException("Error getting user's avatar data", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.gcube.common.keycloak;
|
|||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
|
||||
import org.gcube.common.keycloak.model.TokenResponse;
|
||||
|
@ -12,9 +13,12 @@ public interface KeycloakClient {
|
|||
public static final String OPEN_ID_URI_PATH = "protocol/openid-connect";
|
||||
public static final String TOKEN_URI_PATH = "token";
|
||||
public static final String TOKEN_INTROSPECT_URI_PATH = "introspect";
|
||||
public static final String AVATAR_URI_PATH = "account-avatar";
|
||||
public final static String D4S_CONTEXT_HEADER_NAME = "X-D4Science-Context";
|
||||
|
||||
public static String DEFAULT_REALM = "d4science";
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Keycloak base {@link URL} for the given context and the default realm (<code>d4science</code>)
|
||||
*
|
||||
|
@ -23,7 +27,6 @@ public interface KeycloakClient {
|
|||
* @throws KeycloakClientException if something goes wrong discovering the endpoint URL
|
||||
*/
|
||||
URL getRealmBaseURL(String context) throws KeycloakClientException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Keycloak base {@link URL} for the given context and in the given realm.
|
||||
|
@ -62,6 +65,15 @@ public interface KeycloakClient {
|
|||
*/
|
||||
URL computeIntrospectionEndpointURL(URL tokenEndpointURL) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Constructs the Keycloak <code>avatar</code> endpoint {@link URL} from the realm's base URL.
|
||||
*
|
||||
* @param realmBaseURL the realm's base URL to use
|
||||
* @return the Keycloak <code>avatar</code> endpoint URL
|
||||
* @throws KeycloakClientException if something goes wrong discovering the endpoint URL
|
||||
*/
|
||||
public URL getAvatarEndpointURL(URL realmBaseURL) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token from the context's Keycloak server, by using provided clientId and client secret.
|
||||
*
|
||||
|
@ -83,7 +95,8 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenWithContext(String context, String clientId, String clientSecret, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenWithContext(String context, String clientId, String clientSecret, String audience)
|
||||
throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token for a specific user from the context's Keycloak server, by using provided clientId and client secret and user's username and password.
|
||||
|
@ -96,7 +109,8 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username, String password) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
|
||||
String password) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token for a specific user from the Keycloak server, by using provided clientId and client secret and user's username and password, reducing the audience to the requested one.
|
||||
|
@ -110,9 +124,12 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret, String username, String password, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret, String username,
|
||||
String password, String audience) throws KeycloakClientException;
|
||||
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
|
||||
String username, String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException;
|
||||
|
||||
|
||||
/**
|
||||
* Queries an OIDC token from the Keycloak server, by using provided clientId and client secret.
|
||||
*
|
||||
|
@ -134,7 +151,8 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenWithContext(URL tokenURL, String clientId, String clientSecret, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenWithContext(URL tokenURL, String clientId, String clientSecret, String audience)
|
||||
throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token for a specific user from the context's Keycloak server, by using provided clientId and client secret and user's username and password, , reducing the audience to the requested one.
|
||||
|
@ -147,7 +165,11 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret, String username, String password, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret, String username,
|
||||
String password, String audience) throws KeycloakClientException;
|
||||
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret,
|
||||
String username, String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token from the Keycloak server, by using provided authorization.
|
||||
|
@ -170,7 +192,8 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenWithContext(String context, String authorization, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenWithContext(String context, String authorization, String audience)
|
||||
throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token for a specific user from the context's Keycloak server, by using provided clientId and client secret and user's username and password.
|
||||
|
@ -183,7 +206,11 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(String context, String authorization, String username, String password, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(String context, String authorization, String username,
|
||||
String password, String audience) throws KeycloakClientException;
|
||||
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String authorization, String username,
|
||||
String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token from the Keycloak server, by using provided authorization.
|
||||
|
@ -204,7 +231,8 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenWithContext(URL tokenURL, String authorization, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenWithContext(URL tokenURL, String authorization, String audience)
|
||||
throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an OIDC token for a specific user from the context's Keycloak server, by using provided clientId and client secret and user's username and password.
|
||||
|
@ -217,7 +245,11 @@ public interface KeycloakClient {
|
|||
* @return the issued token as {@link TokenResponse} object
|
||||
* @throws KeycloakClientException if something goes wrong performing the query
|
||||
*/
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username, String password, String audience) throws KeycloakClientException;
|
||||
TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username, String password,
|
||||
String audience) throws KeycloakClientException;
|
||||
|
||||
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username,
|
||||
String password, String audience, Map<String, String> extraHeaders) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Queries an UMA token from the Keycloak server, by using provided authorization, for the given audience (context),
|
||||
|
@ -389,6 +421,27 @@ public interface KeycloakClient {
|
|||
TokenResponse refreshToken(URL tokenURL, String clientId, String clientSecret, String refreshTokenJWTString)
|
||||
throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForOfflineToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForOfflineToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForRefreshToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForRefreshToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForAccessToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeTokenForAccessToken(String context, TokenResponse oidcTokenResponse, String clientId,
|
||||
String clientSecret, String audience) throws KeycloakClientException;
|
||||
|
||||
TokenResponse exchangeToken(URL tokenURL, String oidcAccessToken, String clientId, String clientSecret,
|
||||
String audience, String requestedTokenType, String scope) throws KeycloakClientException;
|
||||
|
||||
/**
|
||||
* Introspects an access token against the Keycloak server.
|
||||
*
|
||||
|
@ -441,4 +494,8 @@ public interface KeycloakClient {
|
|||
boolean isAccessTokenVerified(URL introspectionURL, String clientId, String clientSecret,
|
||||
String accessTokenJWTString) throws KeycloakClientException;
|
||||
|
||||
public byte[] getAvatarData(String context, TokenResponse tokenResponse) throws KeycloakClientException;
|
||||
|
||||
public byte[] getAvatarData(URL avatarURL, TokenResponse tokenResponse) throws KeycloakClientException;
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ public class OIDCConstants {
|
|||
public static final String SCOPE_PARAMETER = "scope";
|
||||
public static final String CLIENT_CREDENTIALS_GRANT_TYPE = "client_credentials";
|
||||
public static final String UMA_TOKEN_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:uma-ticket";
|
||||
public static final String TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
|
||||
public static final String AUDIENCE_PARAMETER = "audience";
|
||||
public static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
|
||||
public static final String REFRESH_TOKEN_PARAMETER = "refresh_token";
|
||||
|
@ -16,5 +17,11 @@ public class OIDCConstants {
|
|||
public static final String PASSWORD_GRANT_TYPE = "password";
|
||||
public static final String USERNAME_PARAMETER = "username";
|
||||
public static final String PASSWORD_PARAMETER = "password";
|
||||
public static final String SUBJECT_TOKEN_PARAMETER = "subject_token";
|
||||
public static final String SUBJECT_TOKEN_TYPE_PARAMETER = "subject_token_type";
|
||||
public static final String REQUESTED_TOKEN_TYPE_PARAMETER = "requested_token_type";
|
||||
public static final String ACCESS_TOKEN_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token";
|
||||
public static final String REFRESH_TOKEN_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:refresh_token";
|
||||
public static final String OFFLINE_ACCESS_SCOPE = "offline_access";
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.gcube.common.keycloak;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.gcube.common.keycloak.model.ModelUtils;
|
||||
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
|
||||
|
@ -23,7 +26,11 @@ public class TestKeycloakClient {
|
|||
protected static final String DEV_BASE_URL = "https://url.gcube.d4science.org/auth/realms/d4science";
|
||||
protected static final String DEV_TOKEN_ENDPOINT = DEV_BASE_URL + "/protocol/openid-connect/token";
|
||||
protected static final String DEV_INTROSPECTION_ENDPOINT = DEV_TOKEN_ENDPOINT + "/introspect";
|
||||
protected static final String DEV_AVATAR_ENDPOINT = DEV_BASE_URL + "/account-avatar";
|
||||
|
||||
protected static final String ACCOUNTS_DEV_INTROSPECTION_ENDPOINT = "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
|
||||
|
||||
protected static final String TOKEN_RESTRICTION_VRE_CONTEXT = "%2Fgcube%2Fdevsec%2FCCP";
|
||||
protected static final String CLIENT_ID = "keycloak-client-unit-test";
|
||||
protected static final String CLIENT_SECRET = "ebf6f82e-9511-408e-8321-203081e472d8";
|
||||
protected static final String TEST_AUDIENCE = "conductor-server";
|
||||
|
@ -32,11 +39,6 @@ public class TestKeycloakClient {
|
|||
protected static final String OLD_OIDC_ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSSklZNEpoNF9qdDdvNmREY0NlUDFfS1l0akcxVExXVW9oMkQ2Tzk1bFNBIn0.eyJleHAiOjE2NTI5Nzk4NDUsImlhdCI6MTY1Mjk3OTU0NSwianRpIjoiMzQ2MjgwMWItODg4NS00YTM4LWJkNDUtNWExM2U1MGE5MGU5IiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5kZXYuZDRzY2llbmNlLm9yZy9hdXRoL3JlYWxtcy9kNHNjaWVuY2UiLCJhdWQiOlsiJTJGZ2N1YmUiLCIlMkZnY3ViZSUyRmRldnNlYyUyRmRldlZSRSIsImFjY291bnQiXSwic3ViIjoiYTQ3ZGZlMTYtYjRlZC00NGVkLWExZDktOTdlY2Q1MDQzNjBjIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoia2V5Y2xvYWstY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6ImQ4MDk3MDBmLWEyNDUtNDI3Zi1hYzhjLTQxYjFkZDNkYTQ3MCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsIkluZnJhc3RydWN0dXJlLUNsaWVudCIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiJTJGZ2N1YmUiOnsicm9sZXMiOlsiTWVtYmVyIl19LCJrZXljbG9hay1jbGllbnQiOnsicm9sZXMiOlsidW1hX3Byb3RlY3Rpb24iXX0sIiUyRmdjdWJlJTJGZGV2c2VjJTJGZGV2VlJFIjp7InJvbGVzIjpbIk1lbWJlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJrZXljbG9hay1jbGllbnQiLCJjbGllbnRIb3N0IjoiOTMuNjYuMTg1Ljc1IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQta2V5Y2xvYWstY2xpZW50IiwiY2xpZW50QWRkcmVzcyI6IjkzLjY2LjE4NS43NSJ9.FQu4ox2HWeqeaY7nHYVGeJVpkJOcASfOb8tbOUeG-GB6sMjRB2S8PjLLaw63r_c42yxKszP04XdxGqIWqXTtoD9QCiUHTT5yJTkIpio4tMMGHth9Fbx-9dwk0yy_IFi1_OsCvZFmOQRdjMuUkj1lSqslCzAw-2E5q1Zt415-au5pEVJYNTFqIsG72ChJwh6eq1Dh1XBy8krb7YVPQyIwxO_awgAYO5hbsdvXYlRfCrnB38kk2V6-CQ-XYoL1m7xIB-gjhKCiFvDmmntQSRCZFgb0qi8eOmh9FdzPxZgx7yPJwAAj17dS4B_gz9FpZBVciNzpA6Lf4P2bqvoD9-R6ow";
|
||||
protected static final String OLD_UMA_ACCESS_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSSklZNEpoNF9qdDdvNmREY0NlUDFfS1l0akcxVExXVW9oMkQ2Tzk1bFNBIn0.eyJleHAiOjE2NTI5ODA0NzgsImlhdCI6MTY1Mjk4MDE3OCwianRpIjoiNjBkNzU3MGMtZmQxOC00NGQ1LTg1MzUtODhlMmFmOGQ1ZTgwIiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5kZXYuZDRzY2llbmNlLm9yZy9hdXRoL3JlYWxtcy9kNHNjaWVuY2UiLCJhdWQiOiJjb25kdWN0b3Itc2VydmVyIiwic3ViIjoiYTQ3ZGZlMTYtYjRlZC00NGVkLWExZDktOTdlY2Q1MDQzNjBjIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoia2V5Y2xvYWstY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjI3NDUyN2M5LWNkZjMtNGM2Yi1iNTUxLTFmMTRkZGE5ZGVlZiIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiSW5mcmFzdHJ1Y3R1cmUtQ2xpZW50Il19LCJhdXRob3JpemF0aW9uIjp7InBlcm1pc3Npb25zIjpbeyJzY29wZXMiOlsiZ2V0Il0sInJzaWQiOiIyNDlmZDQ2OS03OWM1LTRiODUtYjE5NS1mMjliM2ViNjAzNDUiLCJyc25hbWUiOiJtZXRhZGF0YSJ9LHsic2NvcGVzIjpbImdldCIsInN0YXJ0IiwidGVybWluYXRlIl0sInJzaWQiOiJhNmYzZWFkZS03NDA0LTRlNWQtOTA3MC04MDBhZGI1YWFjNGUiLCJyc25hbWUiOiJ3b3JrZmxvdyJ9LHsicnNpZCI6IjFiNmMwMGI3LTkxMzktNGVhYS1hYWM3LTIwMjMxZmVlMDVhNSIsInJzbmFtZSI6IkRlZmF1bHQgUmVzb3VyY2UifV19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJjbGllbnRJZCI6ImtleWNsb2FrLWNsaWVudCIsImNsaWVudEhvc3QiOiI5My42Ni4xODUuNzUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1rZXljbG9hay1jbGllbnQiLCJjbGllbnRBZGRyZXNzIjoiOTMuNjYuMTg1Ljc1In0.Hh62E56R-amHwoDPFQEylMvrvmNzWnC_4bDI7_iQYAPJ5YzCNH9d7zcdGaQ96kRmps_JRc2Giv_1W9kYorOhlXl-5QLDrSoqrqFxrNpEGG5r5jpNJbusbu4wNUKiCt_GMnM1UmztgXiQeuggNGkmeBIjotj0eubnmIbUV9ukHj3v7Z5PwNKKX3BCpsghd1u8lg6Nfqk_Oho4GXUfdaFY_AR3SNqzVI_9YLhND_a03MNNWlnfOvj8T4nDCKBZIs91tVyiu98d2TjnQt8PdlVwokMP3LA58m0Khy2cmUm1KF2k0zlzP8MxV9wTxNrpovMr-PnbtEPZ_IlVQIzHwjHfwQ";
|
||||
|
||||
protected static URL tokenURL;
|
||||
protected static URL introspectionURL;
|
||||
protected static TokenResponse oidcTR = null;
|
||||
protected static TokenResponse umaTR = null;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
@ -47,23 +49,29 @@ public class TestKeycloakClient {
|
|||
|
||||
@Test
|
||||
public void test00TokenEndpointConstruction() throws Exception {
|
||||
logger.info("*** [0.0] Start testing Keycloak token endpoint construction from base URL computed from context...");
|
||||
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));
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
logger.info("*** [0.0] Constructed token URL is: {}", tokenURL);
|
||||
URL devTokenURL = new URL(DEV_TOKEN_ENDPOINT);
|
||||
logger.info("*** [0.0] DEV token URL is: {}", devTokenURL);
|
||||
Assert.assertNotNull(tokenURL);
|
||||
Assert.assertTrue(tokenURL.getProtocol().equals("https"));
|
||||
Assert.assertEquals(new URL(DEV_TOKEN_ENDPOINT), tokenURL);
|
||||
logger.info("Constructed URL is: {}", tokenURL);
|
||||
Assert.assertEquals(tokenURL.getProtocol(), "https");
|
||||
Assert.assertEquals(devTokenURL.toString(), tokenURL.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01IntrospectionEndpointConstruction() throws Exception {
|
||||
logger.info("*** [0.0] Start testing Keycloak introspection endpoint construction from base URL...");
|
||||
logger.info("*** [0.1] Start testing Keycloak introspection endpoint construction from base URL...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
logger.info("*** [0.1] Constructed introspection URL is: {}", introspectionURL);
|
||||
URL devIntrospectionURL = new URL(DEV_INTROSPECTION_ENDPOINT);
|
||||
logger.info("*** [0.1] DEV introspection URL is: {}", devIntrospectionURL);
|
||||
Assert.assertNotNull(introspectionURL);
|
||||
Assert.assertTrue(introspectionURL.getProtocol().equals("https"));
|
||||
Assert.assertEquals(new URL(DEV_INTROSPECTION_ENDPOINT), introspectionURL);
|
||||
Assert.assertEquals(introspectionURL.getProtocol(), "https");
|
||||
Assert.assertEquals(devIntrospectionURL.toString(), introspectionURL.toString());
|
||||
logger.info("Constructed URL is: {}", introspectionURL);
|
||||
}
|
||||
|
||||
|
@ -71,20 +79,36 @@ public class TestKeycloakClient {
|
|||
public void test02IntrospectEndpointCompute() throws Exception {
|
||||
logger.info("*** [0.2] Start testing Keycloak userinfo endpoint computed from provided URL string...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL url = client
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
logger.info("*** [0.2] Constructed introspection URL is: {}", introspectionURL);
|
||||
URL computedIntrospectionURL = client
|
||||
.computeIntrospectionEndpointURL(client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT)));
|
||||
logger.info("*** [0.2] Computed introspection URL is: {}", computedIntrospectionURL);
|
||||
URL devIntrospectionURL = new URL(DEV_INTROSPECTION_ENDPOINT);
|
||||
logger.info("*** [0.2] DEV introspection URL is: {}", devIntrospectionURL);
|
||||
Assert.assertNotNull(computedIntrospectionURL);
|
||||
Assert.assertEquals(computedIntrospectionURL.getProtocol(), "https");
|
||||
Assert.assertEquals(introspectionURL.toString(), computedIntrospectionURL.toString());
|
||||
Assert.assertEquals(devIntrospectionURL.toString(), computedIntrospectionURL.toString());
|
||||
}
|
||||
|
||||
Assert.assertNotNull(url);
|
||||
Assert.assertTrue(url.getProtocol().equals("https"));
|
||||
Assert.assertEquals(introspectionURL, url);
|
||||
Assert.assertEquals(new URL(DEV_INTROSPECTION_ENDPOINT), url);
|
||||
logger.info("Computed URL is: {}", url);
|
||||
@Test
|
||||
public void test03AvatarEndpointConstruction() throws Exception {
|
||||
logger.info("*** [0.3] Start testing Keycloak avatar endpoint construction from base URL...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL avatarURL = client.getAvatarEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
logger.info("*** [0.3] Constructed avatar URL is: {}", avatarURL);
|
||||
URL devAvatarURL = new URL(DEV_AVATAR_ENDPOINT);
|
||||
logger.info("*** [0.3] DEV avatar URL is: {}", devAvatarURL);
|
||||
Assert.assertNotNull(avatarURL);
|
||||
Assert.assertEquals(avatarURL.getProtocol(), "https");
|
||||
Assert.assertEquals(devAvatarURL.toString(), avatarURL.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test12QueryOIDCToken() throws Exception {
|
||||
logger.info("*** [1.2] Start testing query OIDC token from Keycloak with context...");
|
||||
oidcTR = KeycloakClientFactory.newInstance().queryOIDCToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET);
|
||||
|
||||
logger.info("*** [1.2] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
@ -96,21 +120,22 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test12aQueryOIDCToken() throws Exception {
|
||||
logger.info("*** [1.2a] Start testing query OIDC token from Keycloak with URL...");
|
||||
oidcTR = KeycloakClientFactory.newInstance().queryOIDCToken(tokenURL, CLIENT_ID,
|
||||
CLIENT_SECRET);
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
|
||||
logger.info("*** [1.2a] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
logger.info("*** [1.2a] OIDC refresh token: {}", oidcTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(oidcTR);
|
||||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), "service-account-" + CLIENT_ID, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test13QueryOIDCTokenOfUser() throws Exception {
|
||||
logger.info("*** [1.3] Start testing query OIDC token from Keycloak with context for user...");
|
||||
oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD);
|
||||
|
||||
|
||||
logger.info("*** [1.3] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
logger.info("*** [1.3] OIDC refresh token: {}", oidcTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(oidcTR);
|
||||
|
@ -120,27 +145,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...");
|
||||
oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TEST_AUDIENCE);
|
||||
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TEST_AUDIENCE);
|
||||
|
||||
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);
|
||||
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse oidcTR = client.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);
|
||||
|
||||
TokenResponse umaTR = client.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());
|
||||
|
@ -149,11 +175,38 @@ public class TestKeycloakClient {
|
|||
TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), TEST_USER_USERNAME, true);
|
||||
}
|
||||
|
||||
@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...");
|
||||
TokenResponse oidcTR = KeycloakClientFactory.newInstance().queryOIDCTokenOfUserWithContext(DEV_ROOT_CONTEXT,
|
||||
CLIENT_ID, CLIENT_SECRET, TEST_USER_USERNAME, TEST_USER_PASSWORD, TOKEN_RESTRICTION_VRE_CONTEXT);
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test24QueryUMAToken() throws Exception {
|
||||
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);
|
||||
TokenResponse umaTR = KeycloakClientFactory.newInstance().queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
|
||||
logger.info("*** [2.4] UMA access token: {}", umaTR.getAccessToken());
|
||||
logger.info("*** [2.4] UMA refresh token: {}", umaTR.getRefreshToken());
|
||||
|
@ -164,9 +217,10 @@ public class TestKeycloakClient {
|
|||
|
||||
@Test
|
||||
public void test24aQueryUMAToken() throws Exception {
|
||||
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);
|
||||
logger.info("*** [2.4a] Start testing query UMA token from Keycloak with URL...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse umaTR = client.queryUMAToken(tokenURL, CLIENT_ID, CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
|
||||
logger.info("*** [2.4a] UMA access token: {}", umaTR.getAccessToken());
|
||||
logger.info("*** [2.4a] UMA refresh token: {}", umaTR.getRefreshToken());
|
||||
|
@ -178,8 +232,11 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test302IntrospectOIDCAccessToken() throws Exception {
|
||||
logger.info("*** [3.2] Start testing introspect OIDC access token...");
|
||||
TokenIntrospectionResponse tir = KeycloakClientFactory.newInstance().introspectAccessToken(
|
||||
DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken());
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
TokenIntrospectionResponse tir = client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
|
||||
oidcTR.getAccessToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(tir);
|
||||
}
|
||||
|
@ -187,17 +244,39 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test302aIntrospectOIDCAccessToken() throws Exception {
|
||||
logger.info("*** [3.2a] Start testing introspect OIDC access token...");
|
||||
TokenIntrospectionResponse tir = KeycloakClientFactory.newInstance().introspectAccessToken(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken());
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
|
||||
oidcTR.getAccessToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(tir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test302bIntrospectOIDCAccessTokenFromDifferentServer() throws Exception {
|
||||
logger.info("*** [3.2b] Start testing introspect OIDC access token with different base URLs...");
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
|
||||
logger.info("*** [3.2b] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
URL introspectionURL = new URL(ACCOUNTS_DEV_INTROSPECTION_ENDPOINT);
|
||||
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
|
||||
oidcTR.getAccessToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(tir, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test304IntrospectUMAAccessToken() throws Exception {
|
||||
logger.info("*** [3.4] Start testing introspect UMA access token...");
|
||||
TokenIntrospectionResponse tir = KeycloakClientFactory.newInstance().introspectAccessToken(
|
||||
DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken());
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse umaTR = client.queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
TokenIntrospectionResponse tir = client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
|
||||
umaTR.getAccessToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(tir);
|
||||
}
|
||||
|
@ -205,8 +284,11 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test304aIntrospectUMAAccessToken() throws Exception {
|
||||
logger.info("*** [3.4a] Start testing introspect UMA access token...");
|
||||
TokenIntrospectionResponse tir = KeycloakClientFactory.newInstance().introspectAccessToken(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken());
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse umaTR = client.queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
|
||||
umaTR.getAccessToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(tir);
|
||||
}
|
||||
|
@ -214,15 +296,22 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test306OIDCAccessTokenVerification() throws Exception {
|
||||
logger.info("*** [3.6] Start OIDC access token verification...");
|
||||
Assert.assertTrue(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken()));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
Assert.assertTrue(
|
||||
client.isAccessTokenVerified(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test306aOIDCAccessTokenVerification() throws Exception {
|
||||
logger.info("*** [3.6a] Start OIDC access token verification...");
|
||||
Assert.assertTrue(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken()));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL tokenURL = client.getTokenEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
TokenResponse oidcTR = client.queryOIDCToken(tokenURL, CLIENT_ID, CLIENT_SECRET);
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
Assert.assertTrue(
|
||||
client.isAccessTokenVerified(introspectionURL, CLIENT_ID, CLIENT_SECRET, oidcTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -235,22 +324,29 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test307aOIDCAccessTokenNonVerification() throws Exception {
|
||||
logger.info("*** [3.7a] Start OIDC access token NON verification...");
|
||||
Assert.assertFalse(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, OLD_OIDC_ACCESS_TOKEN));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
Assert.assertFalse(
|
||||
client.isAccessTokenVerified(introspectionURL, CLIENT_ID, CLIENT_SECRET, OLD_OIDC_ACCESS_TOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test309UMAAccessTokenVerification() throws Exception {
|
||||
logger.info("*** [3.9] Start UMA access token verification...");
|
||||
Assert.assertTrue(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken()));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse umaTR = client.queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
Assert.assertTrue(
|
||||
client.isAccessTokenVerified(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test309aUMAAccessTokenVerification() throws Exception {
|
||||
logger.info("*** [3.9a] Start UMA access token verification...");
|
||||
Assert.assertTrue(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken()));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
TokenResponse umaTR = client.queryUMAToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, TEST_AUDIENCE, null);
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
Assert.assertTrue(
|
||||
client.isAccessTokenVerified(introspectionURL, CLIENT_ID, CLIENT_SECRET, umaTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -263,19 +359,119 @@ public class TestKeycloakClient {
|
|||
@Test
|
||||
public void test310aUMAAccessTokenNonVerification() throws Exception {
|
||||
logger.info("*** [3.10a] Start UMA access token NON verification...");
|
||||
Assert.assertFalse(KeycloakClientFactory.newInstance().isAccessTokenVerified(
|
||||
introspectionURL, CLIENT_ID, CLIENT_SECRET, OLD_UMA_ACCESS_TOKEN));
|
||||
KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
URL introspectionURL = client.getIntrospectionEndpointURL(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
|
||||
Assert.assertFalse(
|
||||
client.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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test51ExchangeToken4Access() throws Exception {
|
||||
logger.info("*** [5.1] Start testing token exchange for access 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.1] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
TokenResponse exchangedTR = client.exchangeTokenForAccessToken(DEV_ROOT_CONTEXT, oidcTR, CLIENT_ID,
|
||||
CLIENT_SECRET, CLIENT_ID);
|
||||
|
||||
logger.info("*** [5.1] Exchanged access token: {}", exchangedTR.getAccessToken());
|
||||
TestModels.checkTokenResponse(exchangedTR, false);
|
||||
Assert.assertNull(exchangedTR.getRefreshToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, exchangedTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test51aExchangeUMAToken4Access() throws Exception {
|
||||
logger.info("*** [5.1a] Start testing UMA token exchange for access 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.1a] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
TokenResponse umaTR = client.queryUMAToken(DEV_ROOT_CONTEXT, oidcTR, TOKEN_RESTRICTION_VRE_CONTEXT, null);
|
||||
|
||||
logger.info("*** [5.1a] UMA access token: {}", umaTR.getAccessToken());
|
||||
|
||||
TokenResponse exchangedTR = client.exchangeTokenForAccessToken(DEV_ROOT_CONTEXT, umaTR, CLIENT_ID,
|
||||
CLIENT_SECRET, CLIENT_ID);
|
||||
|
||||
logger.info("*** [5.1a] Exchanged access token: {}", exchangedTR.getAccessToken());
|
||||
TestModels.checkTokenResponse(exchangedTR, false);
|
||||
Assert.assertNull(exchangedTR.getRefreshToken());
|
||||
|
||||
TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
|
||||
CLIENT_SECRET, exchangedTR.getAccessToken()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test52ExchangeToken4refresh() throws Exception {
|
||||
logger.info("*** [5.2] Start testing token exchange for refresh 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.2] OIDC access token: {}", oidcTR.getAccessToken());
|
||||
|
||||
TokenResponse exchangedTR = client.exchangeTokenForRefreshToken(DEV_ROOT_CONTEXT, oidcTR, CLIENT_ID,
|
||||
CLIENT_SECRET, CLIENT_ID);
|
||||
|
||||
logger.info("*** [5.2] Exchanged access token: {}", exchangedTR.getAccessToken());
|
||||
logger.info("*** [5.2] Exchanged refresh token: {}", exchangedTR.getRefreshToken());
|
||||
TestModels.checkTokenResponse(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 {
|
||||
// logger.info("*** [6] Start testing get user's avatar...");
|
||||
// KeycloakClient client = KeycloakClientFactory.newInstance();
|
||||
// TokenResponse oidcTR = client.queryOIDCTokenOfUser(DEV_ROOT_CONTEXT, GATEWAY, null, TEST_USER_USERNAME, TEST_USER_PASSWORD);
|
||||
// byte[] avatarData = client.getAvatarData(DEV_ROOT_CONTEXT, oidcTR);
|
||||
// Assert.assertNotNull("Avatar data is null", avatarData);
|
||||
// logger.info("*** [6] Avatar image of user is {} bytes", avatarData.length);
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -86,10 +86,16 @@ public class TestModels {
|
|||
}
|
||||
|
||||
public static void checkTokenResponse(TokenResponse tr) throws Exception {
|
||||
checkTokenResponse(tr, true);
|
||||
}
|
||||
|
||||
public static void checkTokenResponse(TokenResponse tr, boolean checkAlsoRefreshToken) throws Exception {
|
||||
Assert.assertNotNull(tr);
|
||||
Assert.assertEquals("bearer", tr.getTokenType().toLowerCase());
|
||||
Assert.assertNotNull(tr.getAccessToken());
|
||||
Assert.assertNotNull(tr.getRefreshToken());
|
||||
Assert.assertNotNull("Access token is null", tr.getAccessToken());
|
||||
if (checkAlsoRefreshToken) {
|
||||
Assert.assertNotNull("Refresh token is null", tr.getRefreshToken());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkAccessToken(AccessToken at, String preferredUsername, boolean checkAudience) {
|
||||
|
@ -99,19 +105,33 @@ public class TestModels {
|
|||
Assert.assertEquals(preferredUsername, at.getPreferredUsername());
|
||||
}
|
||||
if (checkAudience) {
|
||||
Assert.assertNotNull(at.getAudience());
|
||||
Assert.assertNotNull("Audience is null", at.getAudience());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkRefreshToken(RefreshToken rt) {
|
||||
logger.debug("Refresh token:\n{}", ModelUtils.toJSONString(rt, true));
|
||||
Assert.assertNotNull(rt.getOtherClaims());
|
||||
Assert.assertNotNull(rt.getAudience());
|
||||
Assert.assertNotNull("Other claims are null", rt.getOtherClaims());
|
||||
Assert.assertNotNull("Audience is null",rt.getAudience());
|
||||
}
|
||||
|
||||
public static void checkOfflineToken(TokenResponse tr) throws Exception {
|
||||
RefreshToken rt = ModelUtils.getRefreshTokenFrom(tr.getRefreshToken());
|
||||
Assert.assertEquals("Offline", rt.getType());
|
||||
Assert.assertNull("Expiration is not null",rt.getExp());
|
||||
}
|
||||
|
||||
public static void checkTokenIntrospectionResponse(TokenIntrospectionResponse tir) {
|
||||
checkTokenIntrospectionResponse(tir, true);
|
||||
}
|
||||
|
||||
public static void checkTokenIntrospectionResponse(TokenIntrospectionResponse tir, boolean mustBeActive) {
|
||||
logger.debug("Token introspection response :\n{}", ModelUtils.toJSONString(tir, true));
|
||||
Assert.assertTrue(tir.isActive());
|
||||
if (mustBeActive) {
|
||||
Assert.assertTrue("Token is not active", tir.getActive());
|
||||
} else {
|
||||
Assert.assertFalse("Token is active", tir.getActive());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue